diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000000..5b4e0fd7781a --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,9 @@ +# Settings file automatically used by clang-tidy +# +# See ./contrib/utilities/run_clang_tidy.sh for details + +# We disable performance-inefficient-string-concatenation because we don't care about "a"+to_string(5)+... + +Checks: "-*,cppcoreguidelines-pro-type-static-cast-downcast,google-readability-casting,modernize-*,-modernize-pass-by-value,-modernize-raw-string-literal,-modernize-use-auto,-modernize-use-override,-modernize-use-default-member-init,-modernize-use-transparent-functors,use-emplace,mpi-*,performance-*,-performance-inefficient-string-concatenation" + +WarningsAsErrors: '*' diff --git a/Jenkinsfile b/Jenkinsfile index 09370d793b2a..2f6d440b15bd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,11 +1,25 @@ #!groovy +// load library https://github.com/tjhei/jenkins-stuff to provide +// killold.killOldBuilds() function: +@Library('tjhei') _ + pipeline { agent none stages { + stage("abort old") + { + agent none + steps + { + // kill older builds in this PR: + script { killold.killOldBuilds() } + } + } + stage("check") { agent @@ -40,8 +54,17 @@ pipeline stage("indent") { + post { + failure { + githubNotify context: 'indent', description: 'failed', status: 'FAILURE' + } + } + steps { + // we are finally running, so we can mark the 'ready' context from Jenkinsfile.mark as success: + githubNotify context: 'ready', description: ':-)', status: 'SUCCESS' + // We can not use 'indent' because we are missing the master branch: // "fatal: ambiguous argument 'master': unknown revision or path" sh ''' @@ -73,7 +96,23 @@ pipeline image 'tjhei/candi:v9.0.1-r4' } } - post { cleanup { cleanWs() } } + + post { + always { + sh "cp /home/dealii/build/Testing/*/*.xml $WORKSPACE/serial.xml || true" + xunit tools: [CTest(pattern: '*.xml')] + sh "cp /home/dealii/build/detailed.log $WORKSPACE/detailed-serial.log || true" + archiveArtifacts artifacts: 'detailed-serial.log', fingerprint: true + } + + cleanup { + cleanWs() + } + + failure { + githubNotify context: 'CI', description: 'serial build failed', status: 'FAILURE' + } + } steps { @@ -81,9 +120,9 @@ pipeline { sh "echo \"building on node ${env.NODE_NAME}\"" sh '''#!/bin/bash + set -e export NP=`grep -c ^processor /proc/cpuinfo` - export TEST_TIME_LIMIT=1200 - echo $NP + export TEST_TIME_LIMIT=1200 mkdir -p /home/dealii/build cd /home/dealii/build cmake -G "Ninja" \ @@ -93,8 +132,9 @@ pipeline -D DEAL_II_UNITY_BUILD=ON \ $WORKSPACE/ time ninja -j $NP + time ninja test # quicktests time ninja setup_tests - time ctest --output-on-failure -DDESCRIPTION="CI-$JOB_NAME" -j $NP + time ctest --output-on-failure -DDESCRIPTION="CI-$JOB_NAME" -j $NP --no-compress-output -T test ''' } } @@ -110,7 +150,23 @@ pipeline image 'tjhei/candi:v9.0.1-r4' } } - post { cleanup { cleanWs() } } + + post { + always { + sh "cp /home/dealii/build/Testing/*/*.xml $WORKSPACE/mpi.xml || true" + xunit tools: [CTest(pattern: '*.xml')] + sh "cp /home/dealii/build/detailed.log $WORKSPACE/detailed-mpi.log || true" + archiveArtifacts artifacts: 'detailed-mpi.log', fingerprint: true + } + + cleanup { + cleanWs() + } + + failure { + githubNotify context: 'CI', description: 'mpi build failed', status: 'FAILURE' + } + } steps { @@ -118,6 +174,7 @@ pipeline { sh "echo \"building on node ${env.NODE_NAME}\"" sh '''#!/bin/bash + set -e export NP=`grep -c ^processor /proc/cpuinfo` mkdir -p /home/dealii/build cd /home/dealii/build @@ -128,11 +185,13 @@ pipeline -D DEAL_II_UNITY_BUILD=OFF \ $WORKSPACE/ time ninja -j $NP + time ninja test # quicktests time ninja setup_tests - time ctest -R "all-headers|multigrid/transfer" --output-on-failure -DDESCRIPTION="CI-$JOB_NAME" -j $NP + time ctest -R "all-headers|multigrid/transfer" --output-on-failure -DDESCRIPTION="CI-$JOB_NAME" -j $NP --no-compress-output -T test ''' } } + } } @@ -145,6 +204,8 @@ pipeline steps { githubNotify context: 'CI', description: 'OK', status: 'SUCCESS' + // In case the Jenkinsfile.mark job started after we did, make sure we don't leave a pending status around: + githubNotify context: 'ready', description: ':-)', status: 'SUCCESS' } } } diff --git a/README.md b/README.md index 733e289308c7..ba69add07c7f 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ on how to set this up. License: -------- -Please see the file [./LICENSE](LICENSE) for details +Please see the file [./LICENSE.md](LICENSE.md) for details Further information: -------------------- diff --git a/bundled/.clang-tidy b/bundled/.clang-tidy new file mode 100644 index 000000000000..eb40a98a77a0 --- /dev/null +++ b/bundled/.clang-tidy @@ -0,0 +1,6 @@ +# Disable all checks because we don't want to fix things inside +# bundled/. Clang-tidy fails if nothing is chosen, so we just enable a single +# harmless warning: + +Checks: "-*,misc-sizeof-container" + diff --git a/bundled/boost-1.62.0/include/boost/algorithm/cxx14/equal.hpp b/bundled/boost-1.62.0/include/boost/algorithm/cxx14/equal.hpp index f1539f885cee..9f97be1d626d 100644 --- a/bundled/boost-1.62.0/include/boost/algorithm/cxx14/equal.hpp +++ b/bundled/boost-1.62.0/include/boost/algorithm/cxx14/equal.hpp @@ -13,7 +13,6 @@ #define BOOST_ALGORITHM_EQUAL_HPP #include // for std::equal -#include // for std::binary_function #include namespace boost { namespace algorithm { @@ -21,7 +20,7 @@ namespace boost { namespace algorithm { namespace detail { template - struct eq : public std::binary_function { + struct eq { bool operator () ( const T1& v1, const T2& v2 ) const { return v1 == v2 ;} }; diff --git a/bundled/boost-1.62.0/include/boost/algorithm/string/detail/case_conv.hpp b/bundled/boost-1.62.0/include/boost/algorithm/string/detail/case_conv.hpp index 42621c74f06e..233912ca0f20 100644 --- a/bundled/boost-1.62.0/include/boost/algorithm/string/detail/case_conv.hpp +++ b/bundled/boost-1.62.0/include/boost/algorithm/string/detail/case_conv.hpp @@ -30,8 +30,10 @@ namespace boost { // a tolower functor template - struct to_lowerF : public std::unary_function + struct to_lowerF { + typedef CharT argument_type; + typedef CharT result_type; // Constructor to_lowerF( const std::locale& Loc ) : m_Loc( &Loc ) {} @@ -50,8 +52,10 @@ namespace boost { // a toupper functor template - struct to_upperF : public std::unary_function + struct to_upperF { + typedef CharT argument_type; + typedef CharT result_type; // Constructor to_upperF( const std::locale& Loc ) : m_Loc( &Loc ) {} diff --git a/bundled/boost-1.62.0/include/boost/algorithm/string/detail/util.hpp b/bundled/boost-1.62.0/include/boost/algorithm/string/detail/util.hpp index cf4a8b1c8cd4..7844b6723cc6 100644 --- a/bundled/boost-1.62.0/include/boost/algorithm/string/detail/util.hpp +++ b/bundled/boost-1.62.0/include/boost/algorithm/string/detail/util.hpp @@ -89,9 +89,10 @@ namespace boost { template< typename SeqT, typename IteratorT=BOOST_STRING_TYPENAME SeqT::const_iterator > - struct copy_iterator_rangeF : - public std::unary_function< iterator_range, SeqT > + struct copy_iterator_rangeF { + typedef iterator_range argument_type; + typedef SeqT result_type; SeqT operator()( const iterator_range& Range ) const { return copy_range(Range); diff --git a/bundled/boost-1.62.0/include/boost/config/compiler/visualc.hpp b/bundled/boost-1.62.0/include/boost/config/compiler/visualc.hpp index 200d39df5e13..3a68c4d6bd9f 100644 --- a/bundled/boost-1.62.0/include/boost/config/compiler/visualc.hpp +++ b/bundled/boost-1.62.0/include/boost/config/compiler/visualc.hpp @@ -294,10 +294,10 @@ #endif // -// masterleinad: upgrade supported MSVC version to 19.16 (last checked 19.16.27024.1) +// masterleinad: upgrade supported MSVC version to 19.20 (last checked 19.20.27404) // Boost repo has only 19.10: // last known and checked version is 19.10.24629 (VC++ 2017 RC): -#if (_MSC_VER > 1916) +#if (_MSC_VER > 1920) # if defined(BOOST_ASSERT_CONFIG) # error "Unknown compiler version - please run the configure tests and report the results" # else diff --git a/bundled/boost-1.62.0/include/boost/config/stdlib/dinkumware.hpp b/bundled/boost-1.62.0/include/boost/config/stdlib/dinkumware.hpp index af8ddda528da..293a17675f5c 100644 --- a/bundled/boost-1.62.0/include/boost/config/stdlib/dinkumware.hpp +++ b/bundled/boost-1.62.0/include/boost/config/stdlib/dinkumware.hpp @@ -180,7 +180,7 @@ // If _HAS_AUTO_PTR_ETC is defined to 0, std::auto_ptr is not available. // See https://www.visualstudio.com/en-us/news/vs2015-vs.aspx#C++ // and http://blogs.msdn.com/b/vcblog/archive/2015/06/19/c-11-14-17-features-in-vs-2015-rtm.aspx -# if defined(_HAS_AUTO_PTR_ETC) && (_HAS_AUTO_PTR_ETC == 0) +# if defined(_HAS_AUTO_PTR_ETC) && (_HAS_AUTO_PTR_ETC == 0) && !defined BOOST_NO_AUTO_PTR # define BOOST_NO_AUTO_PTR # endif #endif diff --git a/bundled/boost-1.62.0/include/boost/function/function_template.hpp b/bundled/boost-1.62.0/include/boost/function/function_template.hpp index 82c81d769733..7984c8323fed 100644 --- a/bundled/boost-1.62.0/include/boost/function/function_template.hpp +++ b/bundled/boost-1.62.0/include/boost/function/function_template.hpp @@ -656,17 +656,6 @@ namespace boost { BOOST_FUNCTION_TEMPLATE_PARMS > class BOOST_FUNCTION_FUNCTION : public function_base - -#if BOOST_FUNCTION_NUM_ARGS == 1 - - , public std::unary_function - -#elif BOOST_FUNCTION_NUM_ARGS == 2 - - , public std::binary_function - -#endif - { public: #ifndef BOOST_NO_VOID_RETURNS diff --git a/bundled/boost-1.62.0/include/boost/functional.hpp b/bundled/boost-1.62.0/include/boost/functional.hpp index b618485c102e..731e4e1f1c97 100644 --- a/bundled/boost-1.62.0/include/boost/functional.hpp +++ b/bundled/boost-1.62.0/include/boost/functional.hpp @@ -18,6 +18,36 @@ namespace boost { + namespace functional + { + namespace detail { +#if defined(_HAS_AUTO_PTR_ETC) && !_HAS_AUTO_PTR_ETC + // std::unary_function and std::binary_function were both removed + // in C++17. + + template + struct unary_function + { + typedef Arg1 argument_type; + typedef Result result_type; + }; + + template + struct binary_function + { + typedef Arg1 first_argument_type; + typedef Arg2 second_argument_type; + typedef Result result_type; + }; +#else + // Use the standard objects when we have them. + + using std::unary_function; + using std::binary_function; +#endif + } + } + #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // -------------------------------------------------------------------------- // The following traits classes allow us to avoid the need for ptr_fun @@ -147,7 +177,7 @@ namespace boost // -------------------------------------------------------------------------- template class unary_negate - : public std::unary_function::argument_type,bool> + : public boost::functional::detail::unary_function::argument_type,bool> { public: explicit unary_negate(typename unary_traits::param_type x) @@ -181,7 +211,7 @@ namespace boost // -------------------------------------------------------------------------- template class binary_negate - : public std::binary_function::first_argument_type, + : public boost::functional::detail::binary_function::first_argument_type, typename binary_traits::second_argument_type, bool> { @@ -218,7 +248,7 @@ namespace boost // -------------------------------------------------------------------------- template class binder1st - : public std::unary_function::second_argument_type, + : public boost::functional::detail::unary_function::second_argument_type, typename binary_traits::result_type> { public: @@ -264,7 +294,7 @@ namespace boost // -------------------------------------------------------------------------- template class binder2nd - : public std::unary_function::first_argument_type, + : public boost::functional::detail::unary_function::first_argument_type, typename binary_traits::result_type> { public: @@ -309,7 +339,7 @@ namespace boost // mem_fun, etc // -------------------------------------------------------------------------- template - class mem_fun_t : public std::unary_function + class mem_fun_t : public boost::functional::detail::unary_function { public: explicit mem_fun_t(S (T::*p)()) @@ -325,7 +355,7 @@ namespace boost }; template - class mem_fun1_t : public std::binary_function + class mem_fun1_t : public boost::functional::detail::binary_function { public: explicit mem_fun1_t(S (T::*p)(A)) @@ -341,7 +371,7 @@ namespace boost }; template - class const_mem_fun_t : public std::unary_function + class const_mem_fun_t : public boost::functional::detail::unary_function { public: explicit const_mem_fun_t(S (T::*p)() const) @@ -357,7 +387,7 @@ namespace boost }; template - class const_mem_fun1_t : public std::binary_function + class const_mem_fun1_t : public boost::functional::detail::binary_function { public: explicit const_mem_fun1_t(S (T::*p)(A) const) @@ -402,7 +432,7 @@ namespace boost // mem_fun_ref, etc // -------------------------------------------------------------------------- template - class mem_fun_ref_t : public std::unary_function + class mem_fun_ref_t : public boost::functional::detail::unary_function { public: explicit mem_fun_ref_t(S (T::*p)()) @@ -418,7 +448,7 @@ namespace boost }; template - class mem_fun1_ref_t : public std::binary_function + class mem_fun1_ref_t : public boost::functional::detail::binary_function { public: explicit mem_fun1_ref_t(S (T::*p)(A)) @@ -434,7 +464,7 @@ namespace boost }; template - class const_mem_fun_ref_t : public std::unary_function + class const_mem_fun_ref_t : public boost::functional::detail::unary_function { public: explicit const_mem_fun_ref_t(S (T::*p)() const) @@ -451,7 +481,7 @@ namespace boost }; template - class const_mem_fun1_ref_t : public std::binary_function + class const_mem_fun1_ref_t : public boost::functional::detail::binary_function { public: explicit const_mem_fun1_ref_t(S (T::*p)(A) const) @@ -497,7 +527,7 @@ namespace boost // ptr_fun // -------------------------------------------------------------------------- template - class pointer_to_unary_function : public std::unary_function + class pointer_to_unary_function : public boost::functional::detail::unary_function { public: explicit pointer_to_unary_function(Result (*f)(Arg)) @@ -521,7 +551,7 @@ namespace boost } template - class pointer_to_binary_function : public std::binary_function + class pointer_to_binary_function : public boost::functional::detail::binary_function { public: explicit pointer_to_binary_function(Result (*f)(Arg1, Arg2)) diff --git a/bundled/boost-1.62.0/include/boost/functional/hash/extensions.hpp b/bundled/boost-1.62.0/include/boost/functional/hash/extensions.hpp index eafaefe85dce..9f8fe4d65da1 100644 --- a/bundled/boost-1.62.0/include/boost/functional/hash/extensions.hpp +++ b/bundled/boost-1.62.0/include/boost/functional/hash/extensions.hpp @@ -254,8 +254,9 @@ namespace boost #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) template struct hash - : std::unary_function { + typedef T argument_type; + typedef std::size_t result_type; #if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) std::size_t operator()(T const& val) const { @@ -271,8 +272,9 @@ namespace boost #if BOOST_WORKAROUND(__DMC__, <= 0x848) template struct hash - : std::unary_function { + typedef T[n] argument_type; + typedef std::size_t result_type; std::size_t operator()(const T* val) const { return boost::hash_range(val, val+n); @@ -296,8 +298,9 @@ namespace boost { template struct inner - : std::unary_function { + typedef T argument_type; + typedef std::size_t result_type; #if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) std::size_t operator()(T const& val) const { diff --git a/bundled/boost-1.62.0/include/boost/functional/hash/hash.hpp b/bundled/boost-1.62.0/include/boost/functional/hash/hash.hpp index 0a8ceeb4742e..56941c964116 100644 --- a/bundled/boost-1.62.0/include/boost/functional/hash/hash.hpp +++ b/bundled/boost-1.62.0/include/boost/functional/hash/hash.hpp @@ -419,8 +419,9 @@ namespace boost #define BOOST_HASH_SPECIALIZE(type) \ template <> struct hash \ - : public std::unary_function \ { \ + typedef type argument_type; \ + typedef std::size_t result_type; \ std::size_t operator()(type v) const \ { \ return boost::hash_value(v); \ @@ -429,8 +430,9 @@ namespace boost #define BOOST_HASH_SPECIALIZE_REF(type) \ template <> struct hash \ - : public std::unary_function \ { \ + typedef type argument_type; \ + typedef std::size_t result_type; \ std::size_t operator()(type const& v) const \ { \ return boost::hash_value(v); \ @@ -483,8 +485,9 @@ namespace boost template struct hash - : public std::unary_function { + typedef T* argument_type; + typedef std::size_t result_type; std::size_t operator()(T* v) const { #if !BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590) @@ -516,8 +519,9 @@ namespace boost { template struct inner - : public std::unary_function { + typedef T argument_type; + typedef std::size_t result_type; std::size_t operator()(T val) const { #if !BOOST_WORKAROUND(__SUNPRO_CC, <= 590) diff --git a/bundled/boost-1.62.0/include/boost/graph/astar_search.hpp b/bundled/boost-1.62.0/include/boost/graph/astar_search.hpp index 435ccf03b53a..95795f27c2d3 100644 --- a/bundled/boost-1.62.0/include/boost/graph/astar_search.hpp +++ b/bundled/boost-1.62.0/include/boost/graph/astar_search.hpp @@ -46,11 +46,12 @@ namespace boost { template - class astar_heuristic : public std::unary_function< - typename graph_traits::vertex_descriptor, CostType> + class astar_heuristic { public: typedef typename graph_traits::vertex_descriptor Vertex; + typedef Vertex argument_type; + typedef CostType result_type; astar_heuristic() {} CostType operator()(Vertex u) { return static_cast(0); } }; diff --git a/bundled/boost-1.62.0/include/boost/graph/detail/geodesic.hpp b/bundled/boost-1.62.0/include/boost/graph/detail/geodesic.hpp index adcb17f0ae64..0f2f2024fa2a 100644 --- a/bundled/boost-1.62.0/include/boost/graph/detail/geodesic.hpp +++ b/bundled/boost-1.62.0/include/boost/graph/detail/geodesic.hpp @@ -82,8 +82,11 @@ namespace detail { // Similar to std::plus, but maximizes parameters // rather than adding them. template - struct maximize : public std::binary_function + struct maximize { + typedef T result_type; + typedef T first_argument_type; + typedef T second_argument_type; T operator ()(T x, T y) const { BOOST_USING_STD_MAX(); return max BOOST_PREVENT_MACRO_SUBSTITUTION (x, y); } }; @@ -93,11 +96,10 @@ namespace detail { // types, but should be specialized for those types that have // discrete notions of reciprocals. template - struct reciprocal : public std::unary_function + struct reciprocal { - typedef std::unary_function function_type; - typedef typename function_type::result_type result_type; - typedef typename function_type::argument_type argument_type; + typedef T result_type; + typedef T first_argument_type; T operator ()(T t) { return T(1) / t; } }; diff --git a/bundled/boost-1.62.0/include/boost/graph/distributed/crauser_et_al_shortest_paths.hpp b/bundled/boost-1.62.0/include/boost/graph/distributed/crauser_et_al_shortest_paths.hpp index 060cbf9cabe9..70090ce4cfbe 100644 --- a/bundled/boost-1.62.0/include/boost/graph/distributed/crauser_et_al_shortest_paths.hpp +++ b/bundled/boost-1.62.0/include/boost/graph/distributed/crauser_et_al_shortest_paths.hpp @@ -95,8 +95,10 @@ namespace detail { template struct min_in_distance_compare - : std::binary_function { + typedef Vertex first_argument_type; + typedef Vertex second_argument_type; + typedef bool result_type; min_in_distance_compare(DistanceMap d, MinInWeightMap m, Combine combine, Compare compare) : distance_map(d), min_in_weight(m), combine(combine), @@ -119,9 +121,11 @@ namespace detail { template - struct min_out_distance_compare - : std::binary_function + struct min_out_distance_compares { + typedef Vertex first_argument_type; + typedef Vertex second_argument_type; + typedef bool result_type; min_out_distance_compare(DistanceMap d, MinOutWeightMap m, Combine combine, Compare compare) : distance_map(d), min_out_weight(m), combine(combine), diff --git a/bundled/boost-1.62.0/include/boost/graph/parallel/algorithm.hpp b/bundled/boost-1.62.0/include/boost/graph/parallel/algorithm.hpp index eed9bf8769a0..21ad7cc29588 100644 --- a/bundled/boost-1.62.0/include/boost/graph/parallel/algorithm.hpp +++ b/bundled/boost-1.62.0/include/boost/graph/parallel/algorithm.hpp @@ -26,20 +26,29 @@ namespace boost { namespace parallel { }; template - struct minimum : std::binary_function + struct minimum { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; const T& operator()(const T& x, const T& y) const { return x < y? x : y; } }; template - struct maximum : std::binary_function + struct maximum { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; const T& operator()(const T& x, const T& y) const { return x < y? y : x; } }; template - struct sum : std::binary_function + struct sum { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; const T operator()(const T& x, const T& y) const { return x + y; } }; diff --git a/bundled/boost-1.62.0/include/boost/graph/transitive_closure.hpp b/bundled/boost-1.62.0/include/boost/graph/transitive_closure.hpp index 4f81349bf2e1..c8c1629f455a 100644 --- a/bundled/boost-1.62.0/include/boost/graph/transitive_closure.hpp +++ b/bundled/boost-1.62.0/include/boost/graph/transitive_closure.hpp @@ -41,8 +41,9 @@ namespace boost { template < typename TheContainer, typename ST = std::size_t, typename VT = typename TheContainer::value_type > - struct subscript_t:public std::unary_function < ST, VT > + struct subscript_t { + typedef ST& argument_type; typedef VT& result_type; subscript_t(TheContainer & c):container(&c) diff --git a/bundled/boost-1.62.0/include/boost/iostreams/chain.hpp b/bundled/boost-1.62.0/include/boost/iostreams/chain.hpp index bc0fab58ea12..78434f393aed 100644 --- a/bundled/boost-1.62.0/include/boost/iostreams/chain.hpp +++ b/bundled/boost-1.62.0/include/boost/iostreams/chain.hpp @@ -14,7 +14,6 @@ #include #include -#include // unary_function. #include // advance. #include #include // allocator, auto_ptr. @@ -286,7 +285,9 @@ class chain_base { static void set_auto_close(streambuf_type* b, bool close) { b->set_auto_close(close); } - struct closer : public std::unary_function { + struct closer { + typedef streambuf_type* argument_type; + typedef void result_type; closer(BOOST_IOS::openmode m) : mode_(m) { } void operator() (streambuf_type* b) { diff --git a/bundled/boost-1.62.0/include/boost/numeric/conversion/detail/converter.hpp b/bundled/boost-1.62.0/include/boost/numeric/conversion/detail/converter.hpp index 10550f8daaed..2884e84e8d8a 100644 --- a/bundled/boost-1.62.0/include/boost/numeric/conversion/detail/converter.hpp +++ b/bundled/boost-1.62.0/include/boost/numeric/conversion/detail/converter.hpp @@ -450,10 +450,7 @@ namespace boost { namespace numeric { namespace convdetail // Trivial Converter : used when (cv-unqualified) T == (cv-unqualified) S // template - struct trivial_converter_impl : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type - ,BOOST_DEDUCED_TYPENAME Traits::result_type - > - ,public dummy_range_checker + struct trivial_converter_impl : public dummy_range_checker { typedef Traits traits ; @@ -471,10 +468,7 @@ namespace boost { namespace numeric { namespace convdetail // Rounding Converter : used for float to integral conversions. // template - struct rounding_converter : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type - ,BOOST_DEDUCED_TYPENAME Traits::result_type - > - ,public RangeChecker + struct rounding_converter : public RangeChecker ,public Float2IntRounder ,public RawConverter { @@ -501,10 +495,7 @@ namespace boost { namespace numeric { namespace convdetail // Non-Rounding Converter : used for all other conversions. // template - struct non_rounding_converter : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type - ,BOOST_DEDUCED_TYPENAME Traits::result_type - > - ,public RangeChecker + struct non_rounding_converter : public RangeChecker ,public RawConverter { typedef RangeChecker RangeCheckerBase ; diff --git a/bundled/boost-1.62.0/include/boost/signals2/detail/signal_template.hpp b/bundled/boost-1.62.0/include/boost/signals2/detail/signal_template.hpp index fb7591bbc14c..fa19499d871e 100644 --- a/bundled/boost-1.62.0/include/boost/signals2/detail/signal_template.hpp +++ b/bundled/boost-1.62.0/include/boost/signals2/detail/signal_template.hpp @@ -599,7 +599,6 @@ namespace boost class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION: public signal_base, public detail::BOOST_SIGNALS2_STD_FUNCTIONAL_BASE - (typename detail::result_type_wrapper::type) { typedef detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) impl_class; diff --git a/bundled/boost-1.62.0/include/boost/signals2/detail/signals_common_macros.hpp b/bundled/boost-1.62.0/include/boost/signals2/detail/signals_common_macros.hpp index 4ca440382750..acc09362814d 100644 --- a/bundled/boost-1.62.0/include/boost/signals2/detail/signals_common_macros.hpp +++ b/bundled/boost-1.62.0/include/boost/signals2/detail/signals_common_macros.hpp @@ -137,7 +137,7 @@ #define BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(arity) BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(arity) #define BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION -#define BOOST_SIGNALS2_STD_FUNCTIONAL_BASE(result_type) std_functional_base +#define BOOST_SIGNALS2_STD_FUNCTIONAL_BASE std_functional_base #define BOOST_SIGNALS2_PP_COMMA_IF(arity) BOOST_PP_COMMA_IF(arity) @@ -205,8 +205,8 @@ ExtendedSlotFunction, \ Mutex> -#define BOOST_SIGNALS2_STD_FUNCTIONAL_BASE(result_type) \ - std_functional_base +#define BOOST_SIGNALS2_STD_FUNCTIONAL_BASE \ + std_functional_base #define BOOST_SIGNALS2_PP_COMMA_IF(arity) , diff --git a/bundled/boost-1.62.0/include/boost/signals2/detail/slot_template.hpp b/bundled/boost-1.62.0/include/boost/signals2/detail/slot_template.hpp index fc19f5139cc4..1c17c5b76aff 100644 --- a/bundled/boost-1.62.0/include/boost/signals2/detail/slot_template.hpp +++ b/bundled/boost-1.62.0/include/boost/signals2/detail/slot_template.hpp @@ -35,7 +35,7 @@ namespace boost template class BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) BOOST_SIGNALS2_SLOT_TEMPLATE_SPECIALIZATION - : public slot_base, public detail::BOOST_SIGNALS2_STD_FUNCTIONAL_BASE(R) + : public slot_base, public detail::BOOST_SIGNALS2_STD_FUNCTIONAL_BASE { public: diff --git a/bundled/boost-1.62.0/include/boost/signals2/detail/variadic_arg_type.hpp b/bundled/boost-1.62.0/include/boost/signals2/detail/variadic_arg_type.hpp index 14d54b2e3ed2..db9e81c2f3d6 100644 --- a/bundled/boost-1.62.0/include/boost/signals2/detail/variadic_arg_type.hpp +++ b/bundled/boost-1.62.0/include/boost/signals2/detail/variadic_arg_type.hpp @@ -32,15 +32,20 @@ namespace boost typedef typename variadic_arg_type::type type; }; - template + template struct std_functional_base {}; - template - struct std_functional_base: public std::unary_function - {}; - template - struct std_functional_base: public std::binary_function - {}; + template + struct std_functional_base + { + typedef T1 argument_type; + }; + template + struct std_functional_base + { + typedef T1 first_argument_type; + typedef T2 second_argument_type; + }; } // namespace detail } // namespace signals2 } // namespace boost diff --git a/bundled/boost-1.62.0/include/boost/smart_ptr/owner_less.hpp b/bundled/boost-1.62.0/include/boost/smart_ptr/owner_less.hpp index 6899325bd61e..88c3c226d0b9 100644 --- a/bundled/boost-1.62.0/include/boost/smart_ptr/owner_less.hpp +++ b/bundled/boost-1.62.0/include/boost/smart_ptr/owner_less.hpp @@ -5,53 +5,30 @@ // owner_less.hpp // // Copyright (c) 2008 Frank Mori Hess +// Copyright (c) 2016 Peter Dimov // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // -// See http://www.boost.org/libs/smart_ptr/smart_ptr.htm for documentation. +// See http://www.boost.org/libs/smart_ptr/ for documentation. // -#include - namespace boost { - template class shared_ptr; - template class weak_ptr; - - namespace detail - { - template - struct generic_owner_less : public std::binary_function - { - bool operator()(const T &lhs, const T &rhs) const - { - return lhs.owner_before(rhs); - } - bool operator()(const T &lhs, const U &rhs) const - { - return lhs.owner_before(rhs); - } - bool operator()(const U &lhs, const T &rhs) const - { - return lhs.owner_before(rhs); - } - }; - } // namespace detail - template struct owner_less; - - template - struct owner_less >: - public detail::generic_owner_less, weak_ptr > - {}; +template struct owner_less +{ + typedef bool result_type; + typedef T first_argument_type; + typedef T second_argument_type; - template - struct owner_less >: - public detail::generic_owner_less, shared_ptr > - {}; + template bool operator()( U const & u, V const & v ) const + { + return u.owner_before( v ); + } +}; } // namespace boost -#endif // #ifndef BOOST_SMART_PTR_OWNER_LESS_HPP_INCLUDED +#endif // #ifndef BOOST_SMART_PTR_OWNER_LESS_HPP_INCLUDED \ No newline at end of file diff --git a/bundled/boost-1.62.0/include/boost/typeof/std/functional.hpp b/bundled/boost-1.62.0/include/boost/typeof/std/functional.hpp index f1b157764e4e..043a2ba27a08 100644 --- a/bundled/boost-1.62.0/include/boost/typeof/std/functional.hpp +++ b/bundled/boost-1.62.0/include/boost/typeof/std/functional.hpp @@ -10,8 +10,10 @@ #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() +#ifndef BOOST_NO_CXX98_FUNCTION_BASE BOOST_TYPEOF_REGISTER_TEMPLATE(std::unary_function, 2) BOOST_TYPEOF_REGISTER_TEMPLATE(std::binary_function, 3) +#endif//BOOST_NO_CXX98_FUNCTION_BASE BOOST_TYPEOF_REGISTER_TEMPLATE(std::plus, 1) BOOST_TYPEOF_REGISTER_TEMPLATE(std::minus, 1) BOOST_TYPEOF_REGISTER_TEMPLATE(std::multiplies, 1) diff --git a/bundled/boost-1.62.0/include/boost/utility/compare_pointees.hpp b/bundled/boost-1.62.0/include/boost/utility/compare_pointees.hpp index 7e2515c6eea2..7914370f1fad 100644 --- a/bundled/boost-1.62.0/include/boost/utility/compare_pointees.hpp +++ b/bundled/boost-1.62.0/include/boost/utility/compare_pointees.hpp @@ -33,14 +33,17 @@ bool equal_pointees ( OptionalPointee const& x, OptionalPointee const& y ) } template -struct equal_pointees_t : std::binary_function +struct equal_pointees_t { + typedef bool result_type; + typedef OptionalPointee first_argument_type; + typedef OptionalPointee second_argument_type; + bool operator() ( OptionalPointee const& x, OptionalPointee const& y ) const { return equal_pointees(x,y) ; } } ; // template bool less_pointees(OP const& x, OP const& y); -// template struct less_pointees_t; // // Being OP a model of OptionalPointee (either a pointer or an optional): // @@ -56,8 +59,12 @@ bool less_pointees ( OptionalPointee const& x, OptionalPointee const& y ) } template -struct less_pointees_t : std::binary_function +struct less_pointees_t { + typedef bool result_type; + typedef OptionalPointee first_argument_type; + typedef OptionalPointee second_argument_type; + bool operator() ( OptionalPointee const& x, OptionalPointee const& y ) const { return less_pointees(x,y) ; } } ; diff --git a/cmake/checks/check_01_cpu_features.cmake b/cmake/checks/check_01_cpu_features.cmake index f69c1ee268f5..c86145d6feff 100644 --- a/cmake/checks/check_01_cpu_features.cmake +++ b/cmake/checks/check_01_cpu_features.cmake @@ -28,8 +28,8 @@ # DEAL_II_HAVE_AVX *) # DEAL_II_HAVE_AVX512 *) # DEAL_II_HAVE_ALTIVEC *) -# DEAL_II_COMPILER_VECTORIZATION_LEVEL # DEAL_II_HAVE_OPENMP_SIMD *) +# DEAL_II_COMPILER_VECTORIZATION_LEVEL # DEAL_II_OPENMP_SIMD_PRAGMA # # *) @@ -245,7 +245,36 @@ IF(DEAL_II_ALLOW_PLATFORM_INTROSPECTION) } " DEAL_II_HAVE_ALTIVEC) -ENDIF() + + # + # OpenMP 4.0 can be used for vectorization. Only the vectorization + # instructions are allowed, the threading must be done through TBB. + # + + # + # Choosing the right compiler flag is a bit of a mess: + # + IF(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + IF("${CMAKE_CXX_COMPILER_VERSION}" VERSION_GREATER "15" ) + SET(_keyword "qopenmp") + ELSEIF("${CMAKE_CXX_COMPILER_VERSION}" VERSION_GREATER "14" ) + SET(_keyword "openmp") + ENDIF() + ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + SET(_keyword "openmp") + ELSE() + SET(_keyword "fopenmp") + ENDIF() + + CHECK_CXX_COMPILER_FLAG("-${_keyword}-simd" DEAL_II_HAVE_OPENMP_SIMD) + +ENDIF() # IF DEAL_II_ALLOW_PLATFORM_INTROSPECTION + + +# +# Choose DEAL_II_COMPILER_VECTORIZATION level depending on AVX support +# (that was autodetected or manually specified). +# IF(DEAL_II_HAVE_AVX512) SET(DEAL_II_COMPILER_VECTORIZATION_LEVEL 3) @@ -263,26 +292,9 @@ ENDIF() # -# OpenMP 4.0 can be used for vectorization. Only the vectorization -# instructions are allowed, the threading must be done through TBB. -# - +# If we have OpenMP SIMD support (i.e. DEAL_II_HAVE_OPENMP_SIMD is true) +# populate DEAL_II_OPENMP_SIMD_PRAGMA. # -# Choosing the right compiler flag is a bit of a mess: -# -IF(CMAKE_CXX_COMPILER_ID MATCHES "Intel") - IF("${CMAKE_CXX_COMPILER_VERSION}" VERSION_GREATER "15" ) - SET(_keyword "qopenmp") - ELSEIF("${CMAKE_CXX_COMPILER_VERSION}" VERSION_GREATER "14" ) - SET(_keyword "openmp") - ENDIF() -ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - SET(_keyword "openmp") -ELSE() - SET(_keyword "fopenmp") -ENDIF() - -CHECK_CXX_COMPILER_FLAG("-${_keyword}-simd" DEAL_II_HAVE_OPENMP_SIMD) SET(DEAL_II_OPENMP_SIMD_PRAGMA " ") IF(DEAL_II_HAVE_OPENMP_SIMD) diff --git a/cmake/checks/check_01_cxx_features.cmake b/cmake/checks/check_01_cxx_features.cmake index bf1aedec3bee..d1ec609daaf0 100644 --- a/cmake/checks/check_01_cxx_features.cmake +++ b/cmake/checks/check_01_cxx_features.cmake @@ -32,6 +32,17 @@ # +# +# MSVC needs different compiler flags to turn warnings into errors +# additionally a suitable exception handling model is required +# +IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + SET(_werror_flag "/WX /EHsc") +ELSE() + SET(_werror_flag "-Werror") +ENDIF() + + ######################################################################## # # # C++ Version Support: # @@ -99,9 +110,16 @@ ENDIF() MACRO(_check_cxx_flag _suffix) IF("${DEAL_II_CXX_VERSION_FLAG}" STREQUAL "") - CHECK_CXX_COMPILER_FLAG("-std=c++${_suffix}" DEAL_II_HAVE_FLAG_stdcxx${_suffix}) - IF(DEAL_II_HAVE_FLAG_stdcxx${_suffix}) - SET(DEAL_II_CXX_VERSION_FLAG "-std=c++${_suffix}") + IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + CHECK_CXX_COMPILER_FLAG("/std:c++${_suffix}" DEAL_II_HAVE_FLAG_stdcxx${_suffix}) + IF(DEAL_II_HAVE_FLAG_stdcxx${_suffix}) + SET(DEAL_II_CXX_VERSION_FLAG "/std:c++${_suffix}") + ENDIF() + ELSE() + CHECK_CXX_COMPILER_FLAG("-std=c++${_suffix}" DEAL_II_HAVE_FLAG_stdcxx${_suffix}) + IF(DEAL_II_HAVE_FLAG_stdcxx${_suffix}) + SET(DEAL_II_CXX_VERSION_FLAG "-std=c++${_suffix}") + ENDIF() ENDIF() ENDIF() ENDMACRO() @@ -126,7 +144,7 @@ IF(NOT DEFINED DEAL_II_WITH_CXX17 OR DEAL_II_WITH_CXX17) IF(NOT "${DEAL_II_CXX_VERSION_FLAG}" STREQUAL "") # Set CMAKE_REQUIRED_FLAGS for the unit tests MESSAGE(STATUS "Using C++ version flag \"${DEAL_II_CXX_VERSION_FLAG}\"") - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_VERSION_FLAG} -Werror") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_VERSION_FLAG} ${_werror_flag}") UNSET_IF_CHANGED(CHECK_CXX_FEATURES_FLAGS_CXX17_SAVED "${CMAKE_REQUIRED_FLAGS}${DEAL_II_CXX_VERSION_FLAG}" @@ -512,6 +530,9 @@ _bailout("17" "1z") # try to avoid adding an extra flag by doing one last test: # RESET_CMAKE_REQUIRED() +IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/Zc:__cplusplus") +ENDIF() CHECK_CXX_SOURCE_COMPILES( " #include @@ -527,6 +548,7 @@ CHECK_CXX_SOURCE_COMPILES( } " DEAL_II_COMPILER_DEFAULTS_TO_CXX11_OR_NEWER) +RESET_CMAKE_REQUIRED() IF(_user_provided_cxx_version_flag OR NOT DEAL_II_COMPILER_DEFAULTS_TO_CXX11_OR_NEWER OR @@ -570,7 +592,10 @@ UNSET_IF_CHANGED(CHECK_CXX_FEATURES_FLAGS_SAVED # possibilities here. # ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_FLAGS}") -ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror -Wno-unused-command-line-argument") +ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${_werror_flag}") +IF(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Wno-unused-command-line-argument") +ENDIF() # # first try the attribute [[fallthrough]] # diff --git a/cmake/checks/check_02_compiler_features.cmake b/cmake/checks/check_02_compiler_features.cmake index 7ac38fe19f3c..32019e2d331c 100644 --- a/cmake/checks/check_02_compiler_features.cmake +++ b/cmake/checks/check_02_compiler_features.cmake @@ -48,6 +48,15 @@ UNSET_IF_CHANGED(CHECK_CXX_FEATURES_FLAGS_SAVED DEAL_II_COMPILER_HAS_ATTRIBUTE_DEPRECATED ) +# +# MSVC needs different compiler flags to turn warnings into errors +# additionally a suitable exception handling model is required +# +IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + SET(_werror_flag "/WX /EHsc") +ELSE() + SET(_werror_flag "-Werror") +ENDIF() # # Check whether the compiler allows to use arithmetic operations @@ -298,7 +307,10 @@ ENDIF() # "warning #1292: unknown attribute "deprecated"" (icc) # Hence, we treat warnings as errors: ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_FLAGS}") -ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror -Wno-unused-command-line-argument") +ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${_werror_flag}") +IF(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Wno-unused-command-line-argument") +ENDIF() # first see if the compiler accepts the attribute CHECK_CXX_SOURCE_COMPILES( @@ -405,7 +417,7 @@ ENDIF() # # - Matthias Maier, 2015 # -ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") +ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${_werror_flag}") CHECK_CXX_SOURCE_COMPILES( " _Pragma(\"GCC diagnostic push\") @@ -420,33 +432,52 @@ RESET_CMAKE_REQUIRED() # -# Use the 'gold' linker if possible, given that it's substantially faster. +# Use 'lld' or the 'gold' linker if possible, given that either of them is +# substantially faster. # -# We have to try to link a full executable with -fuse-ld=gold to check -# whether "ld.gold" is actually available. +# We have to try to link a full executable with -fuse-ld=lld or -fuse-ld=gold +# to check whether "ld.lld" or "ld.gold" is actually available. # -# Clang always reports "argument unused during compilation" -# if "-fuse-ld=" is used, but fails at link time for an unsupported linker. +# Clang always reports "argument unused during compilation", but fails at link +# time for an unsupported linker. # # ICC also emits a warning but passes for unsupported linkers # unless we turn diagnostic warnings into errors. # # Wolfgang Bangerth, Matthias Maier, Daniel Arndt, 2015, 2018 # -IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Wno-unused-command-line-argument") -ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Intel") - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-diag-error warn") -ENDIF() -ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror -fuse-ld=gold") -CHECK_CXX_SOURCE_COMPILES( - " - int main() { return 0; } - " - DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) -RESET_CMAKE_REQUIRED() +IF(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Wno-unused-command-line-argument") + ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-diag-error warn") + ENDIF() + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-fuse-ld=lld") + CHECK_CXX_SOURCE_COMPILES( + " + int main() { return 0; } + " + DEAL_II_COMPILER_HAS_FUSE_LD_LLD) + RESET_CMAKE_REQUIRED() -IF(DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) - ADD_FLAGS(DEAL_II_LINKER_FLAGS "-fuse-ld=gold") -ENDIF() + IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Wno-unused-command-line-argument") + ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-diag-error warn") + ENDIF() + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-fuse-ld=gold") + CHECK_CXX_SOURCE_COMPILES( + " + int main() { return 0; } + " + DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) + RESET_CMAKE_REQUIRED() + IF(DEAL_II_COMPILER_HAS_FUSE_LD_LLD) + ADD_FLAGS(DEAL_II_LINKER_FLAGS "-fuse-ld=lld") + ELSEIF(DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) + ADD_FLAGS(DEAL_II_LINKER_FLAGS "-fuse-ld=gold") + ENDIF() +ENDIF() diff --git a/cmake/config/template-arguments.in b/cmake/config/template-arguments.in index 551fdd08d3cc..3370a92a6cbd 100644 --- a/cmake/config/template-arguments.in +++ b/cmake/config/template-arguments.in @@ -95,6 +95,10 @@ VECTOR_TYPES := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT@; + @DEAL_II_EXPAND_TPETRA_VECTOR_COMPLEX_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_COMPLEX_FLOAT@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR@; @DEAL_II_EXPAND_TRILINOS_MPI_BLOCKVECTOR@; @@ -120,6 +124,8 @@ REAL_VECTOR_TYPES := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR_REAL@; @DEAL_II_EXPAND_TRILINOS_MPI_BLOCKVECTOR@; @@ -138,6 +144,8 @@ REAL_NONBLOCK_VECTORS := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR_REAL@; } @@ -145,6 +153,10 @@ REAL_NONBLOCK_VECTORS := { Vector; EXTERNAL_PARALLEL_VECTORS := { @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_TRILINOS_MPI_BLOCKVECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT@; + @DEAL_II_EXPAND_TPETRA_VECTOR_COMPLEX_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_COMPLEX_FLOAT@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR@; @DEAL_II_EXPAND_PETSC_MPI_BLOCKVECTOR@ } @@ -163,6 +175,10 @@ VECTORS_WITH_MATRIX := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT@; + @DEAL_II_EXPAND_TPETRA_VECTOR_COMPLEX_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_COMPLEX_FLOAT@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR@; } @@ -250,6 +266,9 @@ SPACE_DIMENSIONS := { 1; 2; 3 } // all ranks used for instantiating tensors RANKS := { 1; 2; 3; 4 } +// all ranks used for instantiating symmetric tensors +SYM_RANKS := { 2; 4 } + // Flags that are allowed in DataOutInterface::set_flags OUTPUT_FLAG_TYPES := { DXFlags; UcdFlags; GnuplotFlags; PovrayFlags; EpsFlags; GmvFlags; TecplotFlags; VtkFlags; SvgFlags; diff --git a/cmake/configure/CUDAComputeCapability/cuda_compute_capability.cu b/cmake/configure/CUDAComputeCapability/cuda_compute_capability.cu new file mode 100644 index 000000000000..23225d463234 --- /dev/null +++ b/cmake/configure/CUDAComputeCapability/cuda_compute_capability.cu @@ -0,0 +1,30 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2019 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE.md at +// the top level directory of deal.II. +// +// --------------------------------------------------------------------- + +#include + +int main() +{ + cudaDeviceProp device_properties; + const cudaError_t error = cudaGetDeviceProperties(&device_properties, + /*device*/0); + if( error != cudaSuccess) + { + std::cout << "CUDA error: " << cudaGetErrorString(error) << '\n'; + return error; + } + std::cout << device_properties.major << device_properties.minor; + return 0; +} diff --git a/cmake/configure/configure_1_cuda.cmake b/cmake/configure/configure_1_cuda.cmake index ce01a3b95a34..94c34940db70 100644 --- a/cmake/configure/configure_1_cuda.cmake +++ b/cmake/configure/configure_1_cuda.cmake @@ -85,6 +85,41 @@ MACRO(FEATURE_CUDA_FIND_EXTERNAL var) SET(CUDA_COMPUTE_CAPABILITY "${CMAKE_MATCH_1}") ELSEIF("${DEAL_II_CUDA_FLAGS_SAVED}" MATCHES "-arch=sm_([0-9]*)") SET(CUDA_COMPUTE_CAPABILITY "${CMAKE_MATCH_1}") + ELSEIF(DEAL_II_ALLOW_PLATFORM_INTROSPECTION) + # + # Try to autodetect the CUDA Compute Capability by asking the device + # + SET(_binary_test_dir ${CMAKE_CURRENT_BINARY_DIR}/cmake/configure/CUDAComputeCapabilityWorkdir) + FILE(REMOVE_RECURSE ${_binary_test_dir}) + FILE(MAKE_DIRECTORY ${_binary_test_dir}) + + EXECUTE_PROCESS( + COMMAND ${CUDA_NVCC_EXECUTABLE} + -ccbin=${CMAKE_CXX_COMPILER} + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/configure/CUDAComputeCapability/cuda_compute_capability.cu + -o cuda_compute_capability + WORKING_DIRECTORY ${_binary_test_dir} + OUTPUT_QUIET + ERROR_QUIET + ) + EXECUTE_PROCESS(COMMAND ${_binary_test_dir}/cuda_compute_capability + RESULT_VARIABLE _result + OUTPUT_VARIABLE CUDA_COMPUTE_CAPABILITY) + IF(${_result} EQUAL 0) + ADD_FLAGS(DEAL_II_CUDA_FLAGS "-arch=sm_${CUDA_COMPUTE_CAPABILITY}") + MESSAGE(STATUS "Detected CUDA Compute Capability ${CUDA_COMPUTE_CAPABILITY}") + ELSE() + MESSAGE(STATUS "Couldn't detect CUDA Compute Capability! " + "The error message was: ${CUDA_COMPUTE_CAPABILITY}") + SET(CUDA_ADDITIONAL_ERROR_STRING + ${CUDA_ADDITIONAL_ERROR_STRING} + "Couldn't detect CUDA Compute Capability! " + "The error message was: ${CUDA_COMPUTE_CAPABILITY}\n" + "Please check the return value of ${_binary_test_dir}/cuda_compute_capability.\n" + "If you want to disable the autodetection, set the compute capability to be used manually." + ) + SET(${var} FALSE) + ENDIF() ELSE() # # Assume a cuda compute capability of 35 diff --git a/cmake/configure/configure_1_lapack.cmake b/cmake/configure/configure_1_lapack.cmake index 2eb4519a15db..b773ccbb8d1e 100644 --- a/cmake/configure/configure_1_lapack.cmake +++ b/cmake/configure/configure_1_lapack.cmake @@ -18,6 +18,7 @@ # MACRO(FEATURE_LAPACK_FIND_EXTERNAL var) + CLEAR_CMAKE_REQUIRED() FIND_PACKAGE(LAPACK) # diff --git a/cmake/configure/configure_1_mpi.cmake b/cmake/configure/configure_1_mpi.cmake index f5e349b1126e..a5929c590838 100644 --- a/cmake/configure/configure_1_mpi.cmake +++ b/cmake/configure/configure_1_mpi.cmake @@ -39,44 +39,6 @@ MACRO(FEATURE_MPI_FIND_EXTERNAL var) SET(${var} FALSE) ENDIF() - CHECK_COMPILER_SETUP( - "${DEAL_II_CXX_FLAGS} ${DEAL_II_CXX_FLAGS_SAVED} ${MPI_CXX_FLAGS}" - "${DEAL_II_LINKER_FLAGS} ${DEAL_II_LINKER_FLAGS_SAVED} ${MPI_LINKER_FLAGS}" - MPI_WORKING_COMPILER - ${DEAL_II_LIBRARIES} ${MPI_LIBRARIES} - ) - - IF(NOT MPI_WORKING_COMPILER) - # - # Try a workaround and drop "-fuse-ld=gold" (if present) from the - # linker invocation - # - MESSAGE(STATUS "Unable to compile a simple test program. " - "Try to drop \"-fuse-ld=gold\" from the linker flags." - ) - STRING(REPLACE "-fuse-ld=gold" "" _filtered_flags "${DEAL_II_LINKER_FLAGS}") - - CHECK_COMPILER_SETUP( - "${DEAL_II_CXX_FLAGS} ${DEAL_II_CXX_FLAGS_SAVED} ${MPI_CXX_FLAGS}" - "${_filtered_flags} ${DEAL_II_LINKER_FLAGS_SAVED} ${MPI_LINKER_FLAGS}" - MPI_WORKING_COMPILER - ${DEAL_II_LIBRARIES} ${MPI_LIBRARIES} - ) - - IF(MPI_WORKING_COMPILER) - SET(DEAL_II_LINKER_FLAGS "${_filtered_flags}") - ELSE() - MESSAGE(STATUS "Could not find a sufficient MPI installation: " - "Unable to compile a simple test program." - ) - SET(MPI_ADDITIONAL_ERROR_STRING - ${MPI_ADDITIONAL_ERROR_STRING} - "Unable to compile and link a simple test program with your MPI installation. \n" - ) - SET(${var} FALSE) - ENDIF() - ENDIF() - ENDIF() ENDMACRO() diff --git a/cmake/configure/configure_2_boost.cmake b/cmake/configure/configure_2_boost.cmake index 5c6f9c35a806..1637b16695c8 100644 --- a/cmake/configure/configure_2_boost.cmake +++ b/cmake/configure/configure_2_boost.cmake @@ -58,7 +58,11 @@ MACRO(FEATURE_BOOST_CONFIGURE_COMMON) # Older boost versions can't know about this but provide a possibility to # circumvent the issue. Hence, we just check ourselves. ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_VERSION_FLAG}") - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") + IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX /EHsc") + ELSE() + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") + ENDIF() CHECK_CXX_SOURCE_COMPILES( " diff --git a/cmake/configure/configure_2_ginkgo.cmake b/cmake/configure/configure_2_ginkgo.cmake new file mode 100644 index 000000000000..5b778ae75a11 --- /dev/null +++ b/cmake/configure/configure_2_ginkgo.cmake @@ -0,0 +1,39 @@ +## --------------------------------------------------------------------- +## +## Copyright (C) 2018 by the deal.II authors +## +## This file is part of the deal.II library. +## +## The deal.II library is free software; you can use it, redistribute +## it, and/or modify it under the terms of the GNU Lesser General +## Public License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## The full text of the license can be found in the file LICENSE.md at +## the top level directory of deal.II. +## +## --------------------------------------------------------------------- + +# +# Configuration for the Ginkgo library: +# + +MACRO(FEATURE_GINKGO_ERROR_MESSAGE) + MESSAGE(FATAL_ERROR "\n" + "Could not find Ginkgo and supporting libraries!\n" + "Please ensure that the libraries are installed on your computer.\n" + "If the libraries are not at a default location, either provide some hints\n" + "for the autodetection:\n" + " $ GINKGO_DIR=\"...\" cmake <...>\n" + " $ cmake -DGINKGO_DIR=\"...\" <...>\n" + "or set the relevant variables by hand in ccmake.\n" + "Relevant hints for GINKGO are GINKGO_DIR.\n" + ) +ENDMACRO() + +MACRO(FEATURE_GINKGO_CONFIGURE_EXTERNAL) + SET(DEAL_II_GINKGO_BUILT_REFERENCE ${GINKGO_BUILT_REFERENCE}) + SET(DEAL_II_GINKGO_BUILT_OPENMP ${GINKGO_BUILT_OMP}) + SET(DEAL_II_GINKGO_BUILT_CUDA ${GINKGO_BUILT_CUDA}) +ENDMACRO() + +CONFIGURE_FEATURE(GINKGO) diff --git a/cmake/configure/configure_2_trilinos.cmake b/cmake/configure/configure_2_trilinos.cmake index c53f105c0995..7a1f32cc5cc0 100644 --- a/cmake/configure/configure_2_trilinos.cmake +++ b/cmake/configure/configure_2_trilinos.cmake @@ -146,7 +146,7 @@ MACRO(FEATURE_TRILINOS_FIND_EXTERNAL var) CHECK_MPI_INTERFACE(TRILINOS ${var}) IF (${var}) - FOREACH(_optional_module EpetraExt ROL Sacado Zoltan) + FOREACH(_optional_module EpetraExt ROL Sacado Tpetra Zoltan) ITEM_MATCHES(_module_found ${_optional_module} ${Trilinos_PACKAGE_LIST}) IF(_module_found) MESSAGE(STATUS "Found ${_optional_module}") @@ -158,6 +158,49 @@ MACRO(FEATURE_TRILINOS_FIND_EXTERNAL var) ENDFOREACH() ENDIF() + IF(${DEAL_II_TRILINOS_WITH_TPETRA}) + # + # Check if Tpetra is usable in fact. + # + LIST(APPEND CMAKE_REQUIRED_INCLUDES ${Trilinos_INCLUDE_DIRS}) + LIST(APPEND CMAKE_REQUIRED_INCLUDES ${MPI_CXX_INCLUDE_PATH}) + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_VERSION_FLAG}") + CHECK_SYMBOL_EXISTS( + "KOKKOS_ENABLE_CUDA_LAMBDA" + "Kokkos_Macros.hpp" + DEAL_II_KOKKOS_LAMBDA_EXISTS) + IF(${DEAL_II_KOKKOS_LAMBDA_EXISTS}) + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "--expt-extended-lambda") + ENDIF() + LIST(APPEND CMAKE_REQUIRED_LIBRARIES "${Trilinos_LIBRARIES}") + CHECK_CXX_SOURCE_COMPILES( + " + #include + int + main() + { + using LO = int; + using GO = unsigned int; + using Node = Kokkos::Compat::KokkosDeviceWrapperNode; + using map_type = Tpetra::Map; + Teuchos::RCP dummy_map = Teuchos::rcp(new map_type()); + Tpetra::Vector dummy_vector(dummy_map); + (void)dummy_vector; + return 0; + } + " + TRILINOS_TPETRA_IS_FUNCTIONAL + ) + RESET_CMAKE_REQUIRED() + IF(NOT TRILINOS_TPETRA_IS_FUNCTIONAL) + MESSAGE( + STATUS + "Tpetra was found but is not usable! Disabling Tpetra support." + ) + SET(DEAL_II_TRILINOS_WITH_TPETRA OFF) + ENDIF() + ENDIF() + IF(${DEAL_II_TRILINOS_WITH_SACADO}) # # Look for Sacado_config.h - we'll query it to determine C++11 support: @@ -227,6 +270,14 @@ MACRO(FEATURE_TRILINOS_CONFIGURE_EXTERNAL) SET(DEAL_II_EXPAND_TRILINOS_MPI_VECTOR "TrilinosWrappers::MPI::Vector") IF (TRILINOS_WITH_MPI) SET(DEAL_II_EXPAND_EPETRA_VECTOR "LinearAlgebra::EpetraWrappers::Vector") + IF (${DEAL_II_TRILINOS_WITH_TPETRA}) + SET(DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE "LinearAlgebra::TpetraWrappers::Vector") + SET(DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT "LinearAlgebra::TpetraWrappers::Vector") + IF (${DEAL_II_WITH_COMPLEX_NUMBERS}) + SET(DEAL_II_EXPAND_TPETRA_VECTOR_COMPLEX_DOUBLE "LinearAlgebra::TpetraWrappers::Vector>") + SET(DEAL_II_EXPAND_TPETRA_VECTOR_COMPLEX_FLOAT "LinearAlgebra::TpetraWrappers::Vector>") + ENDIF() + ENDIF() ENDIF() IF(${DEAL_II_TRILINOS_WITH_SACADO}) # Note: Only CMake 3.0 and greater support line continuation with the "\" character diff --git a/cmake/configure/configure_scalapack.cmake b/cmake/configure/configure_scalapack.cmake index 86ac09a3ab1a..08820ceecbbd 100644 --- a/cmake/configure/configure_scalapack.cmake +++ b/cmake/configure/configure_scalapack.cmake @@ -26,6 +26,36 @@ MACRO(FEATURE_SCALAPACK_FIND_EXTERNAL var) IF(SCALAPACK_FOUND) SET(${var} TRUE) CHECK_MPI_INTERFACE(SCALAPACK ${var}) + + IF (${var}) + SET(CMAKE_REQUIRED_LIBRARIES ${SCALAPACK_LIBRARIES} ${LAPACK_LIBRARIES}) + CHECK_C_SOURCE_COMPILES(" + void pdsyevr_(); + void pssyevr_(); + int main(){ + pdsyevr_(); + pssyevr_(); + return 0; + }" + DEAL_II_SCALAPACK_HAS_PDSYEVR_PSSYEVR) + RESET_CMAKE_REQUIRED() + + IF(NOT DEAL_II_SCALAPACK_HAS_PDSYEVR_PSSYEVR) + MESSAGE(STATUS "Could not find a sufficient SCALAPACK installation: " + "The required symbols pdsyevr_ and pssyevr_ were not found." + ) + SET(SCALAPACK_ADDITIONAL_ERROR_STRING + ${SCALAPACK_ADDITIONAL_ERROR_STRING} + "Could not find a sufficient SCALAPACK installation: \n" + "SCALAPACK symbol check for pdsyevr_ and pssyevr_ failed! " + "This usually means that your SCALAPACK installation is incomplete " + "or the link line is broken. Consult\n" + " CMakeFiles/CMakeError.log\n" + "for further information.\n" + ) + SET(${var} FALSE) + ENDIF() + ENDIF() ENDIF() ENDMACRO() diff --git a/cmake/configure/configure_sundials.cmake b/cmake/configure/configure_sundials.cmake index 4a67fdd8bcd7..0c62c14589de 100644 --- a/cmake/configure/configure_sundials.cmake +++ b/cmake/configure/configure_sundials.cmake @@ -17,6 +17,34 @@ # Configuration for the SUNDIALS library: # +MACRO(FEATURE_SUNDIALS_FIND_EXTERNAL var) + FIND_PACKAGE(SUNDIALS) + + IF(SUNDIALS_FOUND) + SET(${var} TRUE) + + # + # We don't support version 4.0.0 or later yet. + # + SET(_first_unsupported_sundials_version 4.0.0) + IF(NOT SUNDIALS_VERSION VERSION_LESS ${_first_unsupported_sundials_version}) + MESSAGE(STATUS + "Insufficient SUNDIALS installation found: " + "version ${_first_unsupported_sundials_version} " + "or later is not yet supported, " + "but version ${SUNDIALS_VERSION} was found." + ) + SET(SUNDIALS_ADDITIONAL_ERROR_STRING + "Insufficient SUNDIALS installation found!\n" + "Version ${_first_unsupported_sundials_version} " + "or later is not yet supported, " + "but version ${SUNDIALS_VERSION} was found.\n" + ) + SET(${var} FALSE) + ENDIF() + ENDIF() +ENDMACRO() + MACRO(FEATURE_SUNDIALS_CONFIGURE_EXTERNAL) SET(DEAL_II_SUNDIALS_WITH_IDAS ${SUNDIALS_WITH_IDAS}) ENDMACRO() diff --git a/cmake/configure/configure_symengine.cmake b/cmake/configure/configure_symengine.cmake new file mode 100644 index 000000000000..20da3601c285 --- /dev/null +++ b/cmake/configure/configure_symengine.cmake @@ -0,0 +1,63 @@ +## --------------------------------------------------------------------- +## +## Copyright (C) 2019 by the deal.II authors +## +## This file is part of the deal.II library. +## +## The deal.II library is free software; you can use it, redistribute +## it, and/or modify it under the terms of the GNU Lesser General +## Public License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## The full text of the license can be found in the file LICENSE at +## the top level of the deal.II distribution. +## +## --------------------------------------------------------------------- + +# +# Configuration for the SymEngine library: +# + + +MACRO(FEATURE_SYMENGINE_FIND_EXTERNAL var) + FIND_PACKAGE(SYMENGINE) + + IF(SYMENGINE_FOUND) + SET(${var} TRUE) + + # + # We require at least version 0.4 of the symengine library: + # + SET(_version_required "0.4") + + IF(SYMENGINE_VERSION VERSION_LESS ${_version_required}) + MESSAGE(STATUS "Insufficient SymEngine installation found: " + "At least version ${_version_required} is required " + "but version ${SYMENGINE_VERSION} was found." + ) + SET(SYMENGINE_ADDITIONAL_ERROR_STRING + "Insufficient SymEngine installation found!\n" + "At least version ${_version_required} is required " + "but version ${SYMENGINE_VERSION} was found.\n" + ) + SET(${var} FALSE) + ENDIF() + ENDIF() +ENDMACRO() + +MACRO(FEATURE_SYMENGINE_CONFIGURE_EXTERNAL) + SET(DEAL_II_SYMENGINE_WITH_LLVM ${SYMENGINE_WITH_LLVM}) + + IF(DEAL_II_SYMENGINE_WITH_LLVM) + MESSAGE(STATUS "Configured with SymEngine LLVM capabilities.") + ENDIF() + + # + # Overwrite the compiler flags imported from SymEngine + # + SET(SYMENGINE_CXX_FLAGS) + SET(SYMENGINE_CXX_FLAGS_DEBUG) + SET(SYMENGINE_CXX_FLAGS_RELEASE) +ENDMACRO() + + +CONFIGURE_FEATURE(SYMENGINE) diff --git a/cmake/macros/macro_deal_ii_invoke_autopilot.cmake b/cmake/macros/macro_deal_ii_invoke_autopilot.cmake index 94fcbc8a4982..e93e95a0cf75 100644 --- a/cmake/macros/macro_deal_ii_invoke_autopilot.cmake +++ b/cmake/macros/macro_deal_ii_invoke_autopilot.cmake @@ -138,21 +138,37 @@ MACRO(DEAL_II_INVOKE_AUTOPILOT) ) ENDIF() + # # Define custom targets to easily switch the build type: - ADD_CUSTOM_TARGET(debug - COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR} - COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target all - COMMENT "Switch CMAKE_BUILD_TYPE to Debug" - ) + # - ADD_CUSTOM_TARGET(release - COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR} - COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target all - COMMENT "Switch CMAKE_BUILD_TYPE to Release" - ) + IF(${DEAL_II_BUILD_TYPE} MATCHES "Debug") + ADD_CUSTOM_TARGET(debug + COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR} + COMMAND ${CMAKE_COMMAND} -E echo "***" + COMMAND ${CMAKE_COMMAND} -E echo "*** Switched to Debug mode. Now recompile with: ${_make_command}" + COMMAND ${CMAKE_COMMAND} -E echo "***" + COMMENT "Switching CMAKE_BUILD_TYPE to Debug" + VERBATIM + ) + ENDIF() + IF(${DEAL_II_BUILD_TYPE} MATCHES "Release") + ADD_CUSTOM_TARGET(release + COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR} + COMMAND ${CMAKE_COMMAND} -E echo "***" + COMMAND ${CMAKE_COMMAND} -E echo "*** Switched to Release mode. Now recompile with: ${_make_command}" + COMMAND ${CMAKE_COMMAND} -E echo "***" + COMMENT "Switching CMAKE_BUILD_TYPE to Release" + VERBATIM + ) + ENDIF() + + # # Only mention release and debug targets if it is actually possible to # switch between them: + # + IF(${DEAL_II_BUILD_TYPE} MATCHES "DebugRelease") SET(_switch_targets "# ${_make_command} debug - to switch the build type to 'Debug' diff --git a/cmake/modules/FindBOOST.cmake b/cmake/modules/FindBOOST.cmake index 423dcd047ee8..8274a3613ee7 100644 --- a/cmake/modules/FindBOOST.cmake +++ b/cmake/modules/FindBOOST.cmake @@ -50,6 +50,12 @@ ENDIF() # temporarily disable ${CMAKE_SOURCE_DIR}/cmake/modules for module lookup LIST(REMOVE_ITEM CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules/) + +# Work around a CMake compatibility issue with boost-1.70.0 +# compare https://gitlab.kitware.com/cmake/cmake/issues/18865 +# and https://lists.boost.org/Archives/boost/2019/02/245016.php +SET(Boost_NO_BOOST_CMAKE ON) + IF(DEAL_II_WITH_ZLIB) FIND_PACKAGE(Boost ${BOOST_VERSION_REQUIRED} COMPONENTS iostreams serialization system thread @@ -77,7 +83,7 @@ IF(NOT Boost_FOUND AND Boost_USE_STATIC_LIBS) LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules/) ENDIF() - +UNSET(Boost_NO_BOOST_CMAKE) IF(Boost_FOUND) # diff --git a/cmake/modules/FindGINKGO.cmake b/cmake/modules/FindGINKGO.cmake new file mode 100644 index 000000000000..d05c2528bf15 --- /dev/null +++ b/cmake/modules/FindGINKGO.cmake @@ -0,0 +1,72 @@ +## --------------------------------------------------------------------- +## +## Copyright (C) 2018 by the deal.II authors +## +## This file is part of the deal.II library. +## +## The deal.II library is free software; you can use it, redistribute +## it, and/or modify it under the terms of the GNU Lesser General +## Public License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## The full text of the license can be found in the file LICENSE.md at +## the top level directory of deal.II. +## +## --------------------------------------------------------------------- + +# +# Try to find the GINKGO library +# +# This module exports +# +# GINKGO_INCLUDE_DIRS +# + +SET(GINKGO_DIR "" CACHE PATH "An optional hint to a GINKGO installation") +SET_IF_EMPTY(GINKGO_DIR "$ENV{GINKGO_DIR}") + +DEAL_II_FIND_LIBRARY(GINKGO_LIBRARY + NAMES ginkgo + HINTS ${GINKGO_DIR} + PATH_SUFFIXES + lib${LIB_SUFFIX} lib64 lib + # This is a hint, isn't it? + build/${CMAKE_CXX_PLATFORM_ID}-${CMAKE_SYSTEM_PROCESSOR}/libginkgo + ) +DEAL_II_FIND_LIBRARY(GINKGO_REFERENCE_LIBRARY + NAMES ginkgo_reference + HINTS ${GINKGO_DIR} + PATH_SUFFIXES + lib${LIB_SUFFIX} lib64 lib + # This is a hint, isn't it? + build/${CMAKE_CXX_PLATFORM_ID}-${CMAKE_SYSTEM_PROCESSOR}/libginkgo_reference + ) +DEAL_II_FIND_LIBRARY(GINKGO_OMP_LIBRARY + NAMES ginkgo_omp + HINTS ${GINKGO_DIR} + PATH_SUFFIXES + lib${LIB_SUFFIX} lib64 lib + # This is a hint, isn't it? + build/${CMAKE_CXX_PLATFORM_ID}-${CMAKE_SYSTEM_PROCESSOR}/libginkgo_omp + ) +DEAL_II_FIND_LIBRARY(GINKGO_CUDA_LIBRARY + NAMES ginkgo_cuda + HINTS ${GINKGO_DIR} + PATH_SUFFIXES + lib${LIB_SUFFIX} lib64 lib + # This is a hint, isn't it? + build/${CMAKE_CXX_PLATFORM_ID}-${CMAKE_SYSTEM_PROCESSOR}/libginkgo_cuda + ) + +DEAL_II_FIND_PATH(GINKGO_INCLUDE_DIR ginkgo/ginkgo.hpp + HINTS ${GINKGO_DIR} + PATH_SUFFIXES include + ) + +DEAL_II_PACKAGE_HANDLE(GINKGO + LIBRARIES + REQUIRED GINKGO_LIBRARY GINKGO_REFERENCE_LIBRARY GINKGO_OMP_LIBRARY GINKGO_CUDA_LIBRARY + INCLUDE_DIRS REQUIRED GINKGO_INCLUDE_DIR + USER_INCLUDE_DIRS REQUIRED GINKGO_INCLUDE_DIR + CLEAR + GINKGO_INCLUDE_DIR + ) diff --git a/cmake/modules/FindLAPACK.cmake b/cmake/modules/FindLAPACK.cmake index 0d79cc018e20..4227e2c13f09 100644 --- a/cmake/modules/FindLAPACK.cmake +++ b/cmake/modules/FindLAPACK.cmake @@ -90,6 +90,7 @@ FOREACH(_lib ${_fortran_libs}) ENDFOREACH() +SET(_lapack_include_dirs ${LAPACK_INCLUDE_DIRS}) SET(_lapack_libraries ${LAPACK_LIBRARIES}) SET(_lapack_linker_flags ${LAPACK_LINKER_FLAGS}) DEAL_II_PACKAGE_HANDLE(LAPACK @@ -97,6 +98,10 @@ DEAL_II_PACKAGE_HANDLE(LAPACK REQUIRED _lapack_libraries OPTIONAL BLAS_LIBRARIES ${_additional_libraries} LINKER_FLAGS OPTIONAL _lapack_linker_flags BLAS_LINKER_FLAGS + INCLUDE_DIRS + OPTIONAL _lapack_include_dirs + USER_INCLUDE_DIRS + OPTIONAL _lapack_include_dirs CLEAR atlas_LIBRARY atlcblas_LIBRARY atllapack_LIBRARY blas_LIBRARY eigen_blas_LIBRARY f77blas_LIBRARY gslcblas_LIBRARY lapack_LIBRARY diff --git a/cmake/modules/FindSUNDIALS.cmake b/cmake/modules/FindSUNDIALS.cmake index a23e113e7fc6..f7bd1a76ecca 100644 --- a/cmake/modules/FindSUNDIALS.cmake +++ b/cmake/modules/FindSUNDIALS.cmake @@ -21,6 +21,10 @@ # SUNDIALS_LIBRARIES # SUNDIALS_INCLUDE_DIR # SUNDIALS_WITH_IDAS +# SUNDIALS_VERSION +# SUNDIALS_VERSION_MAJOR +# SUNDIALS_VERSION_MINOR +# SUNDIALS_VERSION_PATCH # # Note that sundials headers are typically installed in several directories, # e.g., @@ -86,16 +90,64 @@ ELSE() SET(SUNDIALS_WITH_IDAS FALSE) ENDIF() +# +# Extract SUNDIALS version. +# +DEAL_II_FIND_FILE(SUNDIALS_CONFIG_H + NAMES sundials_config.h + HINTS ${SUNDIALS_INCLUDE_DIR}/sundials + ) +IF(NOT SUNDIALS_CONFIG_H MATCHES "-NOTFOUND") + FILE(STRINGS "${SUNDIALS_CONFIG_H}" SUNDIALS_VERSION_MAJOR_STRING + REGEX "#define.*SUNDIALS_VERSION_MAJOR" + ) + STRING(REGEX REPLACE "^.*SUNDIALS_VERSION_MAJOR.*([0-9]+).*" "\\1" + SUNDIALS_VERSION_MAJOR "${SUNDIALS_VERSION_MAJOR_STRING}" + ) + FILE(STRINGS "${SUNDIALS_CONFIG_H}" SUNDIALS_VERSION_MINOR_STRING + REGEX "#define.*SUNDIALS_VERSION_MINOR" + ) + STRING(REGEX REPLACE "^.*SUNDIALS_VERSION_MINOR.*([0-9]+).*" "\\1" + SUNDIALS_VERSION_MINOR "${SUNDIALS_VERSION_MINOR_STRING}" + ) + FILE(STRINGS "${SUNDIALS_CONFIG_H}" SUNDIALS_VERSION_PATCH_STRING + REGEX "#define.*SUNDIALS_VERSION_PATCH" + ) + STRING(REGEX REPLACE "^.*SUNDIALS_VERSION_PATCH.*([0-9]+).*" "\\1" + SUNDIALS_VERSION_PATCH "${SUNDIALS_VERSION_PATCH_STRING}" + ) +ENDIF() +IF(NOT "${SUNDIALS_VERSION_MAJOR}") + SET(SUNDIALS_VERSION_MAJOR "0") +ENDIF() +IF(NOT "${SUNDIALS_VERSION_MINOR}") + SET(SUNDIALS_VERSION_MINOR "0") +ENDIF() +IF(NOT "${SUNDIALS_VERSION_PATCH}") + SET(SUNDIALS_VERSION_PATCH "0") +ENDIF() +SET(SUNDIALS_VERSION + "${SUNDIALS_VERSION_MAJOR}.${SUNDIALS_VERSION_MINOR}.${SUNDIALS_VERSION_PATCH}" + ) DEAL_II_PACKAGE_HANDLE(SUNDIALS LIBRARIES REQUIRED - ${_sundials_lib_ida} SUNDIALS_LIB_ARKODE - SUNDIALS_LIB_KINSOL SUNDIALS_LIB_SER ${_sundials_lib_par} + ${_sundials_lib_ida} + SUNDIALS_LIB_ARKODE + SUNDIALS_LIB_KINSOL + SUNDIALS_LIB_SER + ${_sundials_lib_par} INCLUDE_DIRS REQUIRED SUNDIALS_INCLUDE_DIR USER_INCLUDE_DIRS REQUIRED SUNDIALS_INCLUDE_DIR CLEAR - SUNDIALS_LIB_IDA SUNDIALS_LIB_IDAS SUNDIALS_LIB_ARKODE - SUNDIALS_LIB_KINSOL SUNDIALS_LIB_SER ${_sundials_lib_par} + SUNDIALS_LIB_IDA + SUNDIALS_LIB_IDAS + SUNDIALS_LIB_ARKODE + SUNDIALS_LIB_KINSOL + SUNDIALS_LIB_SER + ${_sundials_lib_par} + SUNDIALS_INCLUDE_DIR + SUNDIALS_CONFIG_H ) diff --git a/cmake/modules/FindSYMENGINE.cmake b/cmake/modules/FindSYMENGINE.cmake new file mode 100644 index 000000000000..20b73fa50b6e --- /dev/null +++ b/cmake/modules/FindSYMENGINE.cmake @@ -0,0 +1,140 @@ +## --------------------------------------------------------------------- +## +## Copyright (C) 2019 by the deal.II authors +## +## This file is part of the deal.II library. +## +## The deal.II library is free software; you can use it, redistribute +## it, and/or modify it under the terms of the GNU Lesser General +## Public License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## The full text of the license can be found in the file LICENSE at +## the top level of the deal.II distribution. +## +## --------------------------------------------------------------------- + +# +# - Try to find SymEngine +# +# This module exports +# +# SYMENGINE_INCLUDE_DIR +# SYMENGINE_LIBRARY +# SYMENGINE_WITH_LLVM +# + +SET(SYMENGINE_DIR "" CACHE PATH "An optional hint to a SymEngine installation") +SET_IF_EMPTY(SYMENGINE_DIR "$ENV{SYMENGINE_DIR}") + +# +# SymEngine overwrites the CMake module path, so we save +# and restore it after this library is found and configured. +# +SET (DEAL_II_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) + +# +# Include the SymEngine: +# +FIND_PACKAGE(SymEngine + CONFIG QUIET + HINTS ${SYMENGINE_DIR} + PATH_SUFFIXES lib/cmake/symengine + NO_SYSTEM_ENVIRONMENT_PATH + ) + +# +# Reset the CMake module path +# +SET (CMAKE_MODULE_PATH ${DEAL_II_CMAKE_MODULE_PATH}) + + +# +# Look for symengine_config.h - we'll query it to determine supported features: +# +IF(SymEngine_FOUND) + DEAL_II_FIND_FILE(SYMENGINE_SETTINGS_H symengine_config.h + HINTS ${SYMENGINE_INCLUDE_DIRS} + PATH_SUFFIXES symengine + NO_DEFAULT_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_CMAKE_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH + ) +ENDIF() + +# +# Version check +# +IF(EXISTS ${SYMENGINE_SETTINGS_H}) + + FILE(STRINGS "${SYMENGINE_SETTINGS_H}" SYMENGINE_VERSION_MAJOR_STRING + REGEX "#define.*SYMENGINE_MAJOR_VERSION") + STRING(REGEX REPLACE "^.*SYMENGINE_MAJOR_VERSION.*([0-9]+).*" "\\1" + SYMENGINE_VERSION_MAJOR "${SYMENGINE_VERSION_MAJOR_STRING}" + ) + FILE(STRINGS "${SYMENGINE_SETTINGS_H}" SYMENGINE_VERSION_MINOR_STRING + REGEX "#define.*SYMENGINE_MINOR_VERSION") + STRING(REGEX REPLACE "^.*SYMENGINE_MINOR_VERSION.*([0-9]+).*" "\\1" + SYMENGINE_VERSION_MINOR "${SYMENGINE_VERSION_MINOR_STRING}" + ) + FILE(STRINGS "${SYMENGINE_SETTINGS_H}" SYMENGINE_VERSION_PATCH_STRING + REGEX "#define.*SYMENGINE_PATCH_VERSION") + STRING(REGEX REPLACE "^.*SYMENGINE_PATCH_VERSION.*([0-9]+).*" "\\1" + SYMENGINE_VERSION_PATCH "${SYMENGINE_VERSION_PATCH_STRING}" + ) + + SET(SYMENGINE_VERSION ${SymEngine_VERSION}) +ENDIF() + +# +# Feature checks +# + +MACRO(_symengine_feature_check _var _regex) + IF(EXISTS ${SYMENGINE_SETTINGS_H}) + FILE(STRINGS "${SYMENGINE_SETTINGS_H}" SYMENGINE_${_var}_STRING + REGEX "${_regex}") + IF("${SYMENGINE_${_var}_STRING}" STREQUAL "") + SET(SYMENGINE_WITH_${_var} FALSE) + ELSE() + SET(SYMENGINE_WITH_${_var} TRUE) + ENDIF() + ENDIF() +ENDMACRO() + +# Other possible features of interest: BOOST, GMP +_symengine_feature_check(LLVM "#define.*HAVE_SYMENGINE_LLVM") + +# +# Sanitize include dirs: +# + +STRING(REGEX REPLACE + "(lib64|lib)\\/cmake\\/symengine\\/\\.\\.\\/\\.\\.\\/\\.\\.\\/" "" + _symengine_include_dirs "${SYMENGINE_INCLUDE_DIRS}" + ) +REMOVE_DUPLICATES(_symengine_include_dirs) + +# +# Get the full path for the SYMENGINE_LIBRARIES. Some of these libraries are +# CMake targets, so we can query them directly for this information. +# +FOREACH(SYMENGINE_LIBRARY_NAME ${SYMENGINE_LIBRARIES}) + IF (TARGET ${SYMENGINE_LIBRARY_NAME}) + GET_PROPERTY(SYMENGINE_LIBRARY TARGET ${SYMENGINE_LIBRARY_NAME} PROPERTY LOCATION) + ELSE () + SET(SYMENGINE_LIBRARY ${SYMENGINE_LIBRARY_NAME}) + ENDIF() + + SET(_symengine_libraries ${_symengine_libraries} ${SYMENGINE_LIBRARY}) +ENDFOREACH() + + +DEAL_II_PACKAGE_HANDLE(SYMENGINE + LIBRARIES REQUIRED _symengine_libraries + INCLUDE_DIRS REQUIRED _symengine_include_dirs + USER_INCLUDE_DIRS REQUIRED _symengine_include_dirs + CLEAR SYMENGINE_SETTINGS_H SYMENGINE_SKIP_DEPENDENCIES SymEngine_DIR +) diff --git a/cmake/setup_finalize.cmake b/cmake/setup_finalize.cmake index da1d0b9e77da..716093a7b3b5 100644 --- a/cmake/setup_finalize.cmake +++ b/cmake/setup_finalize.cmake @@ -84,12 +84,54 @@ ENDFOREACH() # FOREACH(build ${DEAL_II_BUILD_TYPES}) - CHECK_COMPILER_SETUP( - "${DEAL_II_CXX_FLAGS} ${DEAL_II_CXX_FLAGS_${build}}" - "${DEAL_II_LINKER_FLAGS} ${DEAL_II_LINKER_FLAGS_${build}}" - DEAL_II_HAVE_USABLE_FLAGS_${build} - ${DEAL_II_LIBRARIES} ${DEAL_II_LIBRARIES_${build}} - ) + + MACRO(_check_linker_flags) + CHECK_COMPILER_SETUP( + "${DEAL_II_CXX_FLAGS} ${DEAL_II_CXX_FLAGS_${build}}" + "${DEAL_II_LINKER_FLAGS} ${DEAL_II_LINKER_FLAGS_${build}}" + DEAL_II_HAVE_USABLE_FLAGS_${build} + ${DEAL_II_LIBRARIES} ${DEAL_II_LIBRARIES_${build}} + ) + ENDMACRO() + + MACRO(_drop_linker_flag _linker_flag _replacement_flag _variable) + MESSAGE(STATUS + "Unable to compile a simple test program. " + "Trying to drop \"${_linker_flag}\" from the linker flags." + ) + FOREACH(_flags + DEAL_II_LINKER_FLAGS DEAL_II_LINKER_FLAGS_${build} + BASE_LINKER_FLAGS BASE_LINKER_FLAGS_${build} + ) + STRING(REPLACE "${_linker_flag}" "${_replacement_flag}" + ${_flags} "${${_flags}}" + ) + ENDFOREACH() + SET(${_variable} FALSE CACHE INTERNAL "" FORCE) + SET(${_variable} FALSE) + ENDMACRO() + + _check_linker_flags() + + IF(NOT DEAL_II_HAVE_USABLE_FLAGS_${build} AND DEAL_II_COMPILER_HAS_FUSE_LD_LLD) + SET(_replacement "") + IF(DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) + SET(_replacement "-fuse-ld=gold") + ENDIF() + _drop_linker_flag( + "-fuse-ld=lld" ${_replacement} + DEAL_II_COMPILER_HAS_FUSE_LD_LLD + ) + _check_linker_flags() + ENDIF() + + IF(NOT DEAL_II_HAVE_USABLE_FLAGS_${build} AND DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) + _drop_linker_flag( + "-fuse-ld=gold" "" + DEAL_II_COMPILER_HAS_FUSE_LD_GOLD + ) + _check_linker_flags() + ENDIF() IF(NOT DEAL_II_HAVE_USABLE_FLAGS_${build}) MESSAGE(FATAL_ERROR " diff --git a/contrib/ci/Jenkinsfile.mark b/contrib/ci/Jenkinsfile.mark new file mode 100644 index 000000000000..78f8e02c676c --- /dev/null +++ b/contrib/ci/Jenkinsfile.mark @@ -0,0 +1,63 @@ +#!groovy + +/* + +This Jenkinsfile is used to mark jobs as "pending" as quickly as possible. The +other longer running jobs only set the status to pending once they start +running. + +See https://jenkins.tjhei.info/job/dealii-mark/ for details. + +*/ + +/* +Settings to apply inside Jenkins: + - discover pull requests (remove branches/master) + - Strategy: merged PR + - enable "Disable GitHub Multibranch Status Plugin" + - trigger build on pull request comment: .* /rebuild.* (without space) + - Jenkinsfile: choose contrib/ci/Jenkinsfile.mark + - scan: every 4 hours + - discard: 5+ items + - docker label: small +*/ + +pipeline +{ + agent + { + docker + { + image 'dealii/indent' + } + } + + post { cleanup { cleanWs() } } + + stages + { + stage("check") + { + steps + { + githubNotify context: 'ready', description: 'please be patient, testers are spinning up...', status: 'PENDING' + sh ''' + wget -q -O - https://api.github.com/repos/dealii/dealii/issues/${CHANGE_ID}/labels | grep 'ready to test' || \ + { echo "This commit will only be tested when it has the label 'ready to test'. Trigger a rebuild by adding a comment that contains '/rebuild'..."; exit 1; } + ''' + } + post + { + failure + { + githubNotify context: 'ready', description: 'need ready to test label and /rebuild', status: 'PENDING' + script + { + currentBuild.result='NOT_BUILT' + } + } + } + } + + } +} diff --git a/contrib/ci/Jenkinsfile.osx b/contrib/ci/Jenkinsfile.osx new file mode 100644 index 000000000000..5c0d92165ca2 --- /dev/null +++ b/contrib/ci/Jenkinsfile.osx @@ -0,0 +1,126 @@ +#!groovy + +/* + +This Jenkins job runs a build on OSX + +See https://jenkins.tjhei.info/job/dealii-osx/ for details. + +*/ + +/* +Settings to apply inside Jenkins: + - discover pull requests (remove branches/master) + - Strategy: merged PR + - enable "Disable GitHub Multibranch Status Plugin" + - trigger build on pull request comment: .* /rebuild.* (without space) + - Jenkinsfile: choose contrib/ci/Jenkinsfile.osx + - scan: every 4 hours + - discard: 5+ items +*/ + +// load library https://github.com/tjhei/jenkins-stuff to provide +// killold.killOldBuilds() function: +@Library('tjhei') _ + +pipeline +{ + agent none + + stages + { + stage("abort old") + { + agent none + steps + { + // kill older builds in this PR: + script { killold.killOldBuilds() } + } + } + + stage("main") + { + agent { + node { + label 'osx' + } + } + + post { cleanup { cleanWs() } } + + stages + { + stage("check") + { + when { + allOf { + not {branch 'master'} + } + } + + steps + { + githubNotify context: 'OSX', description: 'pending...', status: 'PENDING' + sh ''' + wget -q -O - https://api.github.com/repos/dealii/dealii/issues/${CHANGE_ID}/labels | grep 'ready to test' || \ + { echo "This commit will only be tested when it has the label 'ready to test'. Trigger a rebuild by adding a comment that contains '/rebuild'..."; exit 1; } + ''' + } + post + { + failure + { + githubNotify context: 'OSX', description: 'need ready to test label and /rebuild', status: 'PENDING' + script + { + currentBuild.result='NOT_BUILT' + } + } + } + } + + stage('build') + { + steps + { + timeout(time: 1, unit: 'HOURS') + { + sh "echo \"building on node ${env.NODE_NAME}\"" + sh '''#!/bin/bash + set -e + mkdir build && cd build + cmake \ + -D DEAL_II_WITH_MPI=OFF \ + -D DEAL_II_CXX_FLAGS='-Werror' \ + -D CMAKE_BUILD_TYPE=Debug \ + $WORKSPACE/ && make -j 4 + make test # quicktests + ''' + } + } + + post + { + always + { + archiveArtifacts artifacts: 'build/detailed.log', fingerprint: true + } + failure + { + githubNotify context: 'OSX', description: 'build failed', status: 'FAILURE' + } + } + } + + stage("finalize") + { + steps + { + githubNotify context: 'OSX', description: 'OK', status: 'SUCCESS' + } + } + } + } + } +} diff --git a/contrib/ci/Jenkinsfile.tidy b/contrib/ci/Jenkinsfile.tidy new file mode 100644 index 000000000000..6aa1179e43dd --- /dev/null +++ b/contrib/ci/Jenkinsfile.tidy @@ -0,0 +1,113 @@ +#!groovy + +/* + +This Jenkins job runs clang-tidy on the code base + +See https://jenkins.tjhei.info/job/dealii-tidy/ for details. + +*/ + +/* +Settings to apply inside Jenkins: + - discover pull requests (remove branches/master) + - Strategy: merged PR + - enable "Disable GitHub Multibranch Status Plugin" + - trigger build on pull request comment: .* /rebuild.* (without space!) + - Jenkinsfile: choose contrib/ci/Jenkinsfile.tidy + - scan: every 4 hours + - discard: 5+ items +*/ + +// load library https://github.com/tjhei/jenkins-stuff to provide +// killold.killOldBuilds() function: +@Library('tjhei') _ + +pipeline +{ + agent none + + stages + { + stage("abort old") + { + agent none + steps + { + githubNotify context: 'tidy', description: 'initializing...', status: 'PENDING' + // kill older builds in this PR: + script { killold.killOldBuilds() } + } + } + + stage("main") + { + agent + { + docker + { + image 'tjhei/candi-base-clang' + } + } + + post { cleanup { cleanWs() } } + + stages + { + stage("check") + { + when { + allOf { + not {branch 'master'} + } + } + + steps + { + githubNotify context: 'tidy', description: 'pending...', status: 'PENDING' + sh ''' + wget -q -O - https://api.github.com/repos/dealii/dealii/issues/${CHANGE_ID}/labels | grep 'ready to test' || \ + { echo "This commit will only be tested when it has the label 'ready to test'. Trigger a rebuild by adding a comment that contains '/rebuild'..."; exit 1; } + ''' + } + post + { + failure + { + githubNotify context: 'tidy', description: 'need ready to test label and /rebuild', status: 'PENDING' + script + { + currentBuild.result='NOT_BUILT' + } + } + } + } + + stage('build') + { + steps + { + timeout(time: 2, unit: 'HOURS') + { + sh "echo \"building on node ${env.NODE_NAME}\"" + sh '''#!/bin/bash + mkdir build && cd build + $WORKSPACE/contrib/utilities/run_clang_tidy.sh $WORKSPACE + ''' + githubNotify context: 'tidy', description: 'OK', status: 'SUCCESS' + } + } + + post + { + failure + { + githubNotify context: 'tidy', description: 'build failed', status: 'FAILURE' + } + } + } + + } + } + } +} diff --git a/contrib/utilities/dotgdbinit.py b/contrib/utilities/dotgdbinit.py index a4fb32598441..57d6ae956921 100644 --- a/contrib/utilities/dotgdbinit.py +++ b/contrib/utilities/dotgdbinit.py @@ -1,6 +1,6 @@ # --------------------------------------------------------------------- # -# Copyright (C) 2015 - 2017 by the deal.II authors +# Copyright (C) 2015 - 2018 by the deal.II authors # # This file is part of the deal.II library. # @@ -25,7 +25,7 @@ # slightly older versions of GDB (the Python interface was added in 7.0, # released in 2009). # -# Authors: Wolfgang Bangerth, 2015, David Wells, 2015 - 2017 +# Authors: Wolfgang Bangerth, 2015, David Wells, 2015 - 2018 # set print pretty 1 @@ -52,6 +52,31 @@ def build_output_string(keys, accessor): "\n}") +class AlignedVectorPrinter(object): + """Print a deal.II AlignedVector instance.""" + def __init__(self, typename, val): + self.typename = typename + self.val = val + self.length = int(self.val['data_end'] - self.val['data_begin']) + + def children(self): + # The first entry (see the "Pretty Printing API" documentation of GDB) + # in the tuple should be a name for the child, which should be nothing + # (the array elements don't have individual names) here. + return (("", (self.val['data_begin'] + count).dereference()) + for count in range(self.length)) + + def to_string(self): + return "AlignedVector<{}>({})".format(self.val.type.template_argument(0), + self.length) + + @staticmethod + def display_hint(): + """Provide a hint to GDB that this is an array-like container + (so print values in sequence).""" + return "array" + + class PointPrinter(object): """Print a deal.II Point instance.""" def __init__(self, typename, val): @@ -94,23 +119,17 @@ class VectorPrinter(object): def __init__(self, typename, val): self.typename = typename self.val = val + a_vec = self.val['values'] + self.length = int(a_vec['data_end'] - a_vec['data_begin']) def children(self): - # The first entry (see the "Pretty Printing API" documentation of GDB) - # in the tuple should be a name for the child, which should be nothing - # (an empty string) here. - return (("", (self.val['values'] + count).dereference()) - for count in range(int(self.val['vec_size']))) + return (("values", self.val['values']), + ("thread_loop_partitioner", + self.val['thread_loop_partitioner'])) def to_string(self): - return "{}[{}]".format(self.val.type.template_argument(0), - self.val['vec_size']) - - @staticmethod - def display_hint(): - """Provide a hint to GDB that this is an array-like container - (so print values in sequence).""" - return "array" + return "Vector<{}>({})".format(self.val.type.template_argument(0), + self.length) class QuadraturePrinter(object): @@ -184,6 +203,7 @@ def __call__(self, val): def register_dealii_printers(): """Register deal.II pretty-printers with gdb.""" printers = { + AlignedVectorPrinter: ['AlignedVector'], PointPrinter: ['Point'], TensorPrinter: ['Tensor'], VectorPrinter: ['Vector'], diff --git a/contrib/utilities/generate_lapack_templates b/contrib/utilities/generate_lapack_templates index af3e009e7e99..d86e466800a3 100755 --- a/contrib/utilities/generate_lapack_templates +++ b/contrib/utilities/generate_lapack_templates @@ -557,7 +557,7 @@ def main(): routines.append(FortranRoutine(file_name, guard_fp)) except NotImplementedError: # not a lot we can do. If its in the whitelist we will fail - # again later anway + # again later anyway continue routines.sort(key=lambda u: u.general_name) diff --git a/contrib/utilities/indent b/contrib/utilities/indent index ca889f7fcd36..9cb6892274d1 100755 --- a/contrib/utilities/indent +++ b/contrib/utilities/indent @@ -17,7 +17,7 @@ # # This script does the same thing as contrib/utilities/indent-all but only # reformats files which have changed (or have been added but neither -# staged/commited) since the last merge commit to the master branch. +# staged/committed) since the last merge commit to the master branch. # # The script needs to be executed as # ./contrib/utilities/indent diff --git a/contrib/utilities/indent.py b/contrib/utilities/indent.py index 0ca683d70891..82ba521487e7 100644 --- a/contrib/utilities/indent.py +++ b/contrib/utilities/indent.py @@ -112,7 +112,7 @@ def parse_arguments(): "By default only \"examples\", \"include\", " "\"source\" and \"tests\" " "directories are chosen to work on." - "Path to directories can be both abosulte or relative.") + "Path to directories can be both absolute or relative.") parser.add_argument("-j", metavar="THREAD_COUNT", type=int, default=0, help="Number of clang-format instances to be run " diff --git a/contrib/utilities/indent_common.sh b/contrib/utilities/indent_common.sh index 6bbeb92115ab..c8e4a26f9607 100644 --- a/contrib/utilities/indent_common.sh +++ b/contrib/utilities/indent_common.sh @@ -205,7 +205,7 @@ export -f fix_permissions # serves as a good candidate to separate individual file names. # - For 'xargs', -0 does the opposite: it separates filenames that are # delimited by \0 -# - the options "-n 1 -P 10" make sure that the following script with be +# - the options "-n 1 -P 10" make sure that the following script will be # called exactly with one file name as argument at a time, but we allow # execution for up to 10 times in parallel # diff --git a/contrib/utilities/run_clang_tidy.sh b/contrib/utilities/run_clang_tidy.sh index d292ef84a084..70dc612c6621 100755 --- a/contrib/utilities/run_clang_tidy.sh +++ b/contrib/utilities/run_clang_tidy.sh @@ -21,7 +21,7 @@ # Usage: # /contrib/utilities/run_clang_tidy.sh SRC_DIR OPTIONAL_CMAKE_ARGS # with: -# SRC_DIR is an absolute path to a deal.II source directory +# SRC_DIR points to a deal.II source directory # OPTIONAL_CMAKE_ARGS are optional arguments to pass to CMake # make sure to run this script in an empty build directory # @@ -29,8 +29,9 @@ # Clang 5.0.1+ and have clang, clang++, and run-clang-tidy.py in # your path. -# grab first argument: +# grab first argument and make relative path an absolute one: SRC=$1 +SRC=$(cd "$SRC";pwd) shift if test ! -d "$SRC/source" -o ! -d "$SRC/include" -o ! -d "$SRC/examples" -o ! -f "$SRC/CMakeLists.txt" ; then @@ -40,36 +41,32 @@ if test ! -d "$SRC/source" -o ! -d "$SRC/include" -o ! -d "$SRC/examples" -o ! - fi echo "SRC-DIR=$SRC" -# do not allow bundled packages, otherwise we get too many warnings from TBB/UMFPACK/etc. # enable MPI (to get MPI warnings) # export compile commands (so that run-clang-tidy.py works) -ARGS="-D DEAL_II_ALLOW_BUNDLED=OFF -D DEAL_II_WITH_MPI=ON -D CMAKE_EXPORT_COMPILE_COMMANDS=ON $@" +ARGS=("-D" "DEAL_II_WITH_MPI=ON" "-D" "CMAKE_EXPORT_COMPILE_COMMANDS=ON" "-D" "CMAKE_BUILD_TYPE=Debug" "$@") -# disable performance-inefficient-string-concatenation because we don't care about "a"+to_string(5)+... -CHECKS="-*, - cppcoreguidelines-pro-type-static-cast-downcast, - google-readability-casting, - modernize-*, - -modernize-pass-by-value, - -modernize-raw-string-literal, - -modernize-use-auto, - -modernize-use-override, - -modernize-use-default-member-init, - -modernize-use-transparent-functors, - mpi-*, - performance-*, - -performance-inefficient-string-concatenation" - -CHECKS="$(echo "${CHECKS}" | tr -d '[:space:]')" -echo "$CHECKS" +# for a list of checks, see /.clang-tidy +cat "$SRC/.clang-tidy" if ! [ -x "$(command -v run-clang-tidy.py)" ] || ! [ -x "$(command -v clang++)" ]; then echo "make sure clang, clang++, and run-clang-tidy.py (part of clang) are in the path" exit 2 fi -CC=clang CXX=clang++ cmake $ARGS "$SRC" || (echo "cmake failed!"; false) || exit 2 +CC=clang CXX=clang++ cmake "${ARGS[@]}" "$SRC" || (echo "cmake failed!"; false) || exit 2 cmake --build . --target expand_all_instantiations || (echo "make expand_all_instantiations failed!"; false) || exit 3 -run-clang-tidy.py -p . -checks="$CHECKS" -quiet -header-filter="$SRC/include/*" -fix +# finally run it: +# pipe away stderr (just contains nonsensical "x warnings generated") +# pipe output to output.txt +run-clang-tidy.py -p . -quiet -header-filter="$SRC/include/*" 2>error.txt >output.txt + +if grep -E -q '(warning|error): ' output.txt; then + grep -E '(warning|error): ' output.txt + exit 4 +fi + +echo "OK" +exit 0 + diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index ddfdd2977e34..97edbbb32c8d 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -32,20 +32,9 @@ IF(DEAL_II_COMPONENT_DOCUMENTATION) COMPONENT documentation PATTERN "CMakeLists.txt" EXCLUDE PATTERN "doxygen" EXCLUDE - PATTERN "*.in" EXCLUDE PATTERN "news" EXCLUDE ) - CONFIGURE_FILE( - ${CMAKE_CURRENT_SOURCE_DIR}/title.html.in - ${CMAKE_CURRENT_BINARY_DIR}/title.html - ) - INSTALL(FILES - ${CMAKE_CURRENT_BINARY_DIR}/title.html - DESTINATION ${DEAL_II_DOCHTML_RELDIR} - COMPONENT documentation - ) - MESSAGE(STATUS "Setting up documentation - Done") MESSAGE(STATUS "") diff --git a/doc/documentation.html b/doc/documentation.html deleted file mode 100644 index ee8bee879069..000000000000 --- a/doc/documentation.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - The deal.II Online Documentation - - - - - - - - -

-
- deal.II comes with extensive online - documentation that can be grouped into the following categories: -

- - - -
-
-
-
- - Valid HTML 4.01! - - Valid CSS! -
-
- - - diff --git a/doc/doxygen/headers/automatic_and_symbolic_differentiation.h b/doc/doxygen/headers/automatic_and_symbolic_differentiation.h index ae5178e2c8bc..77fc8f6234e3 100644 --- a/doc/doxygen/headers/automatic_and_symbolic_differentiation.h +++ b/doc/doxygen/headers/automatic_and_symbolic_differentiation.h @@ -14,13 +14,13 @@ // --------------------------------------------------------------------- /** - * @defgroup auto_symb_diff Automatic differentiation + * @defgroup auto_symb_diff Automatic and symbolic differentiation * * @brief A module dedicated to the implementation of functions and classes that relate - * to automatic differentiation. + * to automatic and symbolic differentiation. * - * Below we provide a very brief introduction as to what automatic differentiation is, - * what variations of this computational / numerical scheme exist, and how it is integrated + * Below we provide a very brief introduction as to what automatic and symbolic differentiation are, + * what variations of these computational / numerical schemes exist, and how they are integrated * within deal.II's framework. * * @section auto_diff_1 Automatic differentiation @@ -96,7 +96,7 @@ * that, with the appropriate implementation, both first and second derivatives can be computed exactly. * -# With taped approaches, a specified subregion of code is selected as one for which all * operations executed with active (marked) input variables are tracked and recorded in a data structure - * referred to as a tape. At the end of the taped region, the recorded function(s) may be revaluated + * referred to as a tape. At the end of the taped region, the recorded function(s) may be reevaluated * by "replaying" the tape with a different set of input variables instead of recomputing the function * directly. Assuming that the taped region represents a smooth function, arbitrarily high-order * derivatives of the function then can be computed by referring to the code path tracked and stored on @@ -232,7 +232,7 @@ * graph is required. * * In reverse-mode, the chain-rule is computed somewhat unnaturally from the "outside in". The - * values of the dependent variables first get computed and fixed, and then the preceeding + * values of the dependent variables first get computed and fixed, and then the preceding * differential operations are evaluated and multiplied in succession with the previous results * from left to right. Again, if we encapsulate and fix the order of operations using parentheses, * this implies that the reverse calculation is performed by @@ -450,9 +450,23 @@ * * @subsubsection auto_diff_1_3 User interface to the automatic differentiation libraries * - * As of the current release, there is no formal, unified interface to the automatic - * differentation libraries that we support. It is therefore necessary for users to - * manage the initialization and derivative computations themselves. + * The deal.II library offers a unified interface to the automatic differentiation libraries that + * we support. To date, the helper classes have been developed for the following contexts: + * + * - Classes designed to operate at the quadrature point level (or any general continuum point): + * - ScalarFunction: Differentiation of a scalar-valued function. One typical use would be the + * the development of constitutive laws directly from a strain energy function. + * - VectorFunction: Differentiation of a vector-valued function. This could be used to + * linearize the kinematic variables of a constitutive law, or assist in solving + * the evolution equations of local internal variables. + * - Classes designed to operate at the cell level: + * - EnergyFunctional: Differentiation of a scalar-valued energy functional, such as might arise + * from variational formulations. + * - ResidualLinearization: Differentiation of a vector-valued finite element residual, leading to + * its consistent linearization. + * + * Naturally, it is also possible for users to manage the initialization and derivative + * computations themselves. * * The most up-to-date examples of how this is done using ADOL-C can be found in * - their user manual, @@ -464,4 +478,10 @@ * - a code-gallery example, and * - our test-suite. * + * + * @section symb_diff_1 Symbolic differentiation + * + * TODO. As a temporary placeholder, here is a link to the Wikipedia article on + * symbolic differentiation and the + * SymPy library. */ diff --git a/doc/doxygen/headers/hp.h b/doc/doxygen/headers/hp.h index 5fceed9e248c..b9c69531681f 100644 --- a/doc/doxygen/headers/hp.h +++ b/doc/doxygen/headers/hp.h @@ -89,6 +89,21 @@ * collection of mappings is used, the same holds for hp::MappingCollection * objects as well. * + * Whenever p adaptivity is considered in an hp finite element program, + * a hierarchy of finite elements needs to be established to determine + * succeeding finite elements for refinement and preceding ones for coarsening. + * Typically, this hierarchy considers how finite element spaces are nested: + * for example, a $Q_1$ element describes a sub-space of a $Q_2$ element, + * and so doing $p$ refinement usually means using a larger (more accurate) + * finite element space. In other words, the hierarchy of finite elements is built + * by considering whether some elements of the collection are sub- or + * super-spaces of others. + * + * By default, we assume that finite elements are stored in an ascending order + * based on their polynomial degree. If the order of elements differs, + * a corresponding hierarchy needs to be supplied to the collection via the + * hp::FECollection::set_hierarchy() member function. + * * @ingroup hp */ diff --git a/doc/doxygen/headers/laoperators.h b/doc/doxygen/headers/laoperators.h index 64d8bfe40fad..49d2a122bda0 100644 --- a/doc/doxygen/headers/laoperators.h +++ b/doc/doxygen/headers/laoperators.h @@ -89,6 +89,9 @@ * encapsulation of individual linear operators into blocked linear * operator variants. * + * The step-20 tutorial program has a detailed usage example of the + * LinearOperator class. + * * @note As explained below, when using LinearOperator as res = op_a*x * a PackagedOperation class instance is generated behind-the-curtains. * Consequently, the user program has to include header files for both classes @@ -175,6 +178,9 @@ * Vector residual = b - op_a * x; // computes the residual at this point * @endcode * + * The step-20 tutorial program has a detailed usage example of the + * PackagedOperation class. + * * * @ingroup LAC * @ingroup MATRICES diff --git a/doc/doxygen/headers/manifold.h b/doc/doxygen/headers/manifold.h index 0eb3b05b48c5..84e04ef3795b 100644 --- a/doc/doxygen/headers/manifold.h +++ b/doc/doxygen/headers/manifold.h @@ -60,7 +60,7 @@ * in the Mapping class (see the @ref mapping module), which however obtains * its information about the boundary of the domain from the classes * described here. The same is, of course, true when integrating boundary - * terms (e.g., inhomogenous Neumann boundary conditions). + * terms (e.g., inhomogeneous Neumann boundary conditions). * *
  • Domains with nonzero codimension: In cases where a Triangulation is * embedded into a higher dimensional space, i.e., whenever the second diff --git a/doc/doxygen/images/dofinfo_get_dof_indices.png b/doc/doxygen/images/dofinfo_get_dof_indices.png new file mode 100644 index 000000000000..8366cacc6330 Binary files /dev/null and b/doc/doxygen/images/dofinfo_get_dof_indices.png differ diff --git a/doc/doxygen/options.dox.in b/doc/doxygen/options.dox.in index 14fd142f2385..133ed43761fe 100644 --- a/doc/doxygen/options.dox.in +++ b/doc/doxygen/options.dox.in @@ -199,6 +199,8 @@ PREDEFINED = DOXYGEN=1 \ DEAL_II_WITH_SCALAPACK=1 \ DEAL_II_WITH_SLEPC=1 \ DEAL_II_WITH_SUNDIALS=1 \ + DEAL_II_WITH_SYMENGINE=1 \ + DEAL_II_SYMENGINE_WITH_LLVM=1 \ DEAL_II_WITH_THREADS=1 \ DEAL_II_WITH_TRILINOS=1 \ DEAL_II_TRILINOS_WITH_ROL=1 \ @@ -213,6 +215,8 @@ PREDEFINED = DOXYGEN=1 \ DEAL_II_ALWAYS_INLINE= \ __device__= \ DEAL_II_P4EST_VERSION_GTE=1 \ + DEAL_II_SUNDIALS_VERSION_GTE=1 \ + DEAL_II_SUNDIALS_VERSION_LT=0 \ DEAL_II_TRILINOS_VERSION_GTE=1 # do not expand exception declarations diff --git a/doc/external-libs/cuda.html b/doc/external-libs/cuda.html index 8ba33ae33a88..345865b6a903 100644 --- a/doc/external-libs/cuda.html +++ b/doc/external-libs/cuda.html @@ -39,8 +39,8 @@

    Installing deal.II with CUDA

    If you are using CUDA 9 or CUDA 10, you will need to turn off support for C++17 similarly. - By default, we assume that your GPU has compute capability 3.5 but you - can easily set your own CUDA flags: + By default, we try to detect the compute capability of your device + but you can easily set your own CUDA flags:
     
             -DDEAL_II_CUDA_FLAGS="-arch=sm_60"
    diff --git a/doc/external-libs/ginkgo.html b/doc/external-libs/ginkgo.html
    new file mode 100644
    index 000000000000..d918e17f7357
    --- /dev/null
    +++ b/doc/external-libs/ginkgo.html
    @@ -0,0 +1,96 @@
    +
    +
    +  
    +    The deal.II Readme on interfacing to Ginkgo
    +    
    +    
    +    
    +  
    +
    +  
    +
    +    

    Interfacing deal.II to Ginkgo

    + +

    + Ginkgo is + A numerical linear algebra software package that provides its users with + highly optimized fine grid level linear algebra operations. It currently has + the capability to solve on the CPU with the support of OpenMP and on the GPU + with NVIDIA's CUDA libraries. For some operations it uses NVIDIA's own libraries, CuSparse + and CuBLAS, but some routines also have self implemented CUDA functions.See the Ginkgo documentation + for more details. +

    + +

    + deal.II has wrapper classes to the linear algebra + parts of Ginkgo that provide almost the + same interfaces as the built-in deal.II linear algebra operations. +

    + +

    Installing deal.II with Ginkgo

    + +

    + During the CMake configuration, the following flags should be specified: +

      +
    • -DDEAL_II_WITH_GINKGO=ON, to enable the Ginkgo library. +
    • -DGINKGO_DIR=, to specify the path where Ginkgo has been installed. +
    +

    + +

    Installing Ginkgo

    + +

    + Installing Ginkgo is quite simple. Ginkgo currently uses CMake and hence one can use + the following commands to easily install Ginkgo. For different dependencies and compatible + libraries, please refer to Ginkgo. + The different flags that can be added are: +

      +
    • -DBUILD_REFERENCE={ON,OFF}: Builds the reference single thread implementation + used to check the more sophisticated implementations of the GPU/CPU. +
    • -DBUILD_CUDA={ON,OFF}: Builds the GPU implementation, specifically the NVIDIA + CUDA implementations. This needs CUDA to be installed on the machine. +
    • -DBUILD_OMP={ON,OFF}: Builds the multithreaded OpenMP implementations. +
    + To install Ginkgo, you would need to: +
    +	git clone https://github.com/ginkgo-project/ginkgo.git
    +  mkdir build; cd build 
    +  cmake -DBUILD_REFERENCE=on/off -DBUILD_CUDA=on/off -DBUILD_OMP=on/off -DCMAKE_INSTALL_PREFIX=/path/to/install/ -DCMAKE_BUILD_TYPE=Debug
    +	make install
    +      
    +

    + +

    Running the Ginkgo tests

    + +

    + Ginkgo uses gtests to run unit tests. The reference implementations are + non-optimized versions to which the OpenMP and CUDA versions are compared with for + correctness. + + The following command, executed in Ginkgo's build directory, launches its test suite. +

    +	make test
    +      
    + The output should contain several lines of the form: +
    +     Start  1: path/to/test
    + 1/13 Test  #1: path/to/test .............................   Passed    0.01 sec
    +      
    + To run only a specific test for more details, from the build directory, run +
    +	./path/to/test
    +      
    +

    + +
    +
    + + Valid HTML 4.01! + + Valid CSS! +
    + + diff --git a/doc/external-libs/petsc.html b/doc/external-libs/petsc.html index 68a2ac02dbd4..c665079d1764 100644 --- a/doc/external-libs/petsc.html +++ b/doc/external-libs/petsc.html @@ -37,7 +37,7 @@

    Installing deal.II with PETSc

    Note: The most recent version of PETSc that has been reported to be compatible with - deal.II is version 3.9.0. If you use a later + deal.II is version 3.11.0. If you use a later version than this and encounter problems, let us know. deal.II does not support versions of PETSc prior to 3.3.0. diff --git a/doc/external-libs/trilinos.html b/doc/external-libs/trilinos.html index 9579c9a62a0a..09e13e35a04e 100644 --- a/doc/external-libs/trilinos.html +++ b/doc/external-libs/trilinos.html @@ -67,6 +67,7 @@

    Installing Trilinos
  • ROL (optional),
  • Sacado (optional),
  • Teuchos, +
  • Tpetra (optional),
  • Zoltan (optional). @@ -92,6 +93,9 @@
    Installing Trilinos
    -DTrilinos_ENABLE_MueLu=ON \ -DTrilinos_ENABLE_ML=ON \ -DTrilinos_ENABLE_ROL=ON \ + -DTrilinos_ENABLE_Tpetra=ON \ + -DTpetra_INST_COMPLEX_DOUBLE=ON \ + -DTpetra_INST_COMPLEX_FLOAT=ON \ -DTrilinos_ENABLE_Zoltan=ON \ -DTrilinos_VERBOSE_CONFIGURE=OFF \ -DTPL_ENABLE_MPI=ON \ diff --git a/doc/index.html b/doc/index.html index 98b547352979..b720f2cbd532 100644 --- a/doc/index.html +++ b/doc/index.html @@ -18,19 +18,83 @@ - - - - - - - - <h1>The deal.II Documentation Page</h1> - Your browser does not seem to understand frames. A version of this - page that does not use frames can be found at - <a href="documentation.html">documentation.html</a>. - - + +
    + +
    + +
    +

    + Information for developers +

    + +
    + +
    +

    + Further resources +

    + +
    +
    +
    + diff --git a/doc/navbar.html b/doc/navbar.html deleted file mode 100644 index 53fc21aa6c5c..000000000000 --- a/doc/navbar.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - deal.II navigation bar - - - - - - -

    - http://www.dealii.org
    -

    - -
    - -

    - Home
    - README
    -

    - -
    - - Doxygen and Lectures -

    - Tutorial Programs
    - Manual
    - Wolfgang's lectures
    -

    - -
    - - Online Resources -

    - FAQ
    - News
    - Download
    - Mailing list
    - Wiki
    - Bug tracker
    - Reports
    - Publications
    - Authors
    - License
    - Mailing lists -

    - - - diff --git a/doc/news/changes/header b/doc/news/changes/header index 14d7ac1993c7..1b580c8dd3bd 100644 --- a/doc/news/changes/header +++ b/doc/news/changes/header @@ -14,11 +14,11 @@ // --------------------------------------------------------------------- /** -@page changes_after_9_0_1 Changes after Version 9.0.1 +@page recent_changes Changes since the last release

    -This is the list of changes made after the release of deal.II version -9.0.1. All entries are signed with the names of the authors. +This is the list of changes made since the last release of deal.II. +All entries are signed with the names of the authors.

    diff --git a/doc/news/changes/incompatibilities/20190205Maier b/doc/news/changes/incompatibilities/20190205Maier new file mode 100644 index 000000000000..207868135824 --- /dev/null +++ b/doc/news/changes/incompatibilities/20190205Maier @@ -0,0 +1,5 @@ +Changed: The "debug" and "release" targets that are created by the +DEAL_II_INVOKE_AUTOPILOT() macro no longer automatically rebuild the +project. +
    +(Matthias Maier, 2019/02/05) diff --git a/doc/news/changes/incompatibilities/20190320DanielArndt b/doc/news/changes/incompatibilities/20190320DanielArndt new file mode 100644 index 000000000000..e4cc41414bb8 --- /dev/null +++ b/doc/news/changes/incompatibilities/20190320DanielArndt @@ -0,0 +1,4 @@ +Removed: The IndexSet instantiations for FEValues::get_function_values() +and DataOut_DoFData::add_data_vector() have been removed. +
    +(Daniel Arndt, 2019/03/20) diff --git a/doc/news/changes/major/20180524MatthiasMaierDanielArndt b/doc/news/changes/major/20180524MatthiasMaierDanielArndt index 3144a172b929..f76fada44e8e 100644 --- a/doc/news/changes/major/20180524MatthiasMaierDanielArndt +++ b/doc/news/changes/major/20180524MatthiasMaierDanielArndt @@ -1,3 +1,3 @@ Changed: clang-format replaces astyle as source code formatting tool.
    -(2018/05/24, Matthias Maier, Daniel Arndt) +(Matthias Maier, Daniel Arndt, 2018/05/24) diff --git a/doc/news/changes/major/20180531MatthiasMaier b/doc/news/changes/major/20180531MatthiasMaier index 32f6875ac019..05476ca921b8 100644 --- a/doc/news/changes/major/20180531MatthiasMaier +++ b/doc/news/changes/major/20180531MatthiasMaier @@ -4,4 +4,4 @@ storage type. This in particular enables the definition of complex-valued constraints (for example, complex-valued Dirichlet boundary conditions, or periodic boundary conditions with an additional phase shift).
    -(2018/05/31, Matthias Maier, Daniel Arndt, David Wells) +(Matthias Maier, Daniel Arndt, David Wells, 2018/05/31) diff --git a/doc/news/changes/major/20180709Harper b/doc/news/changes/major/20180709Harper index 43baeb009cb7..380ed6877c88 100644 --- a/doc/news/changes/major/20180709Harper +++ b/doc/news/changes/major/20180709Harper @@ -5,4 +5,4 @@ bubble functions. The original description is for simplicial meshes, but this im for quadrilateral and hexahedral meshes. The BR1-P0 pair is LBB stable for Stokes problems. Due to the edge-based bubble functions, features such as hanging nodes are not supported.
    -(Graham Harper 07/09/2018) +(Graham Harper, 07/09/2018) diff --git a/doc/news/changes/major/20180811DavidWells b/doc/news/changes/major/20180811DavidWells index 7a7ca6ed3d83..c6ec70b3af96 100644 --- a/doc/news/changes/major/20180811DavidWells +++ b/doc/news/changes/major/20180811DavidWells @@ -1,4 +1,4 @@ Improved: GridGenerator::extrude_triangulation can now optionally extrude manifold ids.
    -(2018/08/11, David Wells) +(David Wells, 2018/08/11) diff --git a/doc/news/changes/major/20180827Jean-PaulPelteret b/doc/news/changes/major/20180827Jean-PaulPelteret index d0476e4b3bee..6ff2bb4b710e 100644 --- a/doc/news/changes/major/20180827Jean-PaulPelteret +++ b/doc/news/changes/major/20180827Jean-PaulPelteret @@ -1,4 +1,4 @@ -New: A new class Differentiation::AD::ADHelperEnergyFunctional has been +New: A new class Differentiation::AD::EnergyFunctional has been added to help implement (incremental) variational formulations using automatic differentiation. In particular, this class is designed to compute the finite element residuals and their linearizations. diff --git a/doc/news/changes/major/20180930Jean-PaulPelteret b/doc/news/changes/major/20180930Jean-PaulPelteret index 1c5bf9ae1997..3fbe9844e182 100644 --- a/doc/news/changes/major/20180930Jean-PaulPelteret +++ b/doc/news/changes/major/20180930Jean-PaulPelteret @@ -1,4 +1,4 @@ -New: A new class Differentiation::AD::ADHelperResidualLinearization has been +New: A new class Differentiation::AD::ResidualLinearization has been added to help compute the linearization of a residual vector defined on the level of a cell (a finite element residual), or for local nonlinear equations.
    diff --git a/doc/news/changes/major/20190127Fehling b/doc/news/changes/major/20190127Fehling new file mode 100644 index 000000000000..74c4c55f9077 --- /dev/null +++ b/doc/news/changes/major/20190127Fehling @@ -0,0 +1,10 @@ +Changed: Class hp::DoFHandler now transfers the active_fe_index of each +cell automatically when refining/coarsening a Triangulation, +parallel::shared::Triangulation, or +parallel::distributed::Triangulation. However, serialization of a +parallel::distributed::Triangulation still requires a user to +explicitly call the functions +hp::DoFHandler::prepare_for_serialization_of_active_fe_indices() and +hp::DoFHandler::deserialize_active_fe_indices(). +
    +(Marc Fehling, 2019/01/27) diff --git a/doc/news/changes/major/20190130ginkgo-developers b/doc/news/changes/major/20190130ginkgo-developers new file mode 100644 index 000000000000..646f6b3d140d --- /dev/null +++ b/doc/news/changes/major/20190130ginkgo-developers @@ -0,0 +1,7 @@ +New: Support for Ginkgo, a high-performance numerical linear algebra library +has been added. Ginkgo provides advanced highly optimized linear solvers, +matrix formats and an abstraction to easily create linear operators on both +the cpu and the gpu. The deal.II's Ginkgo interface can currently be used to +solve linear systems using Krylov solvers with the cuda and OpenMP paradigms. +
    +(Ginkgo developers, 2019/01/30) diff --git a/doc/news/changes/major/20190208MatthiasMaier b/doc/news/changes/major/20190208MatthiasMaier new file mode 100644 index 000000000000..2131b88f999b --- /dev/null +++ b/doc/news/changes/major/20190208MatthiasMaier @@ -0,0 +1,4 @@ +Improved: The preconditioner and solver setup in step-20 has been rewritten +to highlight the new LinearOperator and PackagedOperation classes. +
    +(Matthias Maier, 2019/02/08) diff --git a/doc/news/changes/major/20190220Jean-PaulPelteret b/doc/news/changes/major/20190220Jean-PaulPelteret new file mode 100644 index 000000000000..3a0e37fe0de4 --- /dev/null +++ b/doc/news/changes/major/20190220Jean-PaulPelteret @@ -0,0 +1,9 @@ +New: A new class Differentiation::AD::ScalarFunction has been +added to help implement point-wise scalar functions using automatic +differentiation. In particular, this class is designed to compute the +gradient and Hessian of a scalar function that is parameterized in +terms of scalar, vector, and tensor arguments. One example of its use +would be to compute the derivatives of a multi-field constitutive law +that is expressed in terms of an energy function. +
    +(Jean-Paul Pelteret, 2019/02/20) diff --git a/doc/news/changes/major/20190321Jean-PaulPelteret b/doc/news/changes/major/20190321Jean-PaulPelteret new file mode 100644 index 000000000000..80e70e9e662a --- /dev/null +++ b/doc/news/changes/major/20190321Jean-PaulPelteret @@ -0,0 +1,9 @@ +New: A new class Differentiation::AD::VectorFunction has been +added to help implement point-wise vector functions using automatic +differentiation. In particular, this class is designed to compute the +Jacobian of a vector function that is parameterized in +terms of scalar, vector, and tensor arguments. One example of its use +would be to compute the linearization of a multi-field constitutive +law that is expressed in terms of some kinetic variables. +
    +(Jean-Paul Pelteret, 2019/03/21) diff --git a/doc/news/changes/major/20190329Jean-PaulPelteret b/doc/news/changes/major/20190329Jean-PaulPelteret new file mode 100644 index 000000000000..50d4c4b64022 --- /dev/null +++ b/doc/news/changes/major/20190329Jean-PaulPelteret @@ -0,0 +1,16 @@ +New: A new class Differentiation::SD::Expression has been added which allows +the creation and manipulation of scalar symbolic functions using the SymEngine +library. It will later be used as the basis of symbolic tensor calculus, amongst +other things. It incorporates numerous features, which currently include: +
      +
    • expression parsing,
    • +
    • comparison operations,
    • +
    • logical operations,
    • +
    • basic math operations,
    • +
    • conditional expression construction,
    • +
    • differentiation,
    • +
    • substitution (partial and complete), and
    • +
    • serialization.
    • +
    +
    +(Jean-Paul Pelteret, 2019/03/29) diff --git a/doc/news/changes/major/20190425RolandRichter b/doc/news/changes/major/20190425RolandRichter new file mode 100644 index 000000000000..4cc8d2e355ca --- /dev/null +++ b/doc/news/changes/major/20190425RolandRichter @@ -0,0 +1,5 @@ +New: The tutorial examples now all use a quadrature formula with a degree depending on the degree of the +finite element, so that one changing the finite element degree does not also require changing by hand the number +of quadrature points. +
    +(Roland Richter, 2019/04/25) diff --git a/doc/news/changes/major/20190502Wang b/doc/news/changes/major/20190502Wang new file mode 100644 index 000000000000..eb996123f5e6 --- /dev/null +++ b/doc/news/changes/major/20190502Wang @@ -0,0 +1,3 @@ +New: The new tutorial program step-61 shows how to use "weak Galerkin" finite element method to solve the Poisson equation. +
    +(Zhuoran Wang, 2019/05/02) diff --git a/doc/news/changes/minor/20180524MartinKronbichlerDenisDavydov b/doc/news/changes/minor/20180524MartinKronbichlerDenisDavydov index 7ceb99438d25..23b1c066746c 100644 --- a/doc/news/changes/minor/20180524MartinKronbichlerDenisDavydov +++ b/doc/news/changes/minor/20180524MartinKronbichlerDenisDavydov @@ -5,4 +5,4 @@ with many blocks, rather than splitting each method into two parts for overlapping communication and computation. The latter is inefficient as soon as too many MPI requests are in flight.
    -(Martin Kronbichler, Denis Davydov 2018/05/24) +(Martin Kronbichler, Denis Davydov, 2018/05/24) diff --git a/doc/news/changes/minor/20180529DenisDavydov b/doc/news/changes/minor/20180529DenisDavydov index c2a26fb7ec37..942cac916f41 100644 --- a/doc/news/changes/minor/20180529DenisDavydov +++ b/doc/news/changes/minor/20180529DenisDavydov @@ -1,3 +1,3 @@ Improved: TimerOutput now dynamically adjust to the the width of Section column.
    -(Denis Davydov 2018/05/29) +(Denis Davydov, 2018/05/29) diff --git a/doc/news/changes/minor/20180529DenisDavydov_b b/doc/news/changes/minor/20180529DenisDavydov_b index aed99f61361c..231c323f136a 100644 --- a/doc/news/changes/minor/20180529DenisDavydov_b +++ b/doc/news/changes/minor/20180529DenisDavydov_b @@ -1,4 +1,4 @@ New: TimerOutput::cpu_and_wall_times_grouped will print CPU and wallclock time in a single table.
    -(Denis Davydov 2018/05/29) +(Denis Davydov, 2018/05/29) diff --git a/doc/news/changes/minor/20180606SambitDas b/doc/news/changes/minor/20180606SambitDas index ac62bd989571..cc39f0cf671a 100644 --- a/doc/news/changes/minor/20180606SambitDas +++ b/doc/news/changes/minor/20180606SambitDas @@ -1,3 +1,3 @@ Improved: Extend ScaLAPACKMatrix::invert() to use pXtrtri for inversion of triangular matrices.
    -(Sambit Das 2018/06/06) +(Sambit Das, 2018/06/06) diff --git a/doc/news/changes/minor/20180611MatthiasMaier b/doc/news/changes/minor/20180611MatthiasMaier index 982f29806d83..1e0bf2ca2390 100644 --- a/doc/news/changes/minor/20180611MatthiasMaier +++ b/doc/news/changes/minor/20180611MatthiasMaier @@ -1,4 +1,4 @@ Fixed: CMake now supports again in-source builds (This functionality was accidentally broken in the previous release).
    -(Matthias Maier 2018/06/11) +(Matthias Maier, 2018/06/11) diff --git a/doc/news/changes/minor/20180612DenisDavydov b/doc/news/changes/minor/20180612DenisDavydov index e9adf8101555..cf260cba941a 100644 --- a/doc/news/changes/minor/20180612DenisDavydov +++ b/doc/news/changes/minor/20180612DenisDavydov @@ -2,4 +2,4 @@ Bugfix: Fixed a bug where VectorDataExchange::ghosts_were_set was not set inside MatrixFree::cell_loop() for block vectors with many blocks.
    -(Denis Davydov 2018/06/12) +(Denis Davydov, 2018/06/12) diff --git a/doc/news/changes/minor/20180614PiYuehChuang b/doc/news/changes/minor/20180614PiYuehChuang index 62dd7e40c2f3..44bda16aa164 100644 --- a/doc/news/changes/minor/20180614PiYuehChuang +++ b/doc/news/changes/minor/20180614PiYuehChuang @@ -1,4 +1,4 @@ Fixed: Mismatched numbers of components between the exact solution and underlying FE in Step-51.
    -(Pi-Yueh Chuang 2018/06/14) +(Pi-Yueh Chuang, 2018/06/14) diff --git a/doc/news/changes/minor/20180614UweKoecher b/doc/news/changes/minor/20180614UweKoecher index 3d855ebc2e56..e12782b921f8 100644 --- a/doc/news/changes/minor/20180614UweKoecher +++ b/doc/news/changes/minor/20180614UweKoecher @@ -2,4 +2,4 @@ Bugfix: Fixed bugs for TrilinosWrapper::SparseMatrix::add(factor, other_matrix) and TrilinosWrapper::SparseMatrix::copy_from(other_matrix) for the case of non-contiguous rows.
    -(Uwe Koecher 2018/06/14) +(Uwe Koecher, 2018/06/14) diff --git a/doc/news/changes/minor/20180621DenisDavydov b/doc/news/changes/minor/20180621DenisDavydov index e996dfe6922d..28e18a78c00b 100644 --- a/doc/news/changes/minor/20180621DenisDavydov +++ b/doc/news/changes/minor/20180621DenisDavydov @@ -2,4 +2,4 @@ New: Extend get_vector_data_ranges() to return extra element in the tuple to represent DataComponentInterpretation. The functions were renamed to get_nonscalar_data_ranges().
    -(Denis Davydov 2018/06/21) +(Denis Davydov, 2018/06/21) diff --git a/doc/news/changes/minor/20180621DenisDavydov_b b/doc/news/changes/minor/20180621DenisDavydov_b index cd9ef39ad6d6..8b52b7dc6975 100644 --- a/doc/news/changes/minor/20180621DenisDavydov_b +++ b/doc/news/changes/minor/20180621DenisDavydov_b @@ -1,3 +1,4 @@ New: Add support for output of tensor-valued data in DataOut::write_vtu(). -(Denis Davydov 2018/06/21) +
    +(Denis Davydov, 2018/06/21) diff --git a/doc/news/changes/minor/20180706DenisDavydov b/doc/news/changes/minor/20180706DenisDavydov index 0df86818f5e4..2a80d652b014 100644 --- a/doc/news/changes/minor/20180706DenisDavydov +++ b/doc/news/changes/minor/20180706DenisDavydov @@ -1,4 +1,4 @@ New: Add GridGenerator::plate_with_a_hole() that generates a rectangular plate with an (offset) cylindrical hole.
    -(Denis Davydov 2018/06/21) +(Denis Davydov, 2018/06/21) diff --git a/doc/news/changes/minor/20180723MarcFehling b/doc/news/changes/minor/20180723MarcFehling deleted file mode 100644 index fd54c397db88..000000000000 --- a/doc/news/changes/minor/20180723MarcFehling +++ /dev/null @@ -1,6 +0,0 @@ -New: Class parallel::distributed::ActiveFEIndicesTransfer -has been introduced to transfer the active_fe_index of each -cell across meshes in case of refinement/serialization, if a -hp::DoFHandler has been used with a parallel::distributed::Triangulation. -
    -(Marc Fehling, 2018/07/23) diff --git a/doc/news/changes/minor/20180726DenisDavydov b/doc/news/changes/minor/20180726DenisDavydov index e279c877e59e..f19d6b7d91e8 100644 --- a/doc/news/changes/minor/20180726DenisDavydov +++ b/doc/news/changes/minor/20180726DenisDavydov @@ -1,3 +1,3 @@ New: Add FiniteSizeHistory class to store a finite-size history of objects.
    -(Denis Davydov 2018/07/26) +(Denis Davydov, 2018/07/26) diff --git a/doc/news/changes/minor/20180802DenisDavydov b/doc/news/changes/minor/20180802DenisDavydov index 543dc6cd9775..c3b00e3a8331 100644 --- a/doc/news/changes/minor/20180802DenisDavydov +++ b/doc/news/changes/minor/20180802DenisDavydov @@ -1,4 +1,4 @@ Fixed: Minor issues when using matrix-free cell categorization with multi-grid operators.
    -(Denis Davydov 2018/08/02) +(Denis Davydov, 2018/08/02) diff --git a/doc/news/changes/minor/20180810BenjaminBrands b/doc/news/changes/minor/20180810BenjaminBrands index 963c26bb6a20..44d7d40ce9d3 100644 --- a/doc/news/changes/minor/20180810BenjaminBrands +++ b/doc/news/changes/minor/20180810BenjaminBrands @@ -1,3 +1,3 @@ Fixed: Bug using ScaLAPACKMatrix::save() and load() for configurations with pHDF5 in combination with serial HDF5 matrices from user code.
    -(Benjamin Brands 2018/08/10) +(Benjamin Brands, 2018/08/10) diff --git a/doc/news/changes/minor/20180813AlexanderKnieps b/doc/news/changes/minor/20180813AlexanderKnieps index 7a324b2f42bd..aada74e48131 100644 --- a/doc/news/changes/minor/20180813AlexanderKnieps +++ b/doc/news/changes/minor/20180813AlexanderKnieps @@ -1,3 +1,3 @@ Fixed: MGConstrainedDofs::initialize(...) now handles refinement edges across periodic boundaries correctly.
    -(Alexander Knieps 2018/08/13) +(Alexander Knieps, 2018/08/13) diff --git a/doc/news/changes/minor/20180821SvenjaSchoeder b/doc/news/changes/minor/20180821SvenjaSchoeder index f8a03c2cf6ff..1e91757b2e95 100644 --- a/doc/news/changes/minor/20180821SvenjaSchoeder +++ b/doc/news/changes/minor/20180821SvenjaSchoeder @@ -2,4 +2,5 @@ New: Add a mask argument to filter out some vector lanes in FEEvaluationBase This is required for local time stepping using the MatrixFree framework, because some cells of batches must be excluded from read/write operations when operating on different time steps compared to their neighbor cells. +
    (Svenja Schoeder, 2018/08/21) diff --git a/doc/news/changes/minor/20180913DenisDavydov b/doc/news/changes/minor/20180913DenisDavydov index 31324ece9746..3d6b6b3d4e97 100644 --- a/doc/news/changes/minor/20180913DenisDavydov +++ b/doc/news/changes/minor/20180913DenisDavydov @@ -1,3 +1,3 @@ New: Add line minimization functions.
    -(Denis Davydov 2018/09/13) +(Denis Davydov, 2018/09/13) diff --git a/doc/news/changes/minor/20180919DenisDavydov b/doc/news/changes/minor/20180919DenisDavydov index 2c7ed701efcb..3588933927df 100644 --- a/doc/news/changes/minor/20180919DenisDavydov +++ b/doc/news/changes/minor/20180919DenisDavydov @@ -1,4 +1,4 @@ New: extend Patterns::Tools::Convert to work with ComponentMask and std::unique_ptr.
    -(Denis Davydov 2018/09/19) +(Denis Davydov, 2018/09/19) diff --git a/doc/news/changes/minor/20180920DenisDavydov b/doc/news/changes/minor/20180920DenisDavydov index 38f78916f180..a1767d7433fd 100644 --- a/doc/news/changes/minor/20180920DenisDavydov +++ b/doc/news/changes/minor/20180920DenisDavydov @@ -1,4 +1,4 @@ New: Add optional flag to ParameterHandler to skip undefined sections and parameters.
    -(Denis Davydov 2018/09/20) +(Denis Davydov, 2018/09/20) diff --git a/doc/news/changes/minor/20181005DenisDavydov b/doc/news/changes/minor/20181005DenisDavydov index d8e1aa30c94a..10e6241a5662 100644 --- a/doc/news/changes/minor/20181005DenisDavydov +++ b/doc/news/changes/minor/20181005DenisDavydov @@ -1,4 +1,4 @@ New: Add inverse_Hilbert_space_filling_curve() to map points in dim-dimensional space to line index of the Hilbert space filling curve.
    -(Denis Davydov 2018/10/05) +(Denis Davydov, 2018/10/05) diff --git a/doc/news/changes/minor/20181006LucaHeltai b/doc/news/changes/minor/20181006LucaHeltai index ea8e3d0ec884..f1426feb81d8 100644 --- a/doc/news/changes/minor/20181006LucaHeltai +++ b/doc/news/changes/minor/20181006LucaHeltai @@ -1,4 +1,4 @@ -New: Added RTree class and pack_rtree() function to create a boost::gemoetry::index::rtree from +New: Added RTree class and pack_rtree() function to create a boost::geometry::index::rtree from containers and/or iterators of BoundingBox, Point, or Segment objects.
    (Luca Heltai, 2018/10/06) diff --git a/doc/news/changes/minor/20190401ArndtTurcksin b/doc/news/changes/minor/20190104ArndtTurcksin similarity index 100% rename from doc/news/changes/minor/20190401ArndtTurcksin rename to doc/news/changes/minor/20190104ArndtTurcksin diff --git a/doc/news/changes/minor/20190111GiovanniAlzetta b/doc/news/changes/minor/20190111GiovanniAlzetta new file mode 100644 index 000000000000..868aee927f14 --- /dev/null +++ b/doc/news/changes/minor/20190111GiovanniAlzetta @@ -0,0 +1,5 @@ +New: GridTools::Cache::get_covering_rtree() automatically stores and generates +a rtree of bounding boxes covering the whole triangulation. In a distributed setting +it can identify which processes have locally owned cells in any part of the mesh. +
    +(Giovanni Alzetta, 2019/01/11) diff --git a/doc/news/changes/minor/20191301VishalBoddu b/doc/news/changes/minor/20190113VishalBoddu similarity index 100% rename from doc/news/changes/minor/20191301VishalBoddu rename to doc/news/changes/minor/20190113VishalBoddu diff --git a/doc/news/changes/minor/20190130DenisDavydov b/doc/news/changes/minor/20190130DenisDavydov new file mode 100644 index 000000000000..4cf4ec962c56 --- /dev/null +++ b/doc/news/changes/minor/20190130DenisDavydov @@ -0,0 +1,4 @@ +New: Add internal::MatrixFreeFunctions::DoFInfo::get_dof_indices_on_cell_batch() to +return locally owned DoFs used by matrix-free framework on a given cell. +
    +(Denis Davydov, 2019/01/30) diff --git a/doc/news/changes/minor/20190130GiovanniAlzetta b/doc/news/changes/minor/20190130GiovanniAlzetta new file mode 100644 index 000000000000..a9b64415e3ee --- /dev/null +++ b/doc/news/changes/minor/20190130GiovanniAlzetta @@ -0,0 +1,5 @@ +Changed: Function GridGenerator::general_cell() can now generate +a cell of dimension `dim` inside a space of dimension `spacedim` +with `dim <= spacedim` +
    +(Giovanni Alzetta, 2019/01/30) diff --git a/doc/news/changes/minor/20190131GiovanniAlzettaDanielArndtWolfgangBangerth b/doc/news/changes/minor/20190131GiovanniAlzettaDanielArndtWolfgangBangerth new file mode 100644 index 000000000000..882d29c7cba7 --- /dev/null +++ b/doc/news/changes/minor/20190131GiovanniAlzettaDanielArndtWolfgangBangerth @@ -0,0 +1,4 @@ +New: added constructor to the class Point, which converts +a boost::geometry::model::point to a dealii::Point +
    +(Giovanni Alzetta, Daniel Arndt, Wolfgang Bangerth, 2019/01/31) diff --git a/doc/news/changes/minor/20190202Arndt b/doc/news/changes/minor/20190202Arndt new file mode 100644 index 000000000000..a3357d6bf42c --- /dev/null +++ b/doc/news/changes/minor/20190202Arndt @@ -0,0 +1,3 @@ +Documented: The minimal supported MPI version is MPI-2.0. +
    +(Daniel Arndt, 2019/02/02) diff --git a/doc/news/changes/minor/20190205MartinKronbichler b/doc/news/changes/minor/20190205MartinKronbichler new file mode 100644 index 000000000000..711b9588dfb0 --- /dev/null +++ b/doc/news/changes/minor/20190205MartinKronbichler @@ -0,0 +1,7 @@ +Fixed: MGLevelGlobalTransfer::copy_to_mg would initialize the level vectors +without ghosts. When combined with Chebyshev smoother and a DiagonalMatrix as +well as specific matrix-free loops, this could lead to ghosted vectors in +places where they were not supposed to be ghosted, leading to exceptions. This +is now fixed. +
    +(Martin Kronbichler, 2019/02/05) diff --git a/doc/news/changes/minor/20190206DenisDavydov b/doc/news/changes/minor/20190206DenisDavydov new file mode 100644 index 000000000000..73aa3ed586bd --- /dev/null +++ b/doc/news/changes/minor/20190206DenisDavydov @@ -0,0 +1,4 @@ +Improved: Use binary search in BlockIndices::global_to_local() to improve performance +for large number of blocks. +
    +(Denis Davydov, 2019/02/06) diff --git a/doc/news/changes/minor/20190206MartinKronbichler b/doc/news/changes/minor/20190206MartinKronbichler new file mode 100644 index 000000000000..ef651a9a6687 --- /dev/null +++ b/doc/news/changes/minor/20190206MartinKronbichler @@ -0,0 +1,9 @@ +Improved: The FEEvaluation::evaluate() and FEEvaluation::integrate() routines +would previously unconditionally use an evaluation routine with a +transformation to a collocation basis and subsequent collocation derivative +for `n_q_points_1d > fe_degree` because it is faster for the usual case of +`n_q_points_1d` close to the polynomial degree. Now, we switch back to the +standard evaluation if `n_q_points_1d > 3 * (fe_degree+1) / 2` where that +variant is faster. +
    +(Martin Kronbichler, 2019/02/06) diff --git a/doc/news/changes/minor/20190207MartinKronbichler b/doc/news/changes/minor/20190207MartinKronbichler new file mode 100644 index 000000000000..3785b7f5ab22 --- /dev/null +++ b/doc/news/changes/minor/20190207MartinKronbichler @@ -0,0 +1,5 @@ +Improved: The iteration of PreconditionChebyshev has been overhauled to reduce +the number of vectors written per iteration to one, leading to slightly faster +execution of the vector updates. +
    +(Martin Kronbichler, 2019/02/07) diff --git a/doc/news/changes/minor/20190208DenisDavydov b/doc/news/changes/minor/20190208DenisDavydov new file mode 100644 index 000000000000..3d8c7ce6cd5f --- /dev/null +++ b/doc/news/changes/minor/20190208DenisDavydov @@ -0,0 +1,3 @@ +New: Add default constructor to SparsityPatternIterators::Accessor(). +
    +(Denis Davydov, 2019/02/08) diff --git a/doc/news/changes/minor/20190208MartinKronbichler b/doc/news/changes/minor/20190208MartinKronbichler new file mode 100644 index 000000000000..3a12e97374da --- /dev/null +++ b/doc/news/changes/minor/20190208MartinKronbichler @@ -0,0 +1,8 @@ +Fixed: PreconditionChebyshev would previously run one iteration more than +requested, i.e., perform `degree+1` matrix-vector products rather than +`degree` which is the convention in literature. This is now fixed. Note that +the quality of PreconditionChebyshev is obviously slightly reduced by this +change, and some solvers might need more outer iterations due to a ligher +Chebyshev iteration. +
    +(Martin Kronbichler, 2019/02/08) diff --git a/doc/news/changes/minor/20190209Arndt b/doc/news/changes/minor/20190209Arndt new file mode 100644 index 000000000000..b781c4394355 --- /dev/null +++ b/doc/news/changes/minor/20190209Arndt @@ -0,0 +1,3 @@ +New: make_const_array_view() creates a constant view from a non-const object. +
    +(Daniel Arndt, 2019/02/09) diff --git a/doc/news/changes/minor/20190210MarcFehling b/doc/news/changes/minor/20190210MarcFehling new file mode 100644 index 000000000000..ab3127585a65 --- /dev/null +++ b/doc/news/changes/minor/20190210MarcFehling @@ -0,0 +1,6 @@ +New: Member functions DoFHandler::set_fe() and hp::DoFHandler::set_fe() +that will register a finite element object without enumerating all +degrees of freedom. In the hp case, the active_fe_indices will be +initialized and communicated amongst all processors, additionally. +
    +(Marc Fehling, 2019/02/10) diff --git a/doc/news/changes/minor/20190211ConradClevenger b/doc/news/changes/minor/20190211ConradClevenger new file mode 100644 index 000000000000..da07b583e6eb --- /dev/null +++ b/doc/news/changes/minor/20190211ConradClevenger @@ -0,0 +1,6 @@ +New: Function MGConstrainedDoFs::make_no_normal_flux_constraints which adds +functionality for no normal flux constraints during geometric mutigrid computations. +Currently, this function is limited to meshes with no normal flux boundaries +normal to the x-, y-, or z-axis. +
    +(Conrad Clevenger, 2019/02/11) diff --git a/doc/news/changes/minor/20190213MatthiasMaier b/doc/news/changes/minor/20190213MatthiasMaier new file mode 100644 index 000000000000..4307beeed445 --- /dev/null +++ b/doc/news/changes/minor/20190213MatthiasMaier @@ -0,0 +1,5 @@ +Fixed: inverse_operator() now handles a (composite) LinearOperator, the +temporary PreconditionIdentity(), or no argument as preconditioner argument +correctly. +
    +(Matthias Maier, 2019/02/13) diff --git a/doc/news/changes/minor/20190213SebastianStark b/doc/news/changes/minor/20190213SebastianStark new file mode 100644 index 000000000000..44710517f535 --- /dev/null +++ b/doc/news/changes/minor/20190213SebastianStark @@ -0,0 +1,3 @@ +Fixed: Handle the case properly that a local matrix with all diagonal elements equal to zero is distributed with AffineConstraints::distribute_local_to_global() to the global matrix while constraints apply. +
    +(Sebastian Stark, 2019/02/13) diff --git a/doc/news/changes/minor/20190219ConradClevenger b/doc/news/changes/minor/20190219ConradClevenger new file mode 100644 index 000000000000..aa560d10d9b8 --- /dev/null +++ b/doc/news/changes/minor/20190219ConradClevenger @@ -0,0 +1,4 @@ +New: Function DoFRenumbering::random(dof_handler, level) which allows for a random renumbering +of degrees of freedom on a level in a mutilevel hierarchy. +
    +(Conrad Clevenger, 2019/02/19) diff --git a/doc/news/changes/minor/20190221MartinKronbichler b/doc/news/changes/minor/20190221MartinKronbichler new file mode 100644 index 000000000000..e22a5b8f6b06 --- /dev/null +++ b/doc/news/changes/minor/20190221MartinKronbichler @@ -0,0 +1,6 @@ +Fixed: FEFaceEvaluation::evaluate() and FEFaceEvaluation::integrate() would +provide wrong results for faces in non-standard orientation layout, namely +with `orientation=true, face_flip={false,true}, face_rotation=true`. This is +now fixed. +
    +(Martin Kronbichler, 2019/02/21) diff --git a/doc/news/changes/minor/20190224MarcFehling b/doc/news/changes/minor/20190224MarcFehling new file mode 100644 index 000000000000..a1bf46b6ff45 --- /dev/null +++ b/doc/news/changes/minor/20190224MarcFehling @@ -0,0 +1,7 @@ +New: Introduced flags for p-refinement and p-coarsening that can be +accessed and changed via member functions of the DoFCellAccessor class, +namely DoFCellAccessor::p_refine_flag_set, DoFCellAccessor::set_p_refine_flag, +DoFCellAccessor::clear_p_refine_flag, and DoFCellAccessor::p_coarsen_flag_set, +DoFCellAccessor::set_p_coarsen_flag, DoFCellAccessor::clear_p_coarsen_flag. +
    +(Marc Fehling, 2019/02/24) diff --git a/doc/news/changes/minor/20190227DanielJodlbauer b/doc/news/changes/minor/20190227DanielJodlbauer new file mode 100644 index 000000000000..a7afb2bcaedd --- /dev/null +++ b/doc/news/changes/minor/20190227DanielJodlbauer @@ -0,0 +1,3 @@ +Fixed: Tensor-valued pvtu output. +
    +(Daniel Jodlbauer, 2019/02/27) diff --git a/doc/news/changes/minor/20190228Fehling b/doc/news/changes/minor/20190228Fehling new file mode 100644 index 000000000000..85c0089d88c7 --- /dev/null +++ b/doc/news/changes/minor/20190228Fehling @@ -0,0 +1,7 @@ +New: Hierarchy of finite elements in hp::FECollection objects. Get succeeding +and preceding indices via hp::FECollection::next_in_hierarchy() and +hp::FECollection::prev_in_hierarchy(). By default, a hierarchy corresponding +to indices is established. Hierarchy can be overridden via +hp::FECollection::set_hierarchy(). +
    +(Marc Fehling, 2019/02/28) diff --git a/doc/news/changes/minor/20190302ArndtStark b/doc/news/changes/minor/20190302ArndtStark new file mode 100644 index 000000000000..5b720d590c1b --- /dev/null +++ b/doc/news/changes/minor/20190302ArndtStark @@ -0,0 +1,4 @@ +Fixed: CellAccessor::material_id interfered with the manifold object +for refining the mesh in case its dimension was less than the space dimension. +
    +(Daniel Arndt, Sebastian Stark, 2019/03/02) diff --git a/doc/news/changes/minor/20190303Fehling b/doc/news/changes/minor/20190303Fehling new file mode 100644 index 000000000000..5bcb949a02ff --- /dev/null +++ b/doc/news/changes/minor/20190303Fehling @@ -0,0 +1,5 @@ +New: Signals Triangulation::pre_distributed_repartition and +Triangulation::post_distributed_repartition which will be triggered in +parallel::distributed::Triangulation::repartition(). +
    +(Marc Fehling, 2019/03/03) diff --git a/doc/news/changes/minor/20190304DavidWells b/doc/news/changes/minor/20190304DavidWells new file mode 100644 index 000000000000..b0cd08c43a68 --- /dev/null +++ b/doc/news/changes/minor/20190304DavidWells @@ -0,0 +1,5 @@ +Fixed: the DoFTools::make_sparsity_pattern variant that takes, as arguments, two +different DoFHandler objects now works correctly with +parallel::shared::Triangulation and parallel::distributed::Triangulation. +
    +(David Wells, 2019/03/04) diff --git a/doc/news/changes/minor/20190305DanielAppelMartinKronbichler-1 b/doc/news/changes/minor/20190305DanielAppelMartinKronbichler-1 new file mode 100644 index 000000000000..e9604fb6dccd --- /dev/null +++ b/doc/news/changes/minor/20190305DanielAppelMartinKronbichler-1 @@ -0,0 +1,5 @@ +Fixed: CylindricalManifold::get_new_point would previously return wrong +results if the resulting point is on the axis, and the cylinder axis does not +pass through the origin. +
    +(Daniel Appel, Martin Kronbichler, 2019/03/05) diff --git a/doc/news/changes/minor/20190305DanielAppelMartinKronbichler-2 b/doc/news/changes/minor/20190305DanielAppelMartinKronbichler-2 new file mode 100644 index 000000000000..2396b24c9e28 --- /dev/null +++ b/doc/news/changes/minor/20190305DanielAppelMartinKronbichler-2 @@ -0,0 +1,4 @@ +Fixed: EllipiticalManifold::push_forward_gradient did previously not take the +rotation into account. This is now fixed. +
    +(Daniel Appel, Martin Kronbichler, 2019/03/05) diff --git a/doc/news/changes/minor/20190306BrunoTurcksin b/doc/news/changes/minor/20190306BrunoTurcksin new file mode 100644 index 000000000000..5bbf2b57151d --- /dev/null +++ b/doc/news/changes/minor/20190306BrunoTurcksin @@ -0,0 +1,4 @@ +Fixed: LinearAlgebra::CUDAWrappers::Vector::add_and_dot was giving a wrong result +if the size of vector was greater than 4096. +
    +(Bruno Turcksin, 2018/03/06) diff --git a/doc/news/changes/minor/20190307LucaHeltai b/doc/news/changes/minor/20190307LucaHeltai new file mode 100644 index 000000000000..3dc9cf177e56 --- /dev/null +++ b/doc/news/changes/minor/20190307LucaHeltai @@ -0,0 +1,4 @@ +New: Added a new function Utilities::type_to_string() to demangle type names. +
    +(Luca Heltai, 2019/03/07) + diff --git a/doc/news/changes/minor/20190308MartinKronbichler b/doc/news/changes/minor/20190308MartinKronbichler new file mode 100644 index 000000000000..714316a34d7b --- /dev/null +++ b/doc/news/changes/minor/20190308MartinKronbichler @@ -0,0 +1,5 @@ +Fixed: DoFHandler::renumber_dofs() called on levels would previously run into +an assertion on distributed triangulation when used with continuous +elements. This is now fixed. +
    +(Martin Kronbichler, 2019/03/08) diff --git a/doc/news/changes/minor/20190310Jean-PaulPelteret-1 b/doc/news/changes/minor/20190310Jean-PaulPelteret-1 new file mode 100644 index 000000000000..6030de9655c3 --- /dev/null +++ b/doc/news/changes/minor/20190310Jean-PaulPelteret-1 @@ -0,0 +1,6 @@ +Changed: The TrilinosWrappers::PreconditionAMG::AdditionalData data structure +is now able to return a parameter list, which can be adjusted and fine-tuned by +the user and later used to initialize the AMG preconditioner. It can also +initialize the null space settings of an existing parameter list. +
    +(Jean-Paul Pelteret, 2019/03/10) diff --git a/doc/news/changes/minor/20190311TimoHeister b/doc/news/changes/minor/20190311TimoHeister new file mode 100644 index 000000000000..db6c9bdafb94 --- /dev/null +++ b/doc/news/changes/minor/20190311TimoHeister @@ -0,0 +1,3 @@ +New: If present, we will detect the LLD linker ld.lld at configuration time. +
    +(Timo Heister, 2019/03/11) diff --git a/doc/news/changes/minor/20190313LucaHeltai b/doc/news/changes/minor/20190313LucaHeltai new file mode 100644 index 000000000000..b3f47d11a631 --- /dev/null +++ b/doc/news/changes/minor/20190313LucaHeltai @@ -0,0 +1,6 @@ +New: Added two new classes to the MeshWorker namespace: MeshWorker::ScratchData and +MeshWorker::CopyData, that can be used as good default classes with the +WorkStream::run() and MeshWorker::mesh_loop() functions. +
    +(Luca Heltai, 2019/03/13) + diff --git a/doc/news/changes/minor/20190316Arndt b/doc/news/changes/minor/20190316Arndt new file mode 100644 index 000000000000..204e05b91457 --- /dev/null +++ b/doc/news/changes/minor/20190316Arndt @@ -0,0 +1,4 @@ +Improved: The apply_all_indicators_to_manifold flag in GridIn::read_ucd() +lets the indicators be used for cells as manifold id as well. +
    +(Daniel Arndt, 2019/03/16) diff --git a/doc/news/changes/minor/20190316DenisDavydov b/doc/news/changes/minor/20190316DenisDavydov new file mode 100644 index 000000000000..7d018538b7f6 --- /dev/null +++ b/doc/news/changes/minor/20190316DenisDavydov @@ -0,0 +1,3 @@ +Improved: DoFRenumbering::cell_wise() now support parallel::Triangulation . +
    +(Denis Davydov, 2019/03/16) diff --git a/doc/news/changes/minor/20190316SebastianStark b/doc/news/changes/minor/20190316SebastianStark new file mode 100644 index 000000000000..8ee817eb59c3 --- /dev/null +++ b/doc/news/changes/minor/20190316SebastianStark @@ -0,0 +1,3 @@ +New: interpolate_to_different_mesh works now with hp::DoFHandler objects +
    +(Sebastian Stark, 2019/03/16) diff --git a/doc/news/changes/minor/20190319DenisDavydov b/doc/news/changes/minor/20190319DenisDavydov new file mode 100644 index 000000000000..ab8f90eec88c --- /dev/null +++ b/doc/news/changes/minor/20190319DenisDavydov @@ -0,0 +1,4 @@ +New: Add Utilities::MPI::create_ascending_partitioning() to create a one-to-one +ascending partitioning from locally owned sizes. +
    +(Denis Davydov, 2019/03/19) diff --git a/doc/news/changes/minor/20190319DenisDavydov_b b/doc/news/changes/minor/20190319DenisDavydov_b new file mode 100644 index 000000000000..7f728e91ef8a --- /dev/null +++ b/doc/news/changes/minor/20190319DenisDavydov_b @@ -0,0 +1,3 @@ +New: Add SparsityTools::gather_sparsity_pattern(). +
    +(Denis Davydov, 2019/03/19) diff --git a/doc/news/changes/minor/20190319LucaHeltai b/doc/news/changes/minor/20190319LucaHeltai new file mode 100644 index 000000000000..5328898f6438 --- /dev/null +++ b/doc/news/changes/minor/20190319LucaHeltai @@ -0,0 +1,4 @@ +New: FEValuesExtractor classes now have a new method get_name() that returns a unique string identifier +for each extractor. +
    +(Luca Heltai, 2019/03/19) diff --git a/doc/news/changes/minor/20190319LucaHeltai_b b/doc/news/changes/minor/20190319LucaHeltai_b new file mode 100644 index 000000000000..c41dc6047793 --- /dev/null +++ b/doc/news/changes/minor/20190319LucaHeltai_b @@ -0,0 +1,5 @@ +New: The new method GridTools::assign_co_dimensional_manifold_indicators() propagate manifold ids from +cells to faces and edges, according to a disambiguation function that takes the set of manifold ids of +the cells that share the given face or edge. +
    +(Luca Heltai, 2019/03/19) diff --git a/doc/news/changes/minor/20190320DenisDavydov b/doc/news/changes/minor/20190320DenisDavydov new file mode 100644 index 000000000000..fa9905b7e403 --- /dev/null +++ b/doc/news/changes/minor/20190320DenisDavydov @@ -0,0 +1,4 @@ +New: Add DynamicSparsityPattern::nonempty_cols()/DynamicSparsityPattern::nonempty_rows() to return columns/rows +stored in the sparsity pattern. +
    +(Denis Davydov, 2019/03/20) diff --git a/doc/news/changes/minor/20190320LucaHeltai b/doc/news/changes/minor/20190320LucaHeltai new file mode 100644 index 000000000000..5d1cbf85cfb2 --- /dev/null +++ b/doc/news/changes/minor/20190320LucaHeltai @@ -0,0 +1,5 @@ +New: The type alias FEValuesViews::View now allows one to infer the correct FEValuesViews type +that would be returned by FEValuesBase::operator[]() when called with a specified extractor type from the +FEValuesExtractors namespace. +
    +(Luca Heltai, 2019/03/20) diff --git a/doc/news/changes/minor/20190323LucaHeltai b/doc/news/changes/minor/20190323LucaHeltai new file mode 100644 index 000000000000..d4b08ab3de45 --- /dev/null +++ b/doc/news/changes/minor/20190323LucaHeltai @@ -0,0 +1,4 @@ +New: Added a variant of MeshWorker::mesh_loop() that takes a class and its member functions as workers +and copiers. +
    +(Luca Heltai, 2019/03/23) diff --git a/doc/news/changes/minor/20190326Arndt b/doc/news/changes/minor/20190326Arndt new file mode 100644 index 000000000000..6d4bd85a7338 --- /dev/null +++ b/doc/news/changes/minor/20190326Arndt @@ -0,0 +1,5 @@ +Changed: parallel::distributed::SolutionTransfer::prepare_serialization() has +been deprecated in favor of +parallel::distributed::SolutionTransfer::prepare_for_serialization(). +
    +(Daniel Arndt, 2019/03/26) diff --git a/doc/news/changes/minor/20190328Bangerth b/doc/news/changes/minor/20190328Bangerth new file mode 100644 index 000000000000..e53f939f72eb --- /dev/null +++ b/doc/news/changes/minor/20190328Bangerth @@ -0,0 +1,5 @@ +New: The Vector class can now be initialized using an object of type +std::initializer_list. Such objects are, in particular, created when +the compiler sees a brace-enclosed list of numbers. +
    +(Wolfgang Bangerth, 2019/03/28) diff --git a/doc/news/changes/minor/20190330Jean-PaulPelteret b/doc/news/changes/minor/20190330Jean-PaulPelteret new file mode 100644 index 000000000000..22364ffafe06 --- /dev/null +++ b/doc/news/changes/minor/20190330Jean-PaulPelteret @@ -0,0 +1,4 @@ +New: The Differentiation::SD::Expression class can now be used to perform +symbolic math calculations. +
    +(Jean-Paul Pelteret, 2019/03/30) diff --git a/doc/news/changes/minor/20190402DenisDavydov b/doc/news/changes/minor/20190402DenisDavydov new file mode 100644 index 000000000000..a2d7537d6756 --- /dev/null +++ b/doc/news/changes/minor/20190402DenisDavydov @@ -0,0 +1,3 @@ +New: Add ArraView::ArrayView() and ArrayView::reinit(value_type *, const std::size_t). +
    +(Denis Davydov, 2019/04/02) diff --git a/doc/news/changes/minor/20190402LucaHeltaiJean-PaulPelteret b/doc/news/changes/minor/20190402LucaHeltaiJean-PaulPelteret new file mode 100644 index 000000000000..942968300abc --- /dev/null +++ b/doc/news/changes/minor/20190402LucaHeltaiJean-PaulPelteret @@ -0,0 +1,5 @@ +New: The GeneralDataStorage class facilitates the storage of any general data. +It offers the ability to store any amount of data, of any type, which is then +made accessible by an identifier string. +
    +(Luca Heltai, Jean-Paul Pelteret, 2019/04/02) diff --git a/doc/news/changes/minor/20190408Arndt b/doc/news/changes/minor/20190408Arndt new file mode 100644 index 000000000000..eaf8cc5e3f71 --- /dev/null +++ b/doc/news/changes/minor/20190408Arndt @@ -0,0 +1,4 @@ +Changed: SmartPointer and Subscriptor use a std::string +instead of a const char * as identifier. +
    +(Daniel Arndt, 2019/04/08) diff --git a/doc/news/changes/minor/20190411LucaHeltai b/doc/news/changes/minor/20190411LucaHeltai new file mode 100644 index 000000000000..ad5ad6c43737 --- /dev/null +++ b/doc/news/changes/minor/20190411LucaHeltai @@ -0,0 +1,4 @@ +New: The method Mapping::get_center() allows one to retrieve the cell center of a cell when the +mapping object does not preserve vertex locations. +
    +(Luca Heltai, 2019/04/11) diff --git a/doc/news/changes/minor/20190411LucaHeltai-b b/doc/news/changes/minor/20190411LucaHeltai-b new file mode 100644 index 000000000000..70e55832071a --- /dev/null +++ b/doc/news/changes/minor/20190411LucaHeltai-b @@ -0,0 +1,3 @@ +New: Added BoundingBox::extend() that allows extending and shrinking of BoundingBox objects. +
    +(Luca Heltai, 2019/04/11) diff --git a/doc/news/changes/minor/20190411LucaHeltai-c b/doc/news/changes/minor/20190411LucaHeltai-c new file mode 100644 index 000000000000..e8a86eb0ffb6 --- /dev/null +++ b/doc/news/changes/minor/20190411LucaHeltai-c @@ -0,0 +1,3 @@ +Fixed: Make sure that GridTools::Cache::get_cell_bounding_boxes_rtree() honors mappings. +
    +(Luca Heltai, 2019/04/11) diff --git a/doc/news/changes/minor/20190412LucaHeltai b/doc/news/changes/minor/20190412LucaHeltai new file mode 100644 index 000000000000..b2e28e48dcf8 --- /dev/null +++ b/doc/news/changes/minor/20190412LucaHeltai @@ -0,0 +1,4 @@ +New: The new FunctionFromFunctionObjects class allows one to wrap a vector of +std::function objects into a Function object, to allow fast prototyping of user codes. +
    +(Luca Heltai, 2019/04/12) diff --git a/doc/news/changes/minor/20190418LucaHeltai b/doc/news/changes/minor/20190418LucaHeltai new file mode 100644 index 000000000000..a0b5e6a83b34 --- /dev/null +++ b/doc/news/changes/minor/20190418LucaHeltai @@ -0,0 +1,3 @@ +New: Functions::CutOffFunctionBase now supports rescaling the function to keep its integral equal to one. +
    +(Luca Heltai, 2019/04/18) diff --git a/doc/news/changes/minor/20190422Jean-PaulPelteret b/doc/news/changes/minor/20190422Jean-PaulPelteret new file mode 100644 index 000000000000..228beb10fa08 --- /dev/null +++ b/doc/news/changes/minor/20190422Jean-PaulPelteret @@ -0,0 +1,5 @@ +New: Some utility functions that facilitate the creation of both scalar and +tensor symbolic variables and symbolic functions have been added to the +Differentiation::SD namespace. +
    +(Jean-Paul Pelteret, 2019/04/22) diff --git a/doc/news/changes/minor/20190423BrunoTurcksin b/doc/news/changes/minor/20190423BrunoTurcksin new file mode 100644 index 000000000000..3a3c21db1801 --- /dev/null +++ b/doc/news/changes/minor/20190423BrunoTurcksin @@ -0,0 +1,4 @@ +Changed: The chunk_size used in CUDA kernels has been reduced from 8 to 1 to +improve performance on newer architectures. +
    +(Bruno Turcksin, 2019/04/23) diff --git a/doc/news/changes/minor/20190423Jean-PaulPelteret b/doc/news/changes/minor/20190423Jean-PaulPelteret new file mode 100644 index 000000000000..5558b79d1e0a --- /dev/null +++ b/doc/news/changes/minor/20190423Jean-PaulPelteret @@ -0,0 +1,5 @@ +New: Some utility functions that perform symbolic differentiation of scalar +symbolic expressions, as well as tensorial expressions, have been added to the +Differentiation::SD namespace. +
    +(Jean-Paul Pelteret, 2019/04/23) diff --git a/doc/readme.html b/doc/readme.html index 2294bfbfa659..8daf1299d953 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -161,15 +161,19 @@

    Configuring and building the library

    deal.II uses the - CMake integrated configuration and build system. Unpacking will create a subdirectory deal.II/ in the current directory. Then do the following steps:

    + CMake integrated configuration and build system. Unpacking will create a subdirectory deal.II/ in the current directory. Then do the following steps to configure the build process:

       mkdir build
       cd build
       cmake -DCMAKE_INSTALL_PREFIX=/path/to/install/dir ../deal.II
    -  make install
    +    
    + We recommend compiling deal.II in parallel if your machine has more than one processor core. This can be done by providing the --jobs flag to make with a numerical argument. Here we compile with four make jobs: +
    +  make --jobs=4 install
       make test
         
    + One should usually use one job for each processor core on the machine.

    These steps compile, link, install the deal.II library, and run a few consistency checks. The whole process should take between a few minutes and an hour, depending on your machine. @@ -182,9 +186,7 @@

    Configuring and building the library

    Another option is to use something like `pwd`/../installed/ (note the backticks). Make sure the installation directory is not the same as the location where you unpacked deal.II/.
  • -
  • If your machine has multiple processors, use make - -jN install in the second to last step instead, where N is the number of simultaneous build processes you want make to use at any given time. Allowing make to use more simultaneous build processes (assuming you have that many processor - cores) will greatly lower the build time. make test automatically runs in parallel and no -jN flag should be supplied to it. +
  • make test automatically runs in parallel and no -jN flag should be supplied to it.
  • If you do not intend to modify the deal.II sources and recompile things, then you can remove the build/ directory after the last step. @@ -312,6 +314,7 @@

    Selecting optional library features

    MPI: To enable parallel computations beyond a single node using the Message Passing Interface (MPI), pass the -DDEAL_II_WITH_MPI=ON argument to cmake. If cmake found MPI but you specifically do not want to use it, then pass -DDEAL_II_WITH_MPI=OFF. + The minimal supported version is MPI-2.0.

  • @@ -423,6 +426,22 @@

    Optional interfaces to other software packages

    about compatibility and configuration can be found here.

    +
    + Ginkgo
    +
    +

    + Ginkgo + is a numerical linear algebra library with highly optimized kernels + for many core architectures with a focus on fine level parallelism. + It allows for easy switching of the executing paradigm (CUDA, OpenMP, etc.) + while providing a multitude of linear solvers and preconditioners + and extension to other linear operators with minimal changes required in the code. + To enable Ginkgo, pass -DGINKGO_DIR=/path/to/ginkgo to CMake when + configuring deal.II. For more detailed instructions, one can refer to + this page. +

    +
    +
    Gmsh
    @@ -587,6 +606,16 @@

    Optional interfaces to other software packages

    -DSUNDIALS_DIR=/path/to/sundials to the deal.II CMake call.

    + +
    + SymEngine
    +
    +

    + SymEngine is a symbolic manipulation package, implementing the building blocks of a computer algebra system (CAS) similar to SymPy. In particular, it can be used for symbolic differentiation. For using + SymEngine with deal.II, version 0.4 or newer is required. To use a self compiled version, pass + -DSYMENGINE_DIR=/path/to/symengine to the deal.II CMake call. +

    +
    Threading Building Blocks (TBB)
    diff --git a/doc/title.html.in b/doc/title.html.in deleted file mode 100644 index 7321caeda3d4..000000000000 --- a/doc/title.html.in +++ /dev/null @@ -1,17 +0,0 @@ - - - - deal.II Title Bar - - - - - -
    -

    deal.II @DEAL_II_PACKAGE_VERSION@ Documentation

    -
    - - - - diff --git a/examples/step-13/step-13.cc b/examples/step-13/step-13.cc index b37aac8107ab..71613bf13e1f 100644 --- a/examples/step-13/step-13.cc +++ b/examples/step-13/step-13.cc @@ -1221,7 +1221,7 @@ namespace Step13 this->triangulation->n_active_cells()); KellyErrorEstimator::estimate( this->dof_handler, - QGauss(3), + QGauss(this->fe->degree + 1), std::map *>(), this->solution, estimated_error_per_cell); diff --git a/examples/step-14/step-14.cc b/examples/step-14/step-14.cc index b79fef2d2f80..6e1c319a563c 100644 --- a/examples/step-14/step-14.cc +++ b/examples/step-14/step-14.cc @@ -878,7 +878,7 @@ namespace Step14 this->triangulation->n_active_cells()); KellyErrorEstimator::estimate( this->dof_handler, - QGauss(3), + QGauss(this->fe->degree + 1), std::map *>(), this->solution, estimated_error_per_cell); @@ -1530,7 +1530,7 @@ namespace Step14 // Initialize a FEValues object with a quadrature formula, // have abbreviations for the number of quadrature points and shape // functions... - QGauss quadrature(4); + QGauss quadrature(dof_handler.get_fe().degree + 1); FEValues fe_values(dof_handler.get_fe(), quadrature, update_gradients | update_quadrature_points | diff --git a/examples/step-15/doc/results.dox b/examples/step-15/doc/results.dox index 3fefe249fee6..9aa5f0c173e1 100644 --- a/examples/step-15/doc/results.dox +++ b/examples/step-15/doc/results.dox @@ -137,7 +137,7 @@ Wolfe and Armijo-Goldstein conditions. For these, one can show the following: satisfied, i.e., the iteration never gets stuck as long as the problem is convex. - If we are close enough to the solution, then the conditions allow for - $\alpha^n$, thereby enabling quadratic convergence. + $\alpha^n=1$, thereby enabling quadratic convergence. We will not dwell on this here any further but leave the implementation of such algorithms as an exercise. We note, however, that when implemented @@ -146,6 +146,9 @@ problems can be solved in anywhere between 5 and 15 Newton iterations to engineering accuracy — substantially fewer than we need with the current version of the program. +More details on globalization methods including backtracking can be found, +for example, in Griva, Nash, Sofer: Linear and nonlinear optimization (2009). +

    Integrating mesh refinement and nonlinear and linear solvers

    diff --git a/examples/step-15/step-15.cc b/examples/step-15/step-15.cc index 0e980c9e7efd..8f5c01b9ef90 100644 --- a/examples/step-15/step-15.cc +++ b/examples/step-15/step-15.cc @@ -234,7 +234,7 @@ namespace Step15 template void MinimalSurfaceProblem::assemble_system() { - const QGauss quadrature_formula(3); + const QGauss quadrature_formula(fe.degree + 1); system_matrix = 0; system_rhs = 0; @@ -376,7 +376,7 @@ namespace Step15 KellyErrorEstimator::estimate( dof_handler, - QGauss(3), + QGauss(fe.degree + 1), std::map *>(), present_solution, estimated_error_per_cell); @@ -504,7 +504,7 @@ namespace Step15 evaluation_point = present_solution; evaluation_point.add(alpha, newton_update); - const QGauss quadrature_formula(3); + const QGauss quadrature_formula(fe.degree + 1); FEValues fe_values(fe, quadrature_formula, update_gradients | update_quadrature_points | diff --git a/examples/step-16b/doc/results.dox b/examples/step-16b/doc/results.dox index 4f5baa31f477..cd4951e1daf2 100644 --- a/examples/step-16b/doc/results.dox +++ b/examples/step-16b/doc/results.dox @@ -15,38 +15,38 @@ DEAL:: Number of degrees of freedom: 25 (by level: 8, 25) DEAL:cg::Starting value 0.510691 DEAL:cg::Convergence step 6 value 4.59193e-14 DEAL::Cycle 1 -DEAL:: Number of active cells: 41 -DEAL:: Number of degrees of freedom: 52 (by level: 8, 25, 41) -DEAL:cg::Starting value 0.455356 -DEAL:cg::Convergence step 8 value 3.09682e-13 +DEAL:: Number of active cells: 44 +DEAL:: Number of degrees of freedom: 55 (by level: 8, 25, 45) +DEAL:cg::Starting value 0.440678 +DEAL:cg::Convergence step 8 value 1.99419e-13 DEAL::Cycle 2 -DEAL:: Number of active cells: 80 -DEAL:: Number of degrees of freedom: 100 (by level: 8, 25, 61, 52) -DEAL:cg::Starting value 0.394469 -DEAL:cg::Convergence step 9 value 1.96993e-13 +DEAL:: Number of active cells: 86 +DEAL:: Number of degrees of freedom: 105 (by level: 8, 25, 69, 49) +DEAL:cg::Starting value 0.371855 +DEAL:cg::Convergence step 9 value 1.13984e-13 DEAL::Cycle 3 -DEAL:: Number of active cells: 161 -DEAL:: Number of degrees of freedom: 190 (by level: 8, 25, 77, 160) -DEAL:cg::Starting value 0.322156 -DEAL:cg::Convergence step 9 value 2.94418e-13 +DEAL:: Number of active cells: 170 +DEAL:: Number of degrees of freedom: 200 (by level: 8, 25, 77, 174) +DEAL:cg::Starting value 0.318967 +DEAL:cg::Convergence step 9 value 2.62112e-13 DEAL::Cycle 4 -DEAL:: Number of active cells: 311 -DEAL:: Number of degrees of freedom: 364 (by level: 8, 25, 86, 227, 174) -DEAL:cg::Starting value 0.279667 -DEAL:cg::Convergence step 10 value 3.45746e-13 +DEAL:: Number of active cells: 332 +DEAL:: Number of degrees of freedom: 388 (by level: 8, 25, 86, 231, 204) +DEAL:cg::Starting value 0.276534 +DEAL:cg::Convergence step 10 value 1.69562e-13 DEAL::Cycle 5 -DEAL:: Number of active cells: 593 -DEAL:: Number of degrees of freedom: 667 (by level: 8, 25, 89, 231, 490, 96) -DEAL:cg::Starting value 0.215917 -DEAL:cg::Convergence step 10 value 1.03758e-13 +DEAL:: Number of active cells: 632 +DEAL:: Number of degrees of freedom: 714 (by level: 8, 25, 89, 231, 514, 141) +DEAL:cg::Starting value 0.215300 +DEAL:cg::Convergence step 10 value 6.47463e-13 DEAL::Cycle 6 -DEAL:: Number of active cells: 1127 -DEAL:: Number of degrees of freedom: 1251 (by level: 8, 25, 89, 274, 760, 417, 178) -DEAL:cg::Starting value 0.185906 -DEAL:cg::Convergence step 10 value 3.40351e-13 +DEAL:: Number of active cells: 1202 +DEAL:: Number of degrees of freedom: 1332 (by level: 8, 25, 89, 282, 771, 435, 257) +DEAL:cg::Starting value 0.175848 +DEAL:cg::Convergence step 10 value 1.80664e-13 DEAL::Cycle 7 -DEAL:: Number of active cells: 2144 -DEAL:: Number of degrees of freedom: 2359 (by level: 8, 25, 89, 308, 779, 1262, 817) -DEAL:cg::Starting value 0.141519 -DEAL:cg::Convergence step 10 value 5.74965e-13 +DEAL:: Number of active cells: 2288 +DEAL:: Number of degrees of freedom: 2511 (by level: 8, 25, 89, 318, 779, 1420, 829, 30) +DEAL:cg::Starting value 0.136724 +DEAL:cg::Convergence step 11 value 9.73331e-14
    diff --git a/examples/step-16b/step-16b.cc b/examples/step-16b/step-16b.cc index b35c6d4f558b..101a570c4678 100644 --- a/examples/step-16b/step-16b.cc +++ b/examples/step-16b/step-16b.cc @@ -561,7 +561,7 @@ namespace Step16 KellyErrorEstimator::estimate( dof_handler, - QGauss(3), + QGauss(fe.degree + 1), std::map *>(), solution, estimated_error_per_cell); diff --git a/examples/step-17/step-17.cc b/examples/step-17/step-17.cc index c837d09506be..14cd33023bd2 100644 --- a/examples/step-17/step-17.cc +++ b/examples/step-17/step-17.cc @@ -462,7 +462,7 @@ namespace Step17 template void ElasticProblem::assemble_system() { - QGauss quadrature_formula(2); + QGauss quadrature_formula(fe.degree + 1); FEValues fe_values(fe, quadrature_formula, update_values | update_gradients | @@ -765,7 +765,7 @@ namespace Step17 Vector local_error_per_cell(triangulation.n_active_cells()); KellyErrorEstimator::estimate( dof_handler, - QGauss(2), + QGauss(fe.degree + 1), std::map *>(), localized_solution, local_error_per_cell, diff --git a/examples/step-18/step-18.cc b/examples/step-18/step-18.cc index 5796801b572f..50feb3f2a778 100644 --- a/examples/step-18/step-18.cc +++ b/examples/step-18/step-18.cc @@ -716,7 +716,7 @@ namespace Step18 : triangulation(MPI_COMM_WORLD) , fe(FE_Q(1), dim) , dof_handler(triangulation) - , quadrature_formula(2) + , quadrature_formula(fe.degree + 1) , present_time(0.0) , present_timestep(1.0) , end_time(10.0) @@ -1441,7 +1441,7 @@ namespace Step18 Vector error_per_cell(triangulation.n_active_cells()); KellyErrorEstimator::estimate( dof_handler, - QGauss(2), + QGauss(fe.degree + 1), std::map *>(), incremental_displacement, error_per_cell, @@ -1608,40 +1608,33 @@ namespace Step18 template void TopLevel::setup_quadrature_point_history() { - // What we need to do here is to first count how many quadrature points - // are within the responsibility of this processor. This, of course, - // equals the number of cells that belong to this processor times the - // number of quadrature points our quadrature formula has on each cell. - // - // For good measure, we also set all user pointers of all cells, whether + // For good measure, we set all user pointers of all cells, whether // ours of not, to the null pointer. This way, if we ever access the user // pointer of a cell which we should not have accessed, a segmentation // fault will let us know that this should not have happened: - unsigned int our_cells = 0; - for (auto cell : triangulation.active_cell_iterators()) - if (cell->is_locally_owned()) - ++our_cells; triangulation.clear_user_data(); - // Next, allocate as many quadrature objects as we need. Since the - // resize function does not actually shrink the amount of - // allocated memory if the requested new size is smaller than the old - // size, we resort to a trick to first free all memory, and then - // reallocate it: we declare an empty vector as a temporary variable and - // then swap the contents of the old vector and this temporary - // variable. This makes sure that the - // quadrature_point_history is now really empty, and we can - // let the temporary variable that now holds the previous contents of the - // vector go out of scope and be destroyed. In the next step. we can then - // re-allocate as many elements as we need, with the vector - // default-initializing the PointHistory objects, which - // includes setting the stress variables to zero. + // Next, allocate the quadrature objects that are within the responsibility + // of this processor. This, of course, equals the number of cells that + // belong to this processor times the number of quadrature points our + // quadrature formula has on each cell. Since the `resize()` function does + // not actually shrink the amount of allocated memory if the requested new + // size is smaller than the old size, we resort to a trick to first free all + // memory, and then reallocate it: we declare an empty vector as a temporary + // variable and then swap the contents of the old vector and this temporary + // variable. This makes sure that the `quadrature_point_history` is now + // really empty, and we can let the temporary variable that now holds the + // previous contents of the vector go out of scope and be destroyed. In the + // next step we can then re-allocate as many elements as we need, with the + // vector default-initializing the `PointHistory` objects, which includes + // setting the stress variables to zero. { std::vector> tmp; - tmp.swap(quadrature_point_history); + quadrature_point_history.swap(tmp); } - quadrature_point_history.resize(our_cells * quadrature_formula.size()); + quadrature_point_history.resize( + triangulation.n_locally_owned_active_cells() * quadrature_formula.size()); // Finally loop over all cells again and set the user pointers from the // cells that belong to the present processor to point to the first @@ -1742,7 +1735,7 @@ namespace Step18 Assert(local_quadrature_points_history >= &quadrature_point_history.front(), ExcInternalError()); - Assert(local_quadrature_points_history < + Assert(local_quadrature_points_history <= &quadrature_point_history.back(), ExcInternalError()); diff --git a/examples/step-20/doc/intro.dox b/examples/step-20/doc/intro.dox index b9a7bde9cf4e..773141dfcc73 100644 --- a/examples/step-20/doc/intro.dox +++ b/examples/step-20/doc/intro.dox @@ -249,7 +249,7 @@ program we do that in the following way: for (unsigned int i=0; i phi_j_u = fe_values[velocities].value (j, q); - const double div_phi_j_u = fe_values[velocities].divergence (j, q); - const double phi_j_p = fe_values[pressure].value (j, q); + const Tensor<1,dim> phi_j_u = fe_values[velocities].value (j, q); + const double div_phi_j_u = fe_values[velocities].divergence (j, q); + const double phi_j_p = fe_values[pressure].value (j, q); local_matrix(i,j) += (phi_i_u * k_inverse_values[q] * phi_j_u - div_phi_i_u * phi_j_p @@ -333,23 +333,23 @@ the same way as above, i.e. the extractor classes also work on FEFaceValues obje @code for (unsigned int face_no=0; - face_no::faces_per_cell; - ++face_no) - if (cell->at_boundary(face_no)) - { - fe_face_values.reinit (cell, face_no); - - pressure_boundary_values - .value_list (fe_face_values.get_quadrature_points(), - boundary_values); - - for (unsigned int q=0; q::faces_per_cell; + ++face_no) + if (cell->at_boundary(face_no)) + { + fe_face_values.reinit (cell, face_no); + + pressure_boundary_values + .value_list (fe_face_values.get_quadrature_points(), + boundary_values); + + for (unsigned int q=0; qblocks that correspond to the individual operators that appear in -the system. We note that the resulting solver is not optimal -- there are much -better ways, for example those explained in the results section of step-22 or -the one we use in step-43 for a problem rather similar to the current one -- -but that the goal is to introduce techniques rather than optimal solvers. +the system. We note that the resulting solver is not optimal -- there are +much better ways to efficiently compute the system, for example those +explained in the results section of step-22 or the one we use in step-43 +for a problem similar to the current one. Here, our goal shall be to +introduce new solution techniques and how they can be implemented in +deal.II.

    Solving using the Schur complement

    @@ -439,115 +441,173 @@ matrix-vector products. @note The key point in this consideration is to recognize that to implement an iterative solver such as CG or GMRES, we never actually need the actual elements of a matrix! All that is required is that we can form -matrix-vector products. The same is true for preconditioners. In deal.II -we encode this requirement by only requiring that matrices and preconditioners -given to solver classes have a vmult() member function that does -the matrix-vector product. How a class chooses to implement this function is -not important to the solver. Consequently, classes can implement it by, -for example, doing a sequence of products and linear solves as discussed -above. - -Using this strategy, we can then implement a class that provides the -function vmult() that is all that the SolverCG class -requires from an object representing a matrix. We can make our life a -bit easier by also introducing an object that represents $M^{-1}$ and -that has its own vmult() function that, if called, solves -the linear system with $M$. Using this (which we will implement as the -InverseMatrix class in the body of the program), the class -that implements the Schur only needs to offer the vmult() -function to perform a matrix-vector multiplication, using the algorithm -above. Here are again the relevant parts of the code: +matrix-vector products. The same is true for preconditioners. In deal.II we +encode this requirement by only requiring that matrices and preconditioners +given to solver classes have a vmult() member function that +does the matrix-vector product. How a class chooses to implement this +function is not important to the solver. Consequently, classes can +implement it by, for example, doing a sequence of products and linear +solves as discussed above. + + +

    The LinearOperator framework in deal.II

    + +deal.II includes support for describing such linear operations in a very +general way. This is done with the LinearOperator class that, like +@ref ConceptMatrixType "the MatrixType concept", +defines a minimal interface for applying a linear operation to a +vector: +@code + std::function vmult; + std::function vmult_add; + std::function Tvmult; + std::function Tvmult_add; +@endcode +The key difference between a LinearOperator and an ordinary matrix is +however that a LinearOperator does not allow any further access to the +underlying object. All you can do with a LinearOperator is to apply its +"action" to a vector! We take the opportunity to introduce the +LinearOperator concept at this point because it is a very useful tool that +allows you to construct complex solvers and preconditioners in a very +intuitive manner. + +As a first example let us construct a LinearOperator object that represents +$M^{-1}$. This means that whenever the vmult() function of +this operator is called it has to solve a linear system. This requires us +to specify a solver (and corresponding) preconditioner. Assuming that +M is a reference to the upper left block of the system matrix +we can write: +@code + const auto op_M = linear_operator(M); + + PreconditionJacobi<> preconditioner_M; + preconditioner_M.initialize(M); + + ReductionControl reduction_control_M(2000, 1.0e-18, 1.0e-10); + SolverCG<> solver_M(reduction_control_M); + const auto op_M_inv = inverse_operator(op_M, solver_M, preconditioner_M); +@endcode +Rather than using a SolverControl we use the ReductionControl class here +that stops iterations when either an absolute tolerance is reached (for +which we choose $10^{-18}$) or when the residual is reduced by a certain +factor (here, $10^{-10}$). In contrast the SolverControl class only checks +for absolute tolerances. We have to use ReductionControl in our case to +work around a minor issue: The right hand sides that we will feed to +op_M_inv are essentially formed by residuals that naturally +decrease vastly in norm as the outer iterations progress. This makes +control by an absolute tolerance very error prone. + +We now have a LinearOperator op_M_inv that we can use to +construct more complicated operators such as the Schur complement $S$. +Assuming that B is a reference to the upper right block +constructing a LinearOperator op_S is a matter of two lines: +@code + const auto op_B = linear_operator(B); + const auto op_S = transpose_operator(op_B) * op_M_inv * op_B; +@endcode +Here, the multiplication of three LinearOperator objects yields a composite +object op_S whose vmult() function first applies +$B$, then $M^{-1}$ (i.e. solving an equation with $M$), and finally $B^T$ +to any given input vector. In that sense op_S.vmult() is +similar to the following code: @code -class SchurComplement : public Subscriptor + B.vmult (tmp1, src); // multiply with the top right block: B + solver_M(M, tmp2, tmp1, preconditioner_M); // multiply with M^-1 + B.Tvmult (dst, tmp2); // multiply with the bottom left block: B^T +@endcode +(tmp1 and tmp2 are two temporary vectors). The +key point behind this approach is the fact that we never actually create an +inner product of matrices. Instead, whenever we have to perform a matrix +vector multiplication with op_S we simply run all individual +vmult operations in above sequence. + +@note We could have achieved the same goal of creating a "matrix like" +object by implementing a specialized class SchurComplement +that provides a suitable vmult() function. Skipping over some +details this might have looked like the following: +@code +class SchurComplement { public: - SchurComplement (const BlockSparseMatrix &A, - const InverseMatrix > &inverse_mass); - - void vmult (Vector &dst, - const Vector &src) const; - private: - const SmartPointer > system_matrix; - const SmartPointer > > inverse_mass; + // ... - mutable Vector tmp1, tmp2; + void SchurComplement::vmult (Vector &dst, + const Vector &src) const + { + B.vmult (tmp1, src); + solver_M(M, tmp2, tmp1, preconditioner_M); + B.Tvmult (dst, tmp2); + } }; - - -void SchurComplement::vmult (Vector &dst, - const Vector &src) const -{ - system_matrix->block(0,1).vmult (tmp1, src); // multiply with the top right block: B - inverse_mass->vmult (tmp2, tmp1); // multiply with M^-1 - system_matrix->block(1,0).vmult (dst, tmp2); // multiply with the bottom left block: B^T -} @endcode +Even though both approaches are exactly equivalent, the LinearOperator +class has a big advantage over this manual approach. +It provides so-called +syntactic sugar: +Mathematically, we think about $S$ as being the composite matrix +$S=B^TM^{-1}B$ and the LinearOperator class allows you to write this out +more or less verbatim, +@code +const auto op_M_inv = inverse_operator(op_M, solver_M, preconditioner_M); +const auto op_S = transpose_operator(op_B) * op_M_inv * op_B; +@endcode +The manual approach on the other hand obscures this fact. -In this code, the constructor takes a reference to a block sparse matrix for -the entire system, and a reference to the object representing the inverse of -the mass matrix. It stores these using SmartPointer objects (see -step-7), and additionally allocates two temporary vectors tmp1 and -tmp2 for the vectors labeled $w,y$ in the list above. - -In the matrix-vector multiplication function, the product $Sv$ is performed in -exactly the order outlined above. Note how we access the blocks $B$ and $B^T$ -by calling system_matrix->block(0,1) and -system_matrix->block(1,0) respectively, thereby picking out -individual blocks of the block system. Multiplication by $M^{-1}$ happens -using the object introduced above. - -With all this, we can go ahead and write down the solver we are going to -use. Essentially, all we need to do is form the right hand sides of the two -equations defining $P$ and $U$, and then solve them with the Schur complement -matrix and the mass matrix, respectively: - +All that is left for us to do now is to form the right hand sides of the +two equations defining $P$ and $U$, and then solve them with the Schur +complement matrix and the mass matrix, respectively. For example the right +hand side of the first equation reads $B^TM^{-1}F-G$. This could be +implemented as follows: @code -template -void MixedLaplaceProblem::solve () -{ - InverseMatrix > inverse_mass (system_matrix.block(0,0)); - Vector tmp (solution.block(0).size()); + Vector schur_rhs (P.size()); + Vector tmp (U.size()); + op_M_inv.vmult (tmp, F); + transpose_operator(op_B).vmult (schur_rhs, tmp); + schur_rhs -= G; +@endcode +Again, this is a perfectly valid approach, but the fact that deal.II +requires us to manually resize the final and temporary vector, and that +every operation takes up a new line makes this hard to read. This is the +point where a second class in the linear operator framework can will help +us. Similarly in spirit to LinearOperator, a PackagedOperation stores a +"computation": +@code + std::function apply; + std::function apply_add; +@endcode +The class allows +lazy evaluation +of expressions involving vectors and linear operators. This is done by +storing the computational expression and only performing the computation +when either the object is converted to a vector object, or +PackagedOperation::apply() (or PackagedOperation::apply_add()) is invoked +by hand. Assuming that F and G are the two +vectors of the right hand side we can simply write: +@code + const auto schur_rhs = transpose_operator(op_B) * op_M_inv * F - G; +@endcode +Here, schur_rhs is a PackagedOperation that records the +computation we specified. It does not create a vector with the actual +result immediately. - { - SchurComplement schur_complement (system_matrix, inverse_mass); - Vector schur_rhs (solution.block(1).size()); - inverse_mass.vmult (tmp, system_rhs.block(0)); - system_matrix.block(1,0).vmult (schur_rhs, tmp); - schur_rhs -= system_rhs.block(1); - - SolverControl solver_control (solution.block(1).size(), - 1e-12*schur_rhs.l2_norm()); - SolverCG<> cg (solver_control); - - PreconditionIdentity preconditioner; - cg.solve (schur_complement, solution.block(1), schur_rhs, - preconditioner); - } +With these prerequisites at hand, solving for $P$ and $U$ is a matter of +creating another solver and inverse: +@code + SolverControl solver_control_S(2000, 1.e-12); + SolverCG<> solver_S(solver_control_S); + PreconditionIdentity preconditioner_S; - { - system_matrix.block(0,1).vmult (tmp, solution.block(1)); - tmp *= -1; - tmp += system_rhs.block(0); + const auto op_S_inv = inverse_operator(op_S, solver_S, preconditioner_S); - inverse_mass.vmult (solution.block(0), tmp); - } -} + P = op_S_inv * schur_rhs; + U = op_M_inv * (F - op_B * P); @endcode -This code looks more impressive than it actually is. At the beginning, we -declare an object representing $M^{-1}$ and a temporary vector (of the size of -the first block of the solution, i.e. with as many entries as there are -velocity unknowns), and the two blocks surrounded by braces then solve the two -equations for $P$ and $U$, in this order. Most of the code in each of the two -blocks is actually devoted to constructing the proper right hand sides. For -the first equation, this would be $B^TM^{-1}F-G$, and $-BP+F$ for the second -one. The first hand side is then solved with the Schur complement matrix, and -the second simply multiplied with $M^{-1}$. The code as shown uses no -preconditioner (i.e. the identity matrix as preconditioner) for the Schur -complement. - +@note The functionality that we developed in this example step by hand is +already readily available in the library. Have a look at +schur_complement(), condense_schur_rhs(), and postprocess_schur_solution().

    A preconditioner for the Schur complement

    @@ -579,105 +639,57 @@ this looks almost as expensive as solving with $S$ right away. However, note that in the inner iteration, we do not have to calculate $M^{-1}$, but only the inverse of its diagonal, which is cheap. -The next step is to define a class that represents this approximate Schur -complement. This should look very much like the Schur complement class itself, -except that it doesn't need the object representing $M^{-1}$ any more -since we can compute the inverse of the diagonal of $M$ on the fly: - +Thankfully, the LinearOperator framework makes this very easy to write out. +We already used a Jacobi preconditioner (preconditioner_M) for +the $M$ matrix earlier. So all that is left to do is to write out how the +approximate Schur complement should look like: @code -class ApproximateSchurComplement : public Subscriptor -{ -public: - ApproximateSchurComplement (const BlockSparseMatrix &A); - - void vmult (Vector &dst, - const Vector &src) const; - -private: - const SmartPointer > system_matrix; - - mutable Vector tmp1, tmp2; -}; - - -void -ApproximateSchurComplement::vmult - (Vector &dst, - const Vector &src) const - { - system_matrix->block(0,1).vmult (tmp1, src); - system_matrix->block(0,0).precondition_Jacobi (tmp2, tmp1); - system_matrix->block(1,0).vmult (dst, tmp2); - } + const auto op_aS = + transpose_operator(op_B) * linear_operator(preconditioner_M) * op_B; @endcode - -Note how the vmult function differs in simply doing one Jacobi sweep +Note how this operator differs in simply doing one Jacobi sweep (i.e. multiplying with the inverses of the diagonal) instead of multiplying -with the full $M^{-1}$. (This is how a single Jacobi preconditioner -step with $M$ is defined: it is the multiplication with the inverse of -the diagonal of $M$; in other words, the operation $({\textrm{diag}\ -}M)^{-1}x$ on a vector $x$ is exactly what the function -SparseMatrix::precondition_Jacobi above does.) - -With all this, we nearly already have the preconditioner: it should be the -inverse of the approximate Schur complement. We implement this with -the InverseMatrix class: - +with the full $M^{-1}$. (This is how a single Jacobi preconditioner step +with $M$ is defined: it is the multiplication with the inverse of the +diagonal of $M$; in other words, the operation $({\textrm{diag}\ }M)^{-1}x$ +on a vector $x$ is exactly what PreconditionJacobi does.) + +With all this we almost have the preconditioner completed: it should be the +inverse of the approximate Schur complement. We implement this again by +creating a linear operator with inverse_operator() function. This time +however we would like to choose a relatively modest tolerance for the CG +solver (that inverts op_aS). The reasoning is that +op_aS is only coarse approximation to op_S, so we +actually do not need to invert it exactly. This, however creates a subtle +problem: preconditioner_S will be used in the final outer CG +iteration to create an orthogonal basis. But for this to work, it must be +precisely the same linear operation for every invocation. We ensure this by +using an IterationNumberControl that allows us to fix the number of CG +iterations that are performed to a fixed small number (in our case 30): @code - ApproximateSchurComplement approximate_schur (system_matrix); - InverseMatrix approximate_inverse - (approximate_schur); + IterationNumberControl iteration_number_control_aS(30, 1.e-18); + SolverCG<> solver_aS(iteration_number_control_aS); + PreconditionIdentity preconditioner_aS; + const auto preconditioner_S = + inverse_operator(op_aS, solver_aS, preconditioner_aS); @endcode That's all! -Taken together, the first block of our solve() function will then -look like this: - -@code - SchurComplement schur_complement (system_matrix, inverse_mass); - Vector schur_rhs (solution.block(1).size()); - inverse_mass.vmult (tmp, system_rhs.block(0)); - system_matrix.block(1,0).vmult (schur_rhs, tmp); - schur_rhs -= system_rhs.block(1); - - SolverControl solver_control (solution.block(1).size(), - 1e-12*schur_rhs.l2_norm()); - SolverCG<> cg (solver_control); - - ApproximateSchurComplement approximate_schur (system_matrix); - InverseMatrix approximate_inverse - (approximate_schur); - cg.solve (schur_complement, solution.block(1), schur_rhs, - approximate_inverse); -@endcode - -Note how we pass the so-defined preconditioner to the solver working on the -Schur complement matrix. - Obviously, applying this inverse of the approximate Schur complement is a very expensive preconditioner, almost as expensive as inverting the Schur complement itself. We can expect it to significantly reduce the number of outer iterations required for the Schur complement. In fact it does: in a -typical run on 5 times refined meshes using elements of order 0, the number of -outer iterations drops from 164 to 12. On the other hand, we now have to apply -a very expensive preconditioner 12 times. A better measure is therefore simply -the run-time of the program: on my laptop, it drops from 28 to 23 seconds for -this test case. That doesn't seem too impressive, but the savings become more -pronounced on finer meshes and with elements of higher order. For example, a -six times refined mesh and using elements of order 2 yields an improvement of -318 to 12 outer iterations, at a runtime of 338 seconds to 229 seconds. Not -earth shattering, but significant. - - -

    A remark on similar functionality in deal.II

    - -As a final remark about solvers and preconditioners, let us note that a -significant amount of functionality introduced above is actually also present -in the library itself. It probably even is more powerful and general, but we -chose to introduce this material here anyway to demonstrate how to work with -block matrices and to develop solvers and preconditioners, rather than using -black box components from the library. +typical run on 7 times refined meshes using elements of order 0, the number of +outer iterations drops from 592 to 39. On the other hand, we now have to apply +a very expensive preconditioner 25 times. A better measure is therefore simply +the run-time of the program: on a current laptop (as of January 2019), it +drops from 3.57 to 2.05 seconds for this test case. That doesn't seem too +impressive, but the savings become more pronounced on finer meshes and with +elements of higher order. For example, an seven times refined mesh and +using elements of order 2 (which amounts to about 0.4 million degrees of +freedom) yields an improvement of 1134 to 83 outer iterations, at a runtime +of 168 seconds to 40 seconds. Not earth shattering, but significant.

    Definition of the test case

    diff --git a/examples/step-20/doc/results.dox b/examples/step-20/doc/results.dox index 42dbf4517127..573fe46f9f09 100644 --- a/examples/step-20/doc/results.dox +++ b/examples/step-20/doc/results.dox @@ -3,33 +3,38 @@

    Output of the program and graphical visualization

    -If we run the program as is, we get this output for the $8\times 8$ -mesh we use (for a total of 64 cells with 64 pressure degrees of -freedom since we use piecewise constants, and 144 velocities because +If we run the program as is, we get this output for the $32\times 32$ +mesh we use (for a total of 1024 cells with 1024 pressure degrees of +freedom since we use piecewise constants, and 2112 velocities because the Raviart-Thomas element defines one degree per freedom per face and -there are 72 faces parallel to the $x$-axis and the same number -parallel to the $y$-axis): +there are $1024 + 32 = 1056$ faces parallel to the $x$-axis and the same +number parallel to the $y$-axis): @verbatim \$ make run [ 66%] Built target \step-20 Scanning dependencies of target run [100%] Run \step-20 with Release configuration -Number of active cells: 64 -Total number of cells: 85 -Number of degrees of freedom: 208 (144+64) -15 CG Schur complement iterations to obtain convergence. -Errors: ||e_p||_L2 = 0.178055, ||e_u||_L2 = 0.0433435 +Number of active cells: 1024 +Total number of cells: 1365 +Number of degrees of freedom: 3136 (2112+1024) +24 CG Schur complement iterations to obtain convergence. +Errors: ||e_p||_L2 = 0.0445032, ||e_u||_L2 = 0.010826 [100%] Built target run @endverbatim -The fact that the number of iterations is so small, of course, is due to good -(but expensive!) preconditioner we have developed. To get confidence in the -solution, let us take a look at it. The following three images show (from left -to right) the x-velocity, the y-velocity, and the pressure: +The fact that the number of iterations is so small, of course, is due to +the good (but expensive!) preconditioner we have developed. To get +confidence in the solution, let us take a look at it. The following three +images show (from left to right) the x-velocity, the y-velocity, and the +pressure: - - - + + + + + + +
    diff --git a/examples/step-20/step-20.cc b/examples/step-20/step-20.cc index 8710392acae2..89ed11124b16 100644 --- a/examples/step-20/step-20.cc +++ b/examples/step-20/step-20.cc @@ -1,6 +1,6 @@ /* --------------------------------------------------------------------- * - * Copyright (C) 2005 - 2018 by the deal.II authors + * Copyright (C) 2005 - 2019 by the deal.II authors * * This file is part of the deal.II library. * @@ -12,9 +12,6 @@ * the top level directory of deal.II. * * --------------------------------------------------------------------- - - * - * Author: Wolfgang Bangerth, Texas A&M University, 2005, 2006 */ @@ -27,12 +24,18 @@ #include #include #include + #include #include #include #include #include +// The only two new header files that deserve some attention are those for +// the LinearOperator and PackagedOperation classes: +#include +#include + #include #include #include @@ -320,7 +323,7 @@ namespace Step20 void MixedLaplaceProblem::make_grid_and_dofs() { GridGenerator::hyper_cube(triangulation, -1, 1); - triangulation.refine_global(3); + triangulation.refine_global(5); dof_handler.distribute_dofs(fe); @@ -559,206 +562,83 @@ namespace Step20 // @sect3{Linear solvers and preconditioners} - // The linear solvers and preconditioners we use in this example have been - // discussed in significant detail already in the introduction. We will - // therefore not discuss the rationale for these classes here any more, but - // rather only comment on implementational aspects. - - // @sect4{The InverseMatrix class template} - - // There are a few places in this program where we will need either the - // action of the inverse of the mass matrix or the action of the inverse of - // the approximate Schur complement. Rather than explicitly calling - // SolverCG::solve every time that we need to solve such a system, we will - // wrap the action of either inverse in a simple class. The only things we - // would like to note are that this class is derived from - // Subscriptor and, as mentioned above, it stores a pointer to - // the underlying matrix with a SmartPointer object. This class - // also appears in step-21 and a more advanced version of it appears in - // step-22. - template - class InverseMatrix : public Subscriptor - { - public: - InverseMatrix(const MatrixType &m); - - void vmult(Vector &dst, const Vector &src) const; - - private: - const SmartPointer matrix; - }; - - - template - InverseMatrix::InverseMatrix(const MatrixType &m) - : matrix(&m) - {} - - - template - void InverseMatrix::vmult(Vector & dst, - const Vector &src) const - { - // To make the control flow simpler, we recreate both the ReductionControl - // and SolverCG objects every time this is called. This is not the most - // efficient choice because SolverCG instances allocate memory whenever - // they are created; this is just a tutorial so such inefficiencies are - // acceptable for the sake of exposition. - SolverControl solver_control(std::max(src.size(), 200), - 1e-8 * src.l2_norm()); - SolverCG<> cg(solver_control); - - dst = 0; - - cg.solve(*matrix, dst, src, PreconditionIdentity()); - } - - - // @sect4{The SchurComplement class} - - // The next class is the Schur complement class. Its rationale has also been - // discussed in length in the introduction. Like InverseMatrix, - // this class is derived from Subscriptor and stores SmartPointer s - // pointing to the system matrix and InverseMatrix wrapper. - // - // The vmult function requires two temporary vectors that we do - // not want to re-allocate and free every time we call this function. Since - // here, we have full control over the use of these vectors (unlike above, - // where a class called by the vmult function required these - // vectors, not the vmult function itself), we allocate them - // directly, rather than going through the VectorMemory - // mechanism. However, again, these member variables do not carry any state - // between successive calls to the member functions of this class (i.e., we - // never care what values they were set to the last time a member function - // was called), we mark these vectors as mutable. - // - // The rest of the (short) implementation of this class is straightforward - // if you know the order of matrix-vector multiplications performed by the - // vmult function: - class SchurComplement : public Subscriptor - { - public: - SchurComplement(const BlockSparseMatrix & A, - const InverseMatrix> &Minv); - - void vmult(Vector &dst, const Vector &src) const; - - private: - const SmartPointer> system_matrix; - const SmartPointer>> m_inverse; - - mutable Vector tmp1, tmp2; - }; - - - SchurComplement ::SchurComplement( - const BlockSparseMatrix & A, - const InverseMatrix> &Minv) - : system_matrix(&A) - , m_inverse(&Minv) - , tmp1(A.block(0, 0).m()) - , tmp2(A.block(0, 0).m()) - {} + // The linear solvers and preconditioners we use in this example have + // been discussed in significant detail already in the introduction. We + // will therefore not discuss the rationale for our approach here any + // more, but rather only comment on some remaining implementational + // aspects. + // @sect4{MixedLaplace::solve} - void SchurComplement::vmult(Vector & dst, - const Vector &src) const + // As already outlined in the introduction, the solve function consists + // essentially of two steps. First, we have to form the first equation + // involving the Schur complement and solve for the pressure (component 1 + // of the solution). Then, we can reconstruct the velocities from the + // second equation (component 0 of the solution). + template + void MixedLaplaceProblem::solve() { - system_matrix->block(0, 1).vmult(tmp1, src); - m_inverse->vmult(tmp2, tmp1); - system_matrix->block(1, 0).vmult(dst, tmp2); - } + // As a first step we declare references to all block components of the + // matrix, the right hand side and the solution vector that we will + // need. + const auto &M = system_matrix.block(0, 0); + const auto &B = system_matrix.block(0, 1); + const auto &F = system_rhs.block(0); + const auto &G = system_rhs.block(1); - // @sect4{The ApproximateSchurComplement class} + auto &U = solution.block(0); + auto &P = solution.block(1); - // The third component of our solver and preconditioner system is the class - // that approximates the Schur complement with the method described in the - // introduction. We will use this class to build a preconditioner for our - // system matrix. - class ApproximateSchurComplement : public Subscriptor - { - public: - ApproximateSchurComplement(const BlockSparseMatrix &A); + // Then, we will create corresponding LinearOperator objects and create + // the op_M_inv operator: + const auto op_M = linear_operator(M); + const auto op_B = linear_operator(B); - void vmult(Vector &dst, const Vector &src) const; + ReductionControl reduction_control_M(2000, 1.0e-18, 1.0e-10); + SolverCG<> solver_M(reduction_control_M); + PreconditionJacobi<> preconditioner_M; - private: - const SmartPointer> system_matrix; + preconditioner_M.initialize(M); - mutable Vector tmp1, tmp2; - }; + const auto op_M_inv = inverse_operator(op_M, solver_M, preconditioner_M); + // This allows us to declare the Schur complement op_S and + // the approximate Schur complement op_aS: + const auto op_S = transpose_operator(op_B) * op_M_inv * op_B; + const auto op_aS = + transpose_operator(op_B) * linear_operator(preconditioner_M) * op_B; + // We now create a preconditioner out of op_aS that + // applies a fixed number of 30 (inexpensive) CG iterations: + IterationNumberControl iteration_number_control_aS(30, 1.e-18); + SolverCG<> solver_aS(iteration_number_control_aS); - ApproximateSchurComplement::ApproximateSchurComplement( - const BlockSparseMatrix &A) - : system_matrix(&A) - , tmp1(A.block(0, 0).m()) - , tmp2(A.block(0, 0).m()) - {} + const auto preconditioner_S = + inverse_operator(op_aS, solver_aS, PreconditionIdentity()); + // Now on to the first equation. The right hand side of it is + // $B^TM^{-1}F-G$, which is what we compute in the first few lines. We + // then solve the first equation with a CG solver and the + // preconditioner we just declared. + const auto schur_rhs = transpose_operator(op_B) * op_M_inv * F - G; - void ApproximateSchurComplement::vmult(Vector & dst, - const Vector &src) const - { - system_matrix->block(0, 1).vmult(tmp1, src); - system_matrix->block(0, 0).precondition_Jacobi(tmp2, tmp1); - system_matrix->block(1, 0).vmult(dst, tmp2); - } + SolverControl solver_control_S(2000, 1.e-12); + SolverCG<> solver_S(solver_control_S); - // @sect4{MixedLaplace::solve} + const auto op_S_inv = inverse_operator(op_S, solver_S, preconditioner_S); - // After all these preparations, we can finally write the function that - // actually solves the linear problem. We will go through the two parts it - // has that each solve one of the two equations, the first one for the - // pressure (component 1 of the solution), then the velocities (component 0 - // of the solution). - template - void MixedLaplaceProblem::solve() - { - InverseMatrix> inverse_mass(system_matrix.block(0, 0)); - Vector tmp(solution.block(0).size()); + P = op_S_inv * schur_rhs; - // Now on to the first equation. The right hand side of it is - // $B^TM^{-1}F-G$, which is what we compute in the first few lines: - { - SchurComplement schur_complement(system_matrix, inverse_mass); - Vector schur_rhs(solution.block(1).size()); - inverse_mass.vmult(tmp, system_rhs.block(0)); - system_matrix.block(1, 0).vmult(schur_rhs, tmp); - schur_rhs -= system_rhs.block(1); - - // Now that we have the right hand side we can go ahead and solve for the - // pressure, using our approximation of the inverse as a preconditioner: - SolverControl solver_control(solution.block(1).size(), - 1e-12 * schur_rhs.l2_norm()); - SolverCG<> cg(solver_control); - - ApproximateSchurComplement approximate_schur(system_matrix); - InverseMatrix approximate_inverse( - approximate_schur); - cg.solve(schur_complement, - solution.block(1), - schur_rhs, - approximate_inverse); - - std::cout << solver_control.last_step() - << " CG Schur complement iterations to obtain convergence." - << std::endl; - } + std::cout << solver_control_S.last_step() + << " CG Schur complement iterations to obtain convergence." + << std::endl; // After we have the pressure, we can compute the velocity. The equation // reads $MU=-BP+F$, and we solve it by first computing the right hand // side, and then multiplying it with the object that represents the // inverse of the mass matrix: - { - system_matrix.block(0, 1).vmult(tmp, solution.block(1)); - tmp *= -1; - tmp += system_rhs.block(0); - - inverse_mass.vmult(solution.block(0), tmp); - } + U = op_M_inv * (F - op_B * P); } diff --git a/examples/step-23/step-23.cc b/examples/step-23/step-23.cc index a120d0991fd6..5b814445501b 100644 --- a/examples/step-23/step-23.cc +++ b/examples/step-23/step-23.cc @@ -373,9 +373,11 @@ namespace Step23 matrix_u.reinit(sparsity_pattern); matrix_v.reinit(sparsity_pattern); - MatrixCreator::create_mass_matrix(dof_handler, QGauss(3), mass_matrix); + MatrixCreator::create_mass_matrix(dof_handler, + QGauss(fe.degree + 1), + mass_matrix); MatrixCreator::create_laplace_matrix(dof_handler, - QGauss(3), + QGauss(fe.degree + 1), laplace_matrix); // The rest of the function is spent on setting vector sizes to the @@ -478,12 +480,12 @@ namespace Step23 VectorTools::project(dof_handler, constraints, - QGauss(3), + QGauss(fe.degree + 1), InitialValuesU(), old_solution_u); VectorTools::project(dof_handler, constraints, - QGauss(3), + QGauss(fe.degree + 1), InitialValuesV(), old_solution_v); diff --git a/examples/step-24/step-24.cc b/examples/step-24/step-24.cc index 737d5cd55376..ed0622a618ad 100644 --- a/examples/step-24/step-24.cc +++ b/examples/step-24/step-24.cc @@ -289,9 +289,11 @@ namespace Step24 mass_matrix.reinit(sparsity_pattern); laplace_matrix.reinit(sparsity_pattern); - MatrixCreator::create_mass_matrix(dof_handler, QGauss(3), mass_matrix); + MatrixCreator::create_mass_matrix(dof_handler, + QGauss(fe.degree + 1), + mass_matrix); MatrixCreator::create_laplace_matrix(dof_handler, - QGauss(3), + QGauss(fe.degree + 1), laplace_matrix); // The second difference, as mentioned, to step-23 is that we need to @@ -336,7 +338,7 @@ namespace Step24 // do something only if that particular face is at the boundary of the // domain. Like this: { - const QGauss quadrature_formula(3); + const QGauss quadrature_formula(fe.degree + 1); FEFaceValues fe_values(fe, quadrature_formula, update_values | update_JxW_values); @@ -472,7 +474,7 @@ namespace Step24 VectorTools::project(dof_handler, constraints, - QGauss(3), + QGauss(fe.degree + 1), InitialValuesP(), old_solution_p); old_solution_v = 0; diff --git a/examples/step-25/step-25.cc b/examples/step-25/step-25.cc index 8f8d4d7b21bc..7372a4798003 100644 --- a/examples/step-25/step-25.cc +++ b/examples/step-25/step-25.cc @@ -308,9 +308,11 @@ namespace Step25 mass_matrix.reinit(sparsity_pattern); laplace_matrix.reinit(sparsity_pattern); - MatrixCreator::create_mass_matrix(dof_handler, QGauss(3), mass_matrix); + MatrixCreator::create_mass_matrix(dof_handler, + QGauss(fe.degree + 1), + mass_matrix); MatrixCreator::create_laplace_matrix(dof_handler, - QGauss(3), + QGauss(fe.degree + 1), laplace_matrix); solution.reinit(dof_handler.n_dofs()); @@ -398,7 +400,7 @@ namespace Step25 Vector &nl_term) const { nl_term = 0; - const QGauss quadrature_formula(3); + const QGauss quadrature_formula(fe.degree + 1); FEValues fe_values(fe, quadrature_formula, update_values | update_JxW_values | @@ -462,7 +464,7 @@ namespace Step25 const Vector &new_data, SparseMatrix &nl_matrix) const { - QGauss quadrature_formula(3); + QGauss quadrature_formula(fe.degree + 1); FEValues fe_values(fe, quadrature_formula, update_values | update_JxW_values | @@ -601,7 +603,7 @@ namespace Step25 constraints.close(); VectorTools::project(dof_handler, constraints, - QGauss(3), + QGauss(fe.degree + 1), InitialValues(1, time), solution); } diff --git a/examples/step-28/step-28.cc b/examples/step-28/step-28.cc index f0e6b763e3d2..5e6bed8f4217 100644 --- a/examples/step-28/step-28.cc +++ b/examples/step-28/step-28.cc @@ -1233,8 +1233,7 @@ namespace Step28 }; - // @sect4{Implementation of the - // NeutronDiffusionProblem::Parameters class} + // @sect4{Implementation of the Parameters class} // Before going on to the implementation of the outer class, we have to // implement the functions of the parameters structure. This is pretty diff --git a/examples/step-29/step-29.cc b/examples/step-29/step-29.cc index cc2d2b459037..805f55801f95 100644 --- a/examples/step-29/step-29.cc +++ b/examples/step-29/step-29.cc @@ -554,8 +554,8 @@ namespace Step29 // used. Since our bilinear form involves boundary integrals on // $\Gamma_2$, we also need a quadrature rule for surface integration on // the faces, which are $dim-1$ dimensional: - QGauss quadrature_formula(2); - QGauss face_quadrature_formula(2); + QGauss quadrature_formula(fe.degree + 1); + QGauss face_quadrature_formula(fe.degree + 1); const unsigned int n_q_points = quadrature_formula.size(), n_face_q_points = face_quadrature_formula.size(), diff --git a/examples/step-3/doc/results.dox b/examples/step-3/doc/results.dox index a39a00addc96..6e61813cf71a 100644 --- a/examples/step-3/doc/results.dox +++ b/examples/step-3/doc/results.dox @@ -192,7 +192,7 @@ suggestions: @code std::cout << "Mean value: " << VectorTools::compute_mean_value (dof_handler, - QGauss<2>(3), + QGauss<2>(fe.degree + 1), solution, 0) << std::endl; diff --git a/examples/step-3/step-3.cc b/examples/step-3/step-3.cc index 1e50eef4db8d..9f35b732793c 100644 --- a/examples/step-3/step-3.cc +++ b/examples/step-3/step-3.cc @@ -272,7 +272,7 @@ void Step3::assemble_system() // 2D. This quadrature formula integrates polynomials of degrees up to three // exactly (in 1D). It is easy to check that this is sufficient for the // present problem: - QGauss<2> quadrature_formula(2); + QGauss<2> quadrature_formula(fe.degree + 1); // And we initialize the object which we have briefly talked about above. It // needs to be told which finite element we want to use, and the quadrature // points and their weights (jointly described by a Quadrature object). As diff --git a/examples/step-33/step-33.cc b/examples/step-33/step-33.cc index a3ce08eb58b4..a24a5665fc25 100644 --- a/examples/step-33/step-33.cc +++ b/examples/step-33/step-33.cc @@ -1381,8 +1381,8 @@ namespace Step33 : mapping() , fe(FE_Q(1), EulerEquations::n_components) , dof_handler(triangulation) - , quadrature(2) - , face_quadrature(2) + , quadrature(fe.degree + 1) + , face_quadrature(fe.degree + 1) , verbose_cout(std::cout, false) { ParameterHandler prm; @@ -2152,8 +2152,7 @@ namespace Step33 direct.solve(system_matrix, newton_update, right_hand_side); - return std::pair(solver_control.last_step(), - solver_control.last_value()); + return {solver_control.last_step(), solver_control.last_value()}; } // Likewise, if we are to use an iterative solver, we use Aztec's GMRES @@ -2215,13 +2214,12 @@ namespace Step33 solver.Iterate(parameters.max_iterations, parameters.linear_residual); - return std::pair(solver.NumIters(), - solver.TrueResidual()); + return {solver.NumIters(), solver.TrueResidual()}; } } Assert(false, ExcNotImplemented()); - return std::pair(0, 0); + return {0, 0}; } diff --git a/examples/step-36/step-36.cc b/examples/step-36/step-36.cc index fe6e593e15d1..6213053568c4 100644 --- a/examples/step-36/step-36.cc +++ b/examples/step-36/step-36.cc @@ -237,7 +237,7 @@ namespace Step36 template void EigenvalueProblem::assemble_system() { - QGauss quadrature_formula(2); + QGauss quadrature_formula(fe.degree + 1); FEValues fe_values(fe, quadrature_formula, diff --git a/examples/step-37/step-37.cc b/examples/step-37/step-37.cc index 65d118b59b30..e64baa61b83b 100644 --- a/examples/step-37/step-37.cc +++ b/examples/step-37/step-37.cc @@ -950,7 +950,7 @@ namespace Step37 // do not have the matrix elements available explicitly, and it is // difficult to make it work efficiently in %parallel.) The smoother is // initialized with our level matrices and the mandatory additional data - // for the Chebyshev smoother. We use a relatively high degree here (4), + // for the Chebyshev smoother. We use a relatively high degree here (5), // since matrix-vector products are comparably cheap. We choose to smooth // out a range of $[1.2 \hat{\lambda}_{\max}/15,1.2 \hat{\lambda}_{\max}]$ // in the smoother where $\hat{\lambda}_{\max}$ is an estimate of the @@ -1002,7 +1002,7 @@ namespace Step37 if (level > 0) { smoother_data[level].smoothing_range = 15.; - smoother_data[level].degree = 4; + smoother_data[level].degree = 5; smoother_data[level].eig_cg_n_iterations = 10; } else diff --git a/examples/step-4/step-4.cc b/examples/step-4/step-4.cc index a63c86d40e5a..e3d1447b2288 100644 --- a/examples/step-4/step-4.cc +++ b/examples/step-4/step-4.cc @@ -186,7 +186,7 @@ double RightHandSide::value(const Point &p, for (unsigned int i = 0; i < dim; ++i) return_value += 4.0 * std::pow(p(i), 4.0); - return 1.; // return_value; + return return_value; } @@ -308,7 +308,7 @@ void Step4::setup_system() template void Step4::assemble_system() { - QGauss quadrature_formula(2); + QGauss quadrature_formula(fe.degree + 1); // We wanted to have a non-constant right hand side, so we use an object of // the class declared above to generate the necessary data. Since this right diff --git a/examples/step-40/CMakeLists.txt b/examples/step-40/CMakeLists.txt index 75c4c132e8bd..e0ac1cf48468 100644 --- a/examples/step-40/CMakeLists.txt +++ b/examples/step-40/CMakeLists.txt @@ -37,7 +37,7 @@ ENDIF() # # Are all dependencies fulfilled? # -IF(NOT (DEAL_II_WITH_PETSC OR DEAL_II_WITH_TRILINOS) OR NOT DEAL_II_WITH_P4EST OR DEAL_II_PETSC_WITH_COMPLEX) # keep in one line +IF(NOT ((DEAL_II_WITH_PETSC AND NOT DEAL_II_PETSC_WITH_COMPLEX) OR DEAL_II_WITH_TRILINOS) OR NOT DEAL_II_WITH_P4EST) # keep in one line MESSAGE(FATAL_ERROR " Error! This tutorial requires a deal.II library that was configured with the following options: DEAL_II_WITH_PETSC = ON diff --git a/examples/step-40/step-40.cc b/examples/step-40/step-40.cc index 0837dd65f662..be92c611a4eb 100644 --- a/examples/step-40/step-40.cc +++ b/examples/step-40/step-40.cc @@ -39,7 +39,7 @@ // if we are using PETSc (see solve() for an example where this is necessary) namespace LA { -#if defined(DEAL_II_WITH_PETSC) && \ +#if defined(DEAL_II_WITH_PETSC) && !defined(DEAL_II_PETSC_WITH_COMPLEX) && \ !(defined(DEAL_II_WITH_TRILINOS) && defined(FORCE_USE_OF_TRILINOS)) using namespace dealii::LinearAlgebraPETSc; # define USE_PETSC_LA @@ -151,7 +151,6 @@ namespace Step40 { public: LaplaceProblem(); - ~LaplaceProblem(); void run(); @@ -166,8 +165,8 @@ namespace Step40 parallel::distributed::Triangulation triangulation; - DoFHandler dof_handler; FE_Q fe; + DoFHandler dof_handler; IndexSet locally_owned_dofs; IndexSet locally_relevant_dofs; @@ -185,7 +184,7 @@ namespace Step40 // @sect3{The LaplaceProblem class implementation} - // @sect4{Constructors and destructors} + // @sect4{Constructor} // Constructors and destructors are rather trivial. In addition to what we // do in step-6, we set the set of processors we want to work on to all @@ -202,8 +201,8 @@ namespace Step40 typename Triangulation::MeshSmoothing( Triangulation::smoothing_on_refinement | Triangulation::smoothing_on_coarsening)) - , dof_handler(triangulation) , fe(2) + , dof_handler(triangulation) , pcout(std::cout, (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)) , computing_timer(mpi_communicator, @@ -214,13 +213,6 @@ namespace Step40 - template - LaplaceProblem::~LaplaceProblem() - { - dof_handler.clear(); - } - - // @sect4{LaplaceProblem::setup_system} // The following function is, arguably, the most interesting one in the @@ -366,7 +358,7 @@ namespace Step40 { TimerOutput::Scope t(computing_timer, "assembly"); - const QGauss quadrature_formula(3); + const QGauss quadrature_formula(fe.degree + 1); FEValues fe_values(fe, quadrature_formula, @@ -523,7 +515,7 @@ namespace Step40 Vector estimated_error_per_cell(triangulation.n_active_cells()); KellyErrorEstimator::estimate( dof_handler, - QGauss(3), + QGauss(fe.degree + 1), std::map *>(), locally_relevant_solution, estimated_error_per_cell); diff --git a/examples/step-41/step-41.cc b/examples/step-41/step-41.cc index 41d2e233aeda..f2e5ec11716b 100644 --- a/examples/step-41/step-41.cc +++ b/examples/step-41/step-41.cc @@ -576,21 +576,22 @@ namespace Step41 // @sect4{ObstacleProblem::output_results} // We use the vtk-format for the output. The file contains the displacement - // and a numerical representation of the active set. The function looks - // standard but note that we can add an IndexSet object to the DataOut - // object in exactly the same way as a regular solution vector: it is simply - // interpreted as a function that is either zero (when a degree of freedom - // is not part of the IndexSet) or one (if it is). + // and a numerical representation of the active set. template void ObstacleProblem::output_results(const unsigned int iteration) const { std::cout << " Writing graphical output..." << std::endl; + TrilinosWrappers::MPI::Vector active_set_vector( + dof_handler.locally_owned_dofs(), MPI_COMM_WORLD); + for (const auto index : active_set) + active_set_vector[index] = 1.; + DataOut data_out; data_out.attach_dof_handler(dof_handler); data_out.add_data_vector(solution, "displacement"); - data_out.add_data_vector(active_set, "active_set"); + data_out.add_data_vector(active_set_vector, "active_set"); data_out.add_data_vector(contact_force, "lambda"); data_out.build_patches(); diff --git a/examples/step-42/step-42.cc b/examples/step-42/step-42.cc index 2006200602e5..32394d47b7bb 100644 --- a/examples/step-42/step-42.cc +++ b/examples/step-42/step-42.cc @@ -897,7 +897,7 @@ namespace Step42 // indicator one. Point<3> rotate_half_sphere(const Point<3> &in) { - return Point<3>(in(2), in(1), -in(0)); + return {in(2), in(1), -in(0)}; } template @@ -1388,13 +1388,9 @@ namespace Step42 std::vector local_dof_indices(dofs_per_cell); - typename DoFHandler::active_cell_iterator cell = - dof_handler.begin_active(), - endc = dof_handler.end(); - const FEValuesExtractors::Vector displacement(0); - for (; cell != endc; ++cell) + for (const auto &cell : dof_handler.active_cell_iterators()) if (cell->is_locally_owned()) { fe_values.reinit(cell); @@ -1553,11 +1549,7 @@ namespace Step42 fraction_of_plastic_q_points_per_cell = 0; - typename DoFHandler::active_cell_iterator cell = - dof_handler.begin_active(), - endc = dof_handler.end(); - unsigned int cell_number = 0; - for (; cell != endc; ++cell, ++cell_number) + for (const auto &cell : dof_handler.active_cell_iterators()) if (cell->is_locally_owned()) { fe_values.reinit(cell); @@ -1574,7 +1566,8 @@ namespace Step42 constitutive_law.get_stress_strain_tensor( strain_tensors[q_point], stress_strain_tensor); if (q_point_is_plastic) - ++fraction_of_plastic_q_points_per_cell(cell_number); + ++fraction_of_plastic_q_points_per_cell( + cell->active_cell_index()); for (unsigned int i = 0; i < dofs_per_cell; ++i) { @@ -2032,6 +2025,16 @@ namespace Step42 mpi_communicator); lambda = distributed_lambda; + TrilinosWrappers::MPI::Vector distributed_active_set_vector( + locally_owned_dofs, mpi_communicator); + distributed_active_set_vector = 0.; + for (const auto index : active_set) + distributed_active_set_vector[index] = 1.; + distributed_lambda.compress(VectorOperation::insert); + + TrilinosWrappers::MPI::Vector active_set_vector(locally_relevant_dofs, + mpi_communicator); + active_set_vector = distributed_active_set_vector; DataOut data_out; @@ -2048,7 +2051,7 @@ namespace Step42 std::vector(dim, "contact_force"), DataOut::type_dof_data, data_component_interpretation); - data_out.add_data_vector(active_set, + data_out.add_data_vector(active_set_vector, std::vector(dim, "active_set"), DataOut::type_dof_data, data_component_interpretation); diff --git a/examples/step-43/step-43.cc b/examples/step-43/step-43.cc index 987b2d6d724a..383bcc2f0fce 100644 --- a/examples/step-43/step-43.cc +++ b/examples/step-43/step-43.cc @@ -78,8 +78,7 @@ namespace Step43 using namespace dealii; - // @sect3{Pressure right hand side, pressure boundary values and saturation - // initial value classes} + // @sect3{Right hand side, boundary and initial value classes} // The following part is taken directly from step-21 so there is no need to // repeat the descriptions found there. diff --git a/examples/step-44/step-44.cc b/examples/step-44/step-44.cc index 1cbc8c819407..7a60db62fefb 100644 --- a/examples/step-44/step-44.cc +++ b/examples/step-44/step-44.cc @@ -2440,7 +2440,7 @@ namespace Step44 // build non-homogeneous constraints in the zeroth iteration (that is, when // `apply_dirichlet_bc == true`) and build only the corresponding // homogeneous constraints in the following step. While the current - // example has only homogenous constraints, previous experiences have + // example has only homogeneous constraints, previous experiences have // shown that a common error is forgetting to add the extra condition when // refactoring the code to specific uses. This could lead errors that are // hard to debug. In this spirit, we choose to make the code more verbose diff --git a/examples/step-49/step-49.cc b/examples/step-49/step-49.cc index a40312e76b40..c99e66a0e32a 100644 --- a/examples/step-49/step-49.cc +++ b/examples/step-49/step-49.cc @@ -278,7 +278,7 @@ struct Grid6Func Point<2> operator()(const Point<2> &in) const { - return Point<2>(in(0), trans(in(1))); + return {in(0), trans(in(1))}; } }; diff --git a/examples/step-5/step-5.cc b/examples/step-5/step-5.cc index 8b694d173a4f..2c0af8746069 100644 --- a/examples/step-5/step-5.cc +++ b/examples/step-5/step-5.cc @@ -162,7 +162,7 @@ void Step5::setup_system() template void Step5::assemble_system() { - QGauss quadrature_formula(2); + QGauss quadrature_formula(fe.degree + 1); FEValues fe_values(fe, quadrature_formula, diff --git a/examples/step-51/step-51.cc b/examples/step-51/step-51.cc index c44dbcda51da..36a1d91145fa 100644 --- a/examples/step-51/step-51.cc +++ b/examples/step-51/step-51.cc @@ -1333,7 +1333,7 @@ namespace Step51 std::map *> neumann_boundary; KellyErrorEstimator::estimate(dof_handler_local, - QGauss(3), + QGauss(fe.degree + 1), neumann_boundary, solution_local, estimated_error_per_cell, diff --git a/examples/step-53/doc/intro.dox b/examples/step-53/doc/intro.dox index cfe64dd35fba..f5c51da6665e 100644 --- a/examples/step-53/doc/intro.dox +++ b/examples/step-53/doc/intro.dox @@ -72,7 +72,7 @@ program the details of your geometry: necessary to compute integrals using curved approximations of the boundary, i.e., describe each edge or face of cells as curves, instead of straight line segments or bilinear patches. The same is, of course, true when - integrating boundary terms (e.g., inhomogenous Neumann boundary + integrating boundary terms (e.g., inhomogeneous Neumann boundary conditions). For the purpose of integration, the various Mapping classes then provide the transformation from the reference cell to the actual cell. diff --git a/examples/step-53/step-53.cc b/examples/step-53/step-53.cc index f60c0755e1ee..3e4eb436a5c9 100644 --- a/examples/step-53/step-53.cc +++ b/examples/step-53/step-53.cc @@ -277,10 +277,9 @@ namespace Step53 const double R_bar = R / std::sqrt(1 - (ellipticity * ellipticity * std::sin(theta) * std::sin(theta))); - return Point<3>((R_bar + d) * std::cos(phi) * std::cos(theta), - (R_bar + d) * std::sin(phi) * std::cos(theta), - ((1 - ellipticity * ellipticity) * R_bar + d) * - std::sin(theta)); + return {(R_bar + d) * std::cos(phi) * std::cos(theta), + (R_bar + d) * std::sin(phi) * std::cos(theta), + ((1 - ellipticity * ellipticity) * R_bar + d) * std::sin(theta)}; } Point<3> AfricaGeometry::pull_back_wgs84(const Point<3> &x) const diff --git a/examples/step-55/step-55.cc b/examples/step-55/step-55.cc index 2d42ef85f432..10b6ac513f10 100644 --- a/examples/step-55/step-55.cc +++ b/examples/step-55/step-55.cc @@ -691,7 +691,7 @@ namespace Step55 FEValuesExtractors::Vector velocities(0); KellyErrorEstimator::estimate( dof_handler, - QGauss(3), + QGauss(fe.degree + 1), std::map *>(), locally_relevant_solution, estimated_error_per_cell, diff --git a/examples/step-57/step-57.cc b/examples/step-57/step-57.cc index 112783b0e353..227e84b75f5d 100644 --- a/examples/step-57/step-57.cc +++ b/examples/step-57/step-57.cc @@ -135,16 +135,18 @@ namespace Step57 BlockVector evaluation_point; }; - // @sect3{Boundary values and right hand side} In this problem we set the - // velocity along the upper surface of the cavity to be one and zero on the - // other three walls. The right hand side function is zero so we do not need - // to set the right hand side function in this tutorial. The number of - // components of the boundary function is dim+1. We will - // ultimately use VectorTools::interpolate_boundary_values to set boundary - // values, which requires the boundary value functions to have the same - // number of components as the solution, even if all are not used. Put - // another way: to make this function happy we define boundary values for - // the pressure even though we will never actually use them. + // @sect3{Boundary values and right hand side} + + // In this problem we set the velocity along the upper surface of the cavity + // to be one and zero on the other three walls. The right hand side function + // is zero so we do not need to set the right hand side function in this + // tutorial. The number of components of the boundary function is + // dim+1. We will ultimately use + // VectorTools::interpolate_boundary_values to set boundary values, which + // requires the boundary value functions to have the same number of + // components as the solution, even if all are not used. Put another way: to + // make this function happy we define boundary values for the pressure even + // though we will never actually use them. template class BoundaryValues : public Function { @@ -254,6 +256,7 @@ namespace Step57 // @sect3{StationaryNavierStokes class implementation} // @sect4{StationaryNavierStokes::StationaryNavierStokes} + // // The constructor of this class looks very similar to the one in step-22. The // only difference is the viscosity and the Augmented Lagrangian coefficient // gamma. @@ -268,6 +271,7 @@ namespace Step57 {} // @sect4{StationaryNavierStokes::setup_dofs} + // // This function initializes the DoFHandler enumerating the degrees of freedom // and constraints on the current mesh. template @@ -331,6 +335,7 @@ namespace Step57 } // @sect4{StationaryNavierStokes::initialize_system} + // // On each mesh the SparsityPattern and the size of the linear system // are different. This function initializes them after mesh refinement. template @@ -350,7 +355,7 @@ namespace Step57 } // @sect4{StationaryNavierStokes::assemble} - + // // This function builds the system matrix and right hand side that we // currently work on. The @p initial_step argument is used to determine // which set of constraints we apply (nonzero for the initial step and zero @@ -513,6 +518,7 @@ namespace Step57 } // @sect4{StationaryNavierStokes::solve} + // // In this function, we use FGMRES together with the block preconditioner, // which is defined at the beginning of the program, to solve the linear // system. What we obtain at this step is the solution vector. If this is @@ -728,6 +734,7 @@ namespace Step57 } // @sect4{StationaryNavierStokes::output_results} + // // This function is the same as in step-22 except that we choose a name // for the output file that also contains the Reynolds number (i.e., the // inverse of the viscosity in the current context). @@ -757,6 +764,7 @@ namespace Step57 } // @sect4{StationaryNavierStokes::process_solution} + // // In our test case, we do not know the analytical solution. This function // outputs the velocity components along $x=0.5$ and $0 \leq y \leq 1$ so they // can be compared with data from the literature. @@ -788,6 +796,7 @@ namespace Step57 } // @sect4{StationaryNavierStokes::run} + // // This is the last step of this program. In this part, we generate the grid // and run the other functions respectively. The max refinement can be set by // the argument. diff --git a/examples/step-59/step-59.cc b/examples/step-59/step-59.cc index 979488fdde04..5627107ffb57 100644 --- a/examples/step-59/step-59.cc +++ b/examples/step-59/step-59.cc @@ -1235,7 +1235,7 @@ namespace Step59 if (level > 0) { smoother_data[level].smoothing_range = 15.; - smoother_data[level].degree = 2; + smoother_data[level].degree = 3; smoother_data[level].eig_cg_n_iterations = 10; } else diff --git a/examples/step-6/step-6.cc b/examples/step-6/step-6.cc index b45caaf7bd4f..18bb3b476823 100644 --- a/examples/step-6/step-6.cc +++ b/examples/step-6/step-6.cc @@ -269,7 +269,7 @@ void Step6::setup_system() template void Step6::assemble_system() { - const QGauss quadrature_formula(3); + const QGauss quadrature_formula(fe.degree + 1); FEValues fe_values(fe, quadrature_formula, @@ -422,7 +422,7 @@ void Step6::refine_grid() KellyErrorEstimator::estimate( dof_handler, - QGauss(3), + QGauss(fe.degree + 1), std::map *>(), solution, estimated_error_per_cell); diff --git a/examples/step-61/CMakeLists.txt b/examples/step-61/CMakeLists.txt new file mode 100644 index 000000000000..438736f4746b --- /dev/null +++ b/examples/step-61/CMakeLists.txt @@ -0,0 +1,39 @@ +## +# CMake script for the step-61 tutorial program: +## + +# Set the name of the project and target: +SET(TARGET "step-61") + +# Declare all source files the target consists of. Here, this is only +# the one step-X.cc file, but as you expand your project you may wish +# to add other source files as well. If your project becomes much larger, +# you may want to either replace the following statement by something like +# FILE(GLOB_RECURSE TARGET_SRC "source/*.cc") +# FILE(GLOB_RECURSE TARGET_INC "include/*.h") +# SET(TARGET_SRC ${TARGET_SRC} ${TARGET_INC}) +# or switch altogether to the large project CMakeLists.txt file discussed +# in the "CMake in user projects" page accessible from the "User info" +# page of the documentation. +SET(TARGET_SRC + ${TARGET}.cc + ) + +# Usually, you will not need to modify anything beyond this point... + +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) + +FIND_PACKAGE(deal.II 9.1.0 QUIET + HINTS ${deal.II_DIR} ${DEAL_II_DIR} ../ ../../ $ENV{DEAL_II_DIR} + ) +IF(NOT ${deal.II_FOUND}) + MESSAGE(FATAL_ERROR "\n" + "*** Could not locate a (sufficiently recent) version of deal.II. ***\n\n" + "You may want to either pass a flag -DDEAL_II_DIR=/path/to/deal.II to cmake\n" + "or set an environment variable \"DEAL_II_DIR\" that contains this path." + ) +ENDIF() + +DEAL_II_INITIALIZE_CACHED_VARIABLES() +PROJECT(${TARGET}) +DEAL_II_INVOKE_AUTOPILOT() diff --git a/examples/step-61/doc/builds-on b/examples/step-61/doc/builds-on new file mode 100644 index 000000000000..2bb1b6e1daea --- /dev/null +++ b/examples/step-61/doc/builds-on @@ -0,0 +1 @@ +step-51 step-7 step-20 diff --git a/examples/step-61/doc/intro.dox b/examples/step-61/doc/intro.dox new file mode 100644 index 000000000000..799566ddaa71 --- /dev/null +++ b/examples/step-61/doc/intro.dox @@ -0,0 +1,468 @@ +
    + + +This program was contributed by Zhuoran Wang. + + + +

    Introduction

    + +This tutorial program presents an implementation of the "weak Galerkin" +finite element method for the Poisson equation. In some sense, the motivation for +considering this method starts from the same point as in step-51: We would like to +consider discontinuous shape functions, but then need to address the fact that +the resulting problem has a much larger number of degrees of freedom compared to +the usual continuous Galerkin method (because, for +example, each vertex carries as many degrees of freedom as there are adjacent cells). +We also have to address the fact that, unlike in the continuous +Galerkin method, every degree of freedom +on one cell couples with all of the degrees of freedom on each of its face neighbor +cells. Consequently, the matrix one gets from the "traditional" discontinuous +Galerkin methods are both large and relatively dense. + +Both the hybridized discontinuous Galerkin method (HDG) in step-51 and the weak +Galerkin (WG) method in this tutorial address the issue of coupling by introducing +additional degrees of freedom whose shape functions only live on a face between +cells (i.e., on the "skeleton" of the mesh), and which therefore "insulate" the +degrees of freedom on the adjacent cells from each other: cell degrees of freedom +only couple with other cell degrees of freedom on the same cell, as well as face +degrees of freedom, but not with cell degrees of freedom on neighboring cells. +Consequently, the coupling of shape functions for these cell degrees of freedom +indeed local to on exactly one cell and the degrees of freedom defined on its +faces. + +For a given equation, say the second order Poisson equation, +the difference between the HDG and the WG method is how precisely one formulates +the problem that connects all of these different shape functions. (Indeed, +for some WG and HDG formulation, it is possible to show that they are equivalent.) +The HDG does things by reformulating second order problems in terms of a system of first +order equations and then conceptually considers the face degrees of freedom +to be "fluxes" of this first order system. In contrast, the WG method keeps things +in second order form and considers the face degrees of freedom as of the same +type as the primary solution variable, just restricted to the lower-dimensional +faces. For the purposes of the equation, one then needs to somehow "extend" +these shape functions into the interior of the cell when defining what it means +to apply a differential operator to them. Compared to the HDG, the method +has the advantage that it does not lead to a proliferation of unknowns due +to rewriting the equation as a first-order system, but it is also not quite +as easy to implement. However, as we will see in the following, this +additional effort is not prohibitive. + + +

    Weak Galerkin finite element methods

    + +Weak Galerkin Finite Element Methods (WGFEMs) use discrete weak functions +to approximate scalar unknowns, and discrete weak gradients to +approximate classical gradients. +The method was originally introduced by Junping Wang and Xiu Ye +in the paper + +A weak Galerkin finite element method for second order elliptic problems, +J. Comput. Appl. Math., 103-115, 2013. +Compared to the continuous Galerkin method, +the weak Galerkin method satisfies important physical properties, namely +local mass conservation and bulk normal flux continuity. +It results in a SPD linear system, and optimal convergence rates can +be obtained with mesh refinement. + + +

    The equation to solve

    +This program solves the Poisson equation +using the weak Galerkin finite element method: +@f{align*}{ + \nabla \cdot \left( -\mathbf{K} \nabla p \right) + &= f, + \qquad \mathbf{x} \in \Omega, \\ + p &= p_D,\qquad \mathbf{x} \in \Gamma^D, \\ + \mathbf{u} \cdot \mathbf{n} &= u_N, + \qquad \mathbf{x} \in \Gamma^N, +@f} +where $\Omega \subset \mathbb{R}^n (n=2,3)$ is a bounded domain. +In the context of the flow of a fluid through a porous medium, +$p$ is the pressure, $\mathbf{K}$ is a permeability tensor, +$f$ is the source term, and +$p_D, u_N$ represent Dirichlet and Neumann boundary conditions. +We can introduce a flux, $\mathbf{u} = -\mathbf{K} \nabla p$, that corresponds +to the Darcy velocity (in the way we did in step-20) and this variable will +be important in the considerations below. + +In this program, we will consider a test case where the exact pressure +is $p = \sin \left( \pi x\right)\sin\left(\pi y \right)$ on the unit square domain, +with homogeneous Dirichelet boundary conditions and $\mathbf{K}$ the identity matrix. +Then we will calculate $L_2$ errors of pressure, velocity, and flux. + + +

    Weak Galerkin scheme

    + +The Poisson equation above has a solution $p$ that needs to satisfy the weak +formulation of the problem, +@f{equation*} +\mathcal{A}\left(p,q \right) = \mathcal{F} \left(q \right), +@f} +for all test functions $q$, where +@f{equation*} +\mathcal{A}\left(p,q\right) + := \int_\Omega \left(\mathbf{K} \nabla p\right) \cdot \nabla q \;\mathrm{d}x, +@f} +and +@f{equation*} +\mathcal{F}\left(q\right) + := \int_\Omega f \, q \;\mathrm{d}x + - \int_{\Gamma^N} u_N q \; \mathrm{d}x. +@f} +Here, we have integrated by parts in the bilinear form, and we are evaluating +the gradient of $p,p$ in the interior and the values of $q$ on the boundary +of the domain. All of this is well defined because we assume that the solution +is in $H^1$ for which taking the gradient and evaluating boundary values +are valid operations. + +The idea of the weak Galerkin method is now to approximate the exact $p$ +solution with a discontinuous function $p_h$. This function may only be +discontinuous along interfaces between cells, and because we will want to +evaluate this function also along interfaces, we have to +prescribe not only what values it is supposed to have in the cell interiors +but also its values along interfaces. We do this by saying that $p_h$ is +actually a tuple, $p_h=(p^\circ,p^\partial)$, though it's really just +a single function that is either equal to $p^\circ(x)$ or $p^\partial(x)$, +depending on whether it is evaluated at a point $x$ that lies in the cell +interior or on cell interfaces. + +We would then like to simply stick this approximation into the bilinear +form above. This works for the case where we have to evaluate the +test function $q_h$ on the boundary (where we would simply take its interface +part $q_h^\partial$) but we have to be careful with the gradient because +that is only defined in cell interiors. Consequently, + the weak Galerkin scheme for the Poisson equation is defined by +@f{equation*} +\mathcal{A}_h\left(p_h,q \right) = \mathcal{F} \left(q_h \right), +@f} +for all discrete test functions $q_h$, where +@f{equation*} +\mathcal{A}_h\left(p_h,q_h\right) + := \sum_{K \in \mathbb{T}} + \int_K \mathbf{K} \nabla_{w,d} p_h \cdot \nabla_{w,d} q_h \;\mathrm{d}x, +@f} +and +@f{equation*} +\mathcal{F}\left(q_h\right) + := \sum_{K \in \mathbb{T}} \int_K f \, q_h^\circ \;\mathrm{d}x + - \sum_{\gamma \in \Gamma_h^N} \int_\gamma u_N q_h^\partial \;\mathrm{d}x, +@f} +The key point is that here, we have replaced the gradient $\nabla p_h$ by the +discrete weak gradient operator + $ \nabla_{w,d} p_h $ that makes sense for our peculiarly defined approximation $p_h$. + +The question is then how that operator works. For this, let us first say how we +think of the discrete approximation $p_h$ of the pressure. As mentioned above, +the "function" $p_h$ actually consists of two parts: the values $p_h^\circ$ in +the interior of cells, and $p_h^\partial$ on the interfaces. We have to define +discrete (finite-dimensional) function spaces for both of these; in this +program, we will use FE_DGQ for $p_h^\circ$ as the space in the interior of +cells (defined on each cell, but in general discontinuous along interfaces), +and FE_FaceQ for $p_h^\partial$ as the space on the interfaces. + +Then let us consider just a single cell (because the integrals above are all +defined cell-wise, and because the weak discrete gradient is defined cell-by-cell). +The restriction of $p_h$ to cell $K$, $p_h|_K$ then consists +of the pair $(p_h^\circ|_K,p_h^\partial|_{\partial K})$. In essence, we can +think of $\nabla_{w,d} p_h$ of some function defined on $K$ that approximates +the gradient; in particular, if $p_h|_K$ was the restriction of a differentiable +function (to the interior and boundary of $K$ -- which would make it continuous +between the interior and boundary), then +$\nabla_{w,d} p_h$ would simply be the exact gradient $\nabla p_h$. But, since +$p_h|_K$ is not continuous between interior and boundary of $K$, we need a more +general definition; furthermore, we can not deal with arbitrary functions, and +so require that $\nabla_{w,d} p_h$ is also in a finite element space (which, since +the gradient is a vector, has to be vector-valued). + +The way this is done is to define this weak gradient operator $\nabla_{w,d}|_K : +DGQ_k(K) \times DGQ_r(\partial K) \rightarrow RT_s(K)$ (where $RT_s(K)$ is the +vector-valued Raviart-Thomas space of order $s$ on cell $K$) in the following way: +@f{equation*}{ + \int_K \mathbf v_h \cdot (\nabla_{w,d} p_h) + = + -\int_K (\nabla \cdot \mathbf v_h) p_h^\circ + +\int_{\partial K} (\mathbf v_h \cdot \mathbf n) p_h^\partial, +@f} +for all test functions $\mathbf v_h \in RT_s(K)$. +This is, in essence, simply an application of the integration-by-parts +formula. In other words, for a given $p_h=(p^\circ_h,p^\partial_h)$, +we need to think of $\nabla_{w,d} p_h|_K$ as that +Raviart-Thomas function of degree $s$ for which the left hand side and right hand side +are equal for all test functions. + +@note It may be worth pointing out that while the weak discrete + gradient is an element of the Raviart-Thomas space $RT_s(K)$ on each + cell $K$, it is discontinuous between cells. On the other hand, the + Raviart-Thomas space $RT_s=RT_s({\mathbb T})$ defined on the entire + mesh and implemented by the FE_RaviartThomas class represents + functions that have continuous normal components at interfaces + between cells. This means that globally, $\nabla_{w,d} p_h$ + is not in $RT_s$, even though it is on every cell $K$ in $RT_s(K)$. + Rather, it is in a "broken" Raviart-Thomas space that below we will + represent by the symbol $DGRT_s$. (The term "broken" here refers to + the process of "breaking something apart", and not to the synonym to + the expression "not functional".) + + +

    Representing the weak gradient

    + +Since $p_h$ is an element of a finite element space, we can expand it in a basis +as we always do, i.e., we can write +@f{equation*}{ + p_h(\mathbf x) = \sum_j P_j \varphi_j(\mathbf x). +@f} +Here, since $p_h$ has two components (the interior and the interface components), +the same must hold true for the basis functions $\varphi_j(\mathbf x)$, which we +can write as $\varphi_j = (\varphi_j^\circ,\varphi_j^\partial)$. If you've +followed the descriptions in step-8, step-20, and the +@ref vector_valued "documentation module on vector-valued problems", +it will be no surprise that for some values of $j$, $\varphi_j^\circ$ will be +zero, whereas for other values of $j$, $\varphi_j^\partial$ will be zero -- i.e., +shape functions will be of either one or the other kind. That is not important, +here, however. What is important is that we need to wonder how we can represent +$\nabla_{w,d} \varphi_j$ because that is clearly what will appear in the +problem when we want to implement the bilinear form +@f{equation*} +\mathcal{A}_h\left(p_h,q_h\right) + = \sum_{K \in \mathbb{T}} + \int_K \mathbf{K} \nabla_{w,d} p_h \cdot \nabla_{w,d} q_h \;\mathrm{d}x, +@f} + +The key point is that $\nabla_{w,d} \varphi_j$ is known to be a member of the +"broken" Raviart-Thomas space $DGRT_s$. What this means is that we can +represent (on each cell $K$ separately) +@f{equation*} +\nabla_{w,d} \varphi_j|_K + = \sum_k C_{jk}^K \mathbf v_k|_K +@f} +where the functions $\mathbf v_k \in DGRT_s$, and where $C^K$ is a matrix of +dimension +@f{align*}{ + \text{dim}\left(DGQ_k(K) \times DGQ_r(K)\right) &\times \text{dim}\left(RT_s(K)\right) + \\ + &= + \left(\text{dim}(DGQ_k(K)) + \text{dim}(DGQ_r(K))\right) \times \text{dim}\left(RT_s(K)\right). +@f} +(That the weak discrete gradient can be represented as a matrix should not come +as a surprise: It is a linear operator from one finite dimensional +space to another finite dimensional space. If one chooses bases +for both of these spaces, then every linear operator can +of course be written as a matrix mapping the vector of expansion coefficients +with regards to the basis of the domain space of the operator, to +the vector of expansion coefficients with regards to the basis in the image +space.) + +Using this expansion, we can easily use the definition of the weak +discrete gradient above to define what the matrix is going to be: +@f{equation*}{ + \int_K \mathbf v_i \cdot \left(\sum_k C_{jk}^K \mathbf v_k\right) + = + -\int_K (\nabla \cdot \mathbf v_i) \varphi_j^\circ + +\int_{\partial K} (\mathbf v_i \cdot \mathbf n) \varphi_j^\partial, +@f} +for all test functions $\mathbf v_i \in DGRT_s$. + +This clearly leads to a linear system of the form +@f{equation*}{ + \sum_k M_{ik}^K C_{jk}^K + = + G_{ij}^K +@f} +with +@f{equation*}{ + M_{ik}^K = \int_K \mathbf v_i \cdot \mathbf v_k, + \qquad\qquad + G_{ij}^K = -\int_K (\nabla \cdot \mathbf v_i) \varphi_j^\circ + +\int_{\partial K} (\mathbf v_i \cdot \mathbf n) \varphi_j^\partial, +@f} +and consequently +@f{equation*}{ + \left(C^K\right)^T = \left(M^K\right)^{-1} G^K. +@f} +(In this last step, we have assumed that the indices $i,j,k$ only range +over those degrees of freedom active on cell $K$, +thereby ensuring that the mass matrix on the space $RT_s(K)$ is invertible.) +Equivalently, using the symmetry of the matrix $M$, we have that +@f{equation*}{ + C^K = \left(G^K\right)^{T} \left(M^K\right)^{-1}. +@f} +Also worth pointing out is that the +matrices $C^K$ and $G^K$ are of course not square but rectangular. + + +

    Assembling the linear system

    + +Having explained how the weak discrete gradient is defined, we can now +come back to the question of how the linear system for the equation in question +should be assembled. Specifically, using the definition of the bilinear +form ${\cal A}_h$ shown above, we then need to compute the elements of the +local contribution to the global matrix, +@f{equation*}{ + A^K_{ij} = \int_K \left({\mathbf K} \nabla_{w,d} \varphi_i\right) \cdot \nabla_{w,d} \varphi_j. +@f} +As explained above, we can expand $\nabla_{w,d} \varphi_i$ in terms of the +Raviart-Thomas basis on each cell, and similarly for $\nabla_{w,d} \varphi_j$: +@f{equation*}{ + A^K_{ij} = \int_K + \left( + {\mathbf K} + \sum_k C_{ik}^K \mathbf v_k|_K + \right) + \cdot + \sum_l C_{jl}^K \mathbf v_l|_K. +@f} +By re-arranging sums, this yields the following expression: +@f{equation*}{ + A^K_{ij} = + \sum_k \sum_l C_{ik}^K C_{jl}^K + \int_K + \left( + {\mathbf K} + \mathbf v_k|_K + \right) + \cdot + \mathbf v_l|_K. +@f} +So, if we have the matrix $C^K$ for each cell $K$, then we can easily compute +the contribution $A^K$ for cell $K$ to the matrix $A$ as follows: +@f{equation*}{ + A^K_{ij} = + \sum_k \sum_l C_{ik}^K C_{jl}^K + H^K_{kl} + = + \sum_k \sum_l C_{ik}^K H^K_{kl} C_{jl}^K + = + \left(C^K H^K (C^K)^T \right)_{ij}. +@f} +Here, +@f{equation*}{ + H^K_{kl} = + \int_K + \left( + {\mathbf K} + \mathbf v_k|_K + \right) + \cdot + \mathbf v_l|_K, +@f} +which is really just the mass matrix on cell $K$ using the Raviart-Thomas +basis and weighting by the permeability tensor $\mathbf K$. The derivation +here then shows that the weak Galerkin method really just requires us +to compute these $C^K$ and $H^K$ matrices on each cell $K$, and then +$A^K = C^K H^K (C^K)^T$, which is easily computed. The code to be shown +below does exactly this. + +Having so computed the contribution $A^K$ of cell $K$ to the global +matrix, all we have to do is to "distribute" these local contributions +into the global matrix. How this is done is first shown in step-3 and +step-4. In the current program, this will be facilitated by calling +AffineConstraints::distribute_local_to_global(). + +A linear system of course also needs a right hand side. There is no difficulty +associated with computing the right hand side here other than the fact +that we only need to use the cell-interior part $\varphi_i^\circ$ for +each shape function $\varphi_i$. + + +

    Post-processing and L2-errors

    + +The discussions in the previous sections have given us a linear +system that we can solve for the numerical pressure $p_h$. We can use +this to compute an approximation to the variable $\mathbf u = -{\mathbf K}\nabla p$ +that corresponds to the velocity with which the medium flows in a porous +medium if this is the model we are trying to solve. This kind of +step -- computing a derived quantity from the solution of the discrete +problem -- is typically called "post-processing". + +Here, instead of using the exact gradient of $p_h$, let us instead +use the discrete weak gradient of $p_h$ to calculate the velocity on each element. +As discussed above, +on each element the gradient of the numerical pressure $\nabla p$ can be +approximated by discrete weak gradients $ \nabla_{w,d}\phi_i$: +@f{equation*} +\nabla_{w,d} p_h += \nabla_{w,d} \left(\sum_{i} P_i \phi_i\right) += \sum_{i} P_i \nabla_{w,d}\phi_i. +@f} + +On cell $K$, +the numerical velocity $ \mathbf{u}_h = -\mathbf{K} \nabla_{w,d}p_h$ can be written as +@f{align*}{ + \mathbf{u}_h + &= -\mathbf{K} \nabla_{w,d} p + = -\mathbf{K}\sum_{i} \sum_{j} P_i C^K_{ij}\mathbf{v}_j, +@f} +where $C^K$ is the expansion matrix from above, and +$\mathbf{v}_j$ is the basis function of the $RT$ space on a cell. + +Unfortunately, $\mathbf{K} \mathbf{v}_j$ may not be in the $RT$ space +(unless, of course, if $\mathbf K$ is constant times the identity matrix). +So, in order to represent it in a finite element program, we need to +project it back into a finite dimensional space we can work with. Here, +we we will use the $L_2$-projection to project it back to the (broken) $RT$ +space. + +We define the projection as +$ \mathbf{Q}_h \left( \mathbf{K}\mathbf{v}_j \right) = +\sum_{k} d_{jk}\mathbf{v}_k$ on each cell $K$. +For any $j$, +$\left( \mathbf{Q}_h \left( \mathbf{Kv}_j \right),\mathbf{v}_k \right)_K = +\left( \mathbf{Kv}_j,\mathbf{v}_k \right)_K.$ +So, rather than the formula shown above, the numerical velocity on cell $K$ +instead becomes +@f{equation*} +\mathbf{u}_h = \mathbf{Q}_h \left( -\mathbf{K}\nabla_{w,d}p_h \right) = +-\sum_i \sum_j P_i B^K_{ij}\mathbf{Q}_h \left( \mathbf{K}\mathbf{v}_j \right), +@f} +and we have the following system to solve for the coefficients $d_{jk}$: +@f{equation*} + \sum_j + \left(\mathbf{v}_i,\mathbf{v}_j\right) + d_{jk} + = + \left( \mathbf{Kv}_j,\mathbf{v}_k \right). +@f} +In the implementation below, the matrix with elements +$ + d_{jk} +$ +is called cell_matrix_D, +whereas the matrix with elements +$ + \left( \mathbf{Kv}_j,\mathbf{v}_k \right) +$ +is called cell_matrix_E. + +Then the elementwise velocity is +@f{equation*} +\mathbf{u}_h = -\sum_{i} \sum_{j}P_ic_{ij}\sum_{k}d_{jk}\mathbf{v}_k = +\sum_{k}- \left(\sum_{j} \sum_{i} P_ic_{ij}d_{jk} \right)\mathbf{v}_k, +@f} +where $-\sum_{j} \sum_{i} P_ic_{ij}d_{jk}$ is called +beta in the code. + +Using this velocity obtained by "postprocessing" the solution, we can +define the $L_2$-errors of pressure, velocity, and flux +by the following formulas: +@f{align*}{ +\|p-p_h^\circ\|^2 + &= \sum_{K \in \mathbb{T}} \|p-p_h^\circ\|_{L_2(K)}^2, \\ + \|\mathbf{u}-\mathbf{u}_h\|^2 + &= \sum_{K \in \mathbb{T}} \|\mathbf{u}-\mathbf{u}_h\|_{L_2(K)^2}^d,\\ +\|(\mathbf{u}-\mathbf{u}_h) \cdot \mathbf{n}\|^2 + &= \sum_{K \in \mathbb{T}} \sum_{\gamma \subset \partial K} + \frac{|K|}{|\gamma|} \|\mathbf{u} \cdot \mathbf{n} - \mathbf{u}_h \cdot \mathbf{n}\|_{L_2(\gamma)}^2, +@f} +where $| K |$ is the area of the element, +$\gamma$ are faces of the element, +$\mathbf{n}$ are unit normal vectors of each face. The last of these +norms measures the accuracy of the normal component of the velocity +vectors over the interfaces between the cells of the mesh. The scaling +factor $|K|/|\gamma|$ is chosen so as to scale out the difference in +the length (or area) of the collection of interfaces as the mesh size +changes. + +The first of these errors above is easily computed using +VectorTools::integrate_difference. The others require a bit more work +and are implemented in the code below. diff --git a/examples/step-61/doc/kind b/examples/step-61/doc/kind new file mode 100644 index 000000000000..c1d9154931a7 --- /dev/null +++ b/examples/step-61/doc/kind @@ -0,0 +1 @@ +techniques diff --git a/examples/step-61/doc/results.dox b/examples/step-61/doc/results.dox new file mode 100644 index 000000000000..ed99e7b0ff45 --- /dev/null +++ b/examples/step-61/doc/results.dox @@ -0,0 +1,173 @@ +

    Results

    + +We run the program with a right hand side that will produce the solution +$p = \sin(\pi x) \sin(\pi y)$ and with homogeneous Dirichlet +boundary conditions in the domain $\Omega = (0,1)^2$. In addition, we choose +the coefficient matrix in the differential operator $\mathbf{K}$ as the +identity matrix. We test this setup using $\mbox{WG}(Q_0,Q_0;RT_{[0]})$, +$\mbox{WG}(Q_1,Q_1;RT_{[1]})$ and $\mbox{WG}(Q_2,Q_2;RT_{[2]})$ element +combinations. We will then visualize pressure values in interiors of cells +and on faces. We want to see that the pressure maximum is around 1 and the minimum +is around 0. With mesh refinement, the convergence rates of pressure, +velocity and flux should then be around 1 for $\mbox{WG}(Q_0,Q_0;RT_{[0]})$ , 2 +for $\mbox{WG}(Q_1,Q_1;RT_{[1]})$, and 3 for $\mbox{WG}(Q_2,Q_2;RT_{[2]})$. + + +

    Test results on WG(Q0,Q0;RT[0])

    + +The following figures show interior pressures and face pressures using the +$\mbox{WG}(Q_0,Q_0;RT_{[0]})$ element. The mesh is refined 2 times (top) +and 4 times (bottom), respectively. When the mesh is coarse, one can see +the face pressures $p^\partial$ neatly between the values of the interior +pressures $p^\circ$ on the two adjacent cells. + + + + + + + + + + +
    + +From the figures, we can see that with the mesh refinement, the maximum and +minimum pressure values are approaching the values we expect. +Since the mesh is a rectangular mesh and numbers of cells in each direction is even, we +have symmetric solutions. From the 3d figures on the right, +we can see that on $\mbox{WG}(Q_0,Q_0;RT_{[0]})$, the pressure is a constant +in the interior of the cell, as expected. + +

    Convergence table

    + +We run the code with finer meshes and get the following convergence rates of pressure, +velocity, and flux (as defined in the introduction). + + + + + + + + + + + + + + + + + + + + +
    number of refinements $\|p-p_h^\circ\|$ $\|\mathbf{u}-\mathbf{u}_h\|$ $\|(\mathbf{u}-\mathbf{u}_h) \cdot \mathbf{n}\|$
    2 1.587e-01 5.113e-01 7.062e-01
    3 8.000e-02 2.529e-01 3.554e-01
    4 4.006e-02 1.260e-01 1.780e-01
    5 2.004e-02 6.297e-02 8.902e-02
    Conv.rate 1.00 1.00 1.00
    + +We can see that the convergence rates of $\mbox{WG}(Q_0,Q_0;RT_{[0]})$ are around 1. +This, of course, matches our theoretical expectations. + + +

    Test results on WG(Q1,Q1;RT[1])

    + +We can repeat the experiment from above using the next higher polynomial +degree: +The following figures are interior pressures and face pressures implemented using +$\mbox{WG}(Q_1,Q_1;RT_{[1]})$. The mesh is refined 4 times. Compared to the +previous figures using +$\mbox{WG}(Q_0,Q_0;RT_{[0]})$, on each cell, the solution is no longer constant +on each cell, as we now use bilinear polynomials to do the approximation. +Consequently, there are 4 pressure values in one interior, 2 pressure values on +each face. + + + + + + +
    + +Compared to the corresponding image for the $\mbox{WG}(Q_0,Q_0;RT_{[0]})$ +combination, the solution is now substantially more accurate and, in +particular so close to being continuous at the interfaces that we can +no longer distinguish the interface pressures $p^\partial$ from the +interior pressures $p^\circ$ on the adjacent cells. + +

    Convergence table

    + +The following are the convergence rates of pressure, velocity, and flux +we obtain from using the $\mbox{WG}(Q_1,Q_1;RT_{[1]})$ element combination: + + + + + + + + + + + + + + + + + + + + +
    number of refinements $\|p-p_h^\circ\|$ $\|\mathbf{u}-\mathbf{u}_h\|$ $\|(\mathbf{u}-\mathbf{u}_h) \cdot \mathbf{n}\|$
    2 1.613e-02 5.093e-02 7.167e-02
    3 4.056e-03 1.276e-02 1.802e-02
    4 1.015e-03 3.191e-03 4.512e-03
    5 2.540e-04 7.979e-04 1.128e-03
    Conv.rate 2.00 2.00 2.00
    + +The convergence rates of $WG(Q_1,Q_1;RT_{[1]})$ are around 2, as expected. + + + +

    Test results on WG(Q2,Q2;RT[2])

    + +Let us go one polynomial degree higher. +The following are interior pressures and face pressures implemented using +$WG(Q_2,Q_2;RT_{[2]})$, with mesh size $h = 1/32$ (i.e., 5 global mesh +refinement steps). In the program, we use +`data_out_face.build_patches(fe.degree)` when generating graphical output +(see the documentation of DataOut::build_patches()), which here implies that +we divide each 2d cell interior into 4 subcells in order to provide a better +visualization of the quadratic polynomials. + + + + + +
    + + +

    Convergence table

    + +As before, we can generate convergence data for the +$L_2$ errors of pressure, velocity, and flux +using the $\mbox{WG}(Q_2,Q_2;RT_{[2]})$ combination: + + + + + + + + + + + + + + + + + + + + +
    number of refinements $\|p-p_h^\circ\|$ $\|\mathbf{u}-\mathbf{u}_h\|$ $\|(\mathbf{u}-\mathbf{u}_h) \cdot \mathbf{n}\|$
    2 1.072e-03 3.375e-03 4.762e-03
    3 1.347e-04 4.233e-04 5.982e-04
    4 1.685e-05 5.295e-05 7.487e-05
    5 2.107e-06 6.620e-06 9.362e-06
    Conv.rate 3.00 3.00 3.00
    + +Once more, the convergence rates of $\mbox{WG}(Q_2,Q_2;RT_{[2]})$ is +as expected, with values around 3. diff --git a/examples/step-61/doc/tooltip b/examples/step-61/doc/tooltip new file mode 100644 index 000000000000..1f69a0606122 --- /dev/null +++ b/examples/step-61/doc/tooltip @@ -0,0 +1 @@ +Weak Galerkin method applied to the Poisson equation diff --git a/examples/step-61/step-61.cc b/examples/step-61/step-61.cc new file mode 100644 index 000000000000..331876650fb4 --- /dev/null +++ b/examples/step-61/step-61.cc @@ -0,0 +1,965 @@ +/* --------------------------------------------------------------------- + * + * Copyright (C) 2018 by the deal.II authors + * + * This file is part of the deal.II library. + * + * The deal.II library is free software; you can use it, redistribute + * it, and/or modify it under the terms of the GNU Lesser General + * Public License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * The full text of the license can be found in the file LICENSE.md at + * the top level directory of deal.II. + * + * --------------------------------------------------------------------- + + * Author: Zhuoran Wang, Colorado State University, 2018 + */ + +// @sect3{Include files} +// This program is based on step-7, step-20 and step-51, +// so most of the following header files are familiar. We +// need the following: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +// Our first step, as always, is to put everything related to this tutorial +// program into its own namespace: +namespace Step61 +{ + using namespace dealii; + + // @sect3{The WGDarcyEquation class template} + + // We will solve for the numerical pressure in the interior and on faces and + // calculate its $L_2$ error of pressure. In the post-processing step, we will + // calculate $L_2$-errors of velocity and flux. + template + class WGDarcyEquation + { + public: + WGDarcyEquation(); + void run(); + + private: + void make_grid(); + void setup_system(); + void assemble_system(); + void solve(); + void postprocess(); + void process_solution(); + void output_results() const; + + Triangulation triangulation; + + AffineConstraints constraints; + + FE_RaviartThomas fe_rt; + DoFHandler dof_handler_rt; + + // The finite element system is used for interior and face solutions. + FESystem fe; + DoFHandler dof_handler; + + SparsityPattern sparsity_pattern; + SparseMatrix system_matrix; + + Vector solution; + Vector system_rhs; + }; + + // @sect3{Right hand side, boundary values, and exact solution} + + // Next, we define the coefficient matrix $\mathbf{K}$, + // Dirichlet boundary conditions, the right-hand side $f = 2\pi^2 \sin(\pi x) + // \sin(\pi y)$, and the reference solutions $p = \sin(\pi x) \sin(\pi y) $. + // + // The coefficient matrix $\mathbf{K}$ is the identity matrix as a test + // example. + template + class Coefficient : public TensorFunction<2, dim> + { + public: + Coefficient() + : TensorFunction<2, dim>() + {} + + virtual void value_list(const std::vector> &points, + std::vector> &values) const override; + }; + + template + void Coefficient::value_list(const std::vector> &points, + std::vector> & values) const + { + Assert(points.size() == values.size(), + ExcDimensionMismatch(points.size(), values.size())); + for (unsigned int p = 0; p < points.size(); ++p) + { + values[p].clear(); + for (unsigned int d = 0; d < dim; ++d) + values[p][d][d] = 1; + } + } + + template + class BoundaryValues : public Function + { + public: + BoundaryValues() + : Function(2) + {} + + virtual double value(const Point & p, + const unsigned int component = 0) const override; + }; + + template + double BoundaryValues::value(const Point & /*p*/, + const unsigned int /*component*/) const + { + return 0; + } + + template + class RightHandSide : public Function + { + public: + RightHandSide() + : Function() + {} + + virtual double value(const Point & p, + const unsigned int component = 0) const override; + }; + + template + double RightHandSide::value(const Point &p, + const unsigned int /*component*/) const + { + double return_value = 0.0; + return_value = 2 * M_PI * M_PI * sin(M_PI * p[0]) * sin(M_PI * p[1]); + return return_value; + } + + template + class Solution : public Function + { + public: + Solution() + : Function(1) + {} + + virtual double value(const Point &p, + const unsigned int) const override; + }; + + template + double Solution::value(const Point &p, const unsigned int) const + { + double return_value = 0; + return_value = sin(M_PI * p[0]) * sin(M_PI * p[1]); + return return_value; + } + + template + class Velocity : public TensorFunction<1, dim> + { + public: + Velocity() + : TensorFunction<1, dim>() + {} + + virtual Tensor<1, dim> value(const Point &p) const override; + }; + + template + Tensor<1, dim> Velocity::value(const Point &p) const + { + Tensor<1, dim> return_value; + return_value[0] = -M_PI * cos(M_PI * p[0]) * sin(M_PI * p[1]); + return_value[1] = -M_PI * sin(M_PI * p[0]) * cos(M_PI * p[1]); + return return_value; + } + + // @sect3{WGDarcyEquation class implementation} + + // @sect4{WGDarcyEquation::WGDarcyEquation} + + // In this constructor, we create a finite element space for vector valued + // functions, FE_RaviartThomas. We will need shape functions in + // this space to approximate discrete weak gradients. + + // FESystem defines finite element spaces in the interior and on + // edges of elements. Each of them gets an individual component. Others are + // the same as previous tutorial programs. + template + WGDarcyEquation::WGDarcyEquation() + : fe_rt(0) + , dof_handler_rt(triangulation) + , + + fe(FE_DGQ(0), 1, FE_FaceQ(0), 1) + , dof_handler(triangulation) + + {} + + // @sect4{WGDarcyEquation::make_grid} + + // We generate a mesh on the unit square domain and refine it. + + template + void WGDarcyEquation::make_grid() + { + GridGenerator::hyper_cube(triangulation, 0, 1); + triangulation.refine_global(1); + + std::cout << " Number of active cells: " << triangulation.n_active_cells() + << std::endl + << " Total number of cells: " << triangulation.n_cells() + << std::endl; + } + + // @sect4{WGDarcyEquation::setup_system} + + // After we create the mesh, we distribute degrees of freedom for the two + // DoFHandler objects. + + template + void WGDarcyEquation::setup_system() + { + dof_handler_rt.distribute_dofs(fe_rt); + dof_handler.distribute_dofs(fe); + + std::cout << " Number of flux degrees of freedom: " + << dof_handler_rt.n_dofs() << std::endl; + + std::cout << " Number of pressure degrees of freedom: " + << dof_handler.n_dofs() << std::endl; + + solution.reinit(dof_handler.n_dofs()); + system_rhs.reinit(dof_handler.n_dofs()); + + { + constraints.clear(); + FEValuesExtractors::Scalar face(1); + ComponentMask face_pressure_mask = fe.component_mask(face); + VectorTools::interpolate_boundary_values( + dof_handler, 0, BoundaryValues(), constraints, face_pressure_mask); + constraints.close(); + } + + + // In the bilinear form, there is no integration term over faces + // between two neighboring cells, so we can just use + // DoFTools::make_sparsity_pattern to calculate the sparse + // matrix. + DynamicSparsityPattern dsp(dof_handler.n_dofs()); + DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints); + sparsity_pattern.copy_from(dsp); + + system_matrix.reinit(sparsity_pattern); + + // solution.reinit(dof_handler.n_dofs()); + // system_rhs.reinit(dof_handler.n_dofs()); + } + + // @sect4{WGDarcyEquation::assemble_system} + + // First, we create quadrature points and FEValue objects for + // cells and faces. Then we allocate space for all cell matrices and the + // right-hand side vector. The following definitions have been explained in + // previous tutorials. + template + void WGDarcyEquation::assemble_system() + { + QGauss quadrature_formula(fe_rt.degree + 1); + QGauss face_quadrature_formula(fe_rt.degree + 1); + const RightHandSide right_hand_side; + + // We define objects to evaluate values and + // gradients of shape functions at the quadrature points. + // Since we need shape functions and normal vectors on faces, we need + // FEFaceValues. + FEValues fe_values_rt(fe_rt, + quadrature_formula, + update_values | update_gradients | + update_quadrature_points | update_JxW_values); + + FEValues fe_values(fe, + quadrature_formula, + update_values | update_quadrature_points | + update_JxW_values); + + FEFaceValues fe_face_values(fe, + face_quadrature_formula, + update_values | update_normal_vectors | + update_quadrature_points | + update_JxW_values); + + FEFaceValues fe_face_values_rt(fe_rt, + face_quadrature_formula, + update_values | update_normal_vectors | + update_quadrature_points | + update_JxW_values); + + + const unsigned int dofs_per_cell_rt = fe_rt.dofs_per_cell; + const unsigned int dofs_per_cell = fe.dofs_per_cell; + + const unsigned int n_q_points = fe_values.get_quadrature().size(); + const unsigned int n_q_points_rt = fe_values_rt.get_quadrature().size(); + const unsigned int n_face_q_points = fe_face_values.get_quadrature().size(); + + std::vector local_dof_indices(dofs_per_cell); + + // We will construct these cell matrices to solve for the pressure. + FullMatrix cell_matrix_rt(dofs_per_cell_rt, dofs_per_cell_rt); + FullMatrix cell_matrix_F(dofs_per_cell, dofs_per_cell_rt); + FullMatrix cell_matrix_C(dofs_per_cell, dofs_per_cell_rt); + FullMatrix local_matrix(dofs_per_cell, dofs_per_cell); + Vector cell_rhs(dofs_per_cell); + Vector cell_solution(dofs_per_cell); + + const Coefficient coefficient; + std::vector> coefficient_values(n_q_points_rt); + + // We need FEValuesExtractors to access the @p interior and + // @p face component of the FESystem shape functions. + const FEValuesExtractors::Vector velocities(0); + const FEValuesExtractors::Scalar interior(0); + const FEValuesExtractors::Scalar face(1); + + typename DoFHandler::active_cell_iterator cell = + dof_handler.begin_active(), + endc = dof_handler.end(); + typename DoFHandler::active_cell_iterator cell_rt = + dof_handler_rt.begin_active(); + + // Here, we will calculate cell matrices used to construct the local matrix + // on each cell. We need shape functions for the Raviart-Thomas space as + // well, so we also loop over the corresponding velocity cell iterators. + for (; cell != endc; ++cell, ++cell_rt) + { + // On each cell, cell matrices are different, so in every loop, they + // need to be re-computed. + fe_values_rt.reinit(cell_rt); + fe_values.reinit(cell); + coefficient.value_list(fe_values_rt.get_quadrature_points(), + coefficient_values); + + // This cell matrix is the mass matrix for the Raviart-Thomas space. + // Hence, we need to loop over all the quadrature points + // for the velocity FEValues object. + cell_matrix_rt = 0; + for (unsigned int q = 0; q < n_q_points_rt; ++q) + { + for (unsigned int i = 0; i < dofs_per_cell_rt; ++i) + { + const Tensor<1, dim> phi_i_u = + fe_values_rt[velocities].value(i, q); + for (unsigned int j = 0; j < dofs_per_cell_rt; ++j) + { + const Tensor<1, dim> phi_j_u = + fe_values_rt[velocities].value(j, q); + cell_matrix_rt(i, j) += + (phi_i_u * phi_j_u * fe_values_rt.JxW(q)); + } + } + } + // Next we take the inverse of this matrix by using + // gauss_jordan(). It will be used to calculate the + // coefficient matrix later. + cell_matrix_rt.gauss_jordan(); + + // From the introduction, we know that the right hand side + // is the difference between a face integral and a cell integral. + // Here, we approximate the negative of the contribution in the + // interior. Each component of this matrix is the integral of a product + // between a basis function of the polynomial space and the divergence + // of a basis function of the Raviart-Thomas space. These basis + // functions are defined in the interior. + cell_matrix_F = 0; + for (unsigned int q = 0; q < n_q_points; ++q) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + for (unsigned int k = 0; k < dofs_per_cell_rt; ++k) + { + const double phi_k_u_div = + fe_values_rt[velocities].divergence(k, q); + cell_matrix_F(i, k) -= (fe_values[interior].value(i, q) * + phi_k_u_div * fe_values.JxW(q)); + } + } + } + + // Now, we approximate the integral on faces. + // Each component is the integral of a product between a basis function + // of the polynomial space and the dot product of a basis function of + // the Raviart-Thomas space and the normal vector. So we loop over all + // the faces of the element and obtain the normal vector. + for (unsigned int face_n = 0; + face_n < GeometryInfo::faces_per_cell; + ++face_n) + { + fe_face_values.reinit(cell, face_n); + fe_face_values_rt.reinit(cell_rt, face_n); + for (unsigned int q = 0; q < n_face_q_points; ++q) + { + const Tensor<1, dim> normal = fe_face_values.normal_vector(q); + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + for (unsigned int k = 0; k < dofs_per_cell_rt; ++k) + { + const Tensor<1, dim> phi_k_u = + fe_face_values_rt[velocities].value(k, q); + cell_matrix_F(i, k) += + (fe_face_values[face].value(i, q) * + (phi_k_u * normal) * fe_face_values.JxW(q)); + } + } + } + } + + // @p cell_matrix_C is matrix product between the inverse of mass matrix @p cell_matrix_rt and @p cell_matrix_F. + cell_matrix_C = 0; + cell_matrix_F.mmult(cell_matrix_C, cell_matrix_rt); + + // Element $a_{ij}$ of the local cell matrix $A$ is given by + // $\int_{E} \sum_{k,l} c_{ik} c_{jl} (\mathbf{K} \mathbf{w}_k) \cdot + // \mathbf{w}_l \mathrm{d}x.$ We have calculated coefficients $c$ in the + // previous step. + local_matrix = 0; + for (unsigned int q = 0; q < n_q_points_rt; ++q) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + for (unsigned int j = 0; j < dofs_per_cell; ++j) + { + for (unsigned int k = 0; k < dofs_per_cell_rt; ++k) + { + const Tensor<1, dim> phi_k_u = + fe_values_rt[velocities].value(k, q); + for (unsigned int l = 0; l < dofs_per_cell_rt; ++l) + { + const Tensor<1, dim> phi_l_u = + fe_values_rt[velocities].value(l, q); + local_matrix(i, j) += + coefficient_values[q] * cell_matrix_C[i][k] * + phi_k_u * cell_matrix_C[j][l] * phi_l_u * + fe_values_rt.JxW(q); + } + } + } + } + } + + // Next, we calculate the right hand side, $\int_{E} f q \mathrm{d}x$. + cell_rhs = 0; + for (unsigned int q = 0; q < n_q_points; ++q) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + cell_rhs(i) += + (fe_values[interior].value(i, q) * + right_hand_side.value(fe_values.quadrature_point(q)) * + fe_values.JxW(q)); + } + } + + // In this part, we distribute components of this local matrix into the + // system matrix and transfer components of the cell right-hand side + // into the system right hand side. + cell->get_dof_indices(local_dof_indices); + constraints.distribute_local_to_global( + local_matrix, cell_rhs, local_dof_indices, system_matrix, system_rhs); + } + } + + // @sect4{WGDarcyEquation::solve} + + // Solving the system of the Darcy equation. Now, we have pressures in the + // interior and on the faces of all the cells. + template + void WGDarcyEquation::solve() + { + SolverControl solver_control(1000, 1e-8 * system_rhs.l2_norm()); + SolverCG<> solver(solver_control); + solver.solve(system_matrix, solution, system_rhs, PreconditionIdentity()); + constraints.distribute(solution); + } + + // @sect4{WGDarcyEquation::process_solution} + + // This part is to calculate the $L_2$ error of the pressure. + template + void WGDarcyEquation::process_solution() + { + // Since we have two different spaces for finite elements in interior and on + // faces, if we want to calculate $L_2$ errors in interior, we need degrees + // of freedom only defined in cells. In FESystem, we have two + // components, the first one is for interior, the second one is for + // skeletons. fe.base_element(0) shows we only need degrees of + // freedom defined in cells. + DoFHandler interior_dof_handler(triangulation); + interior_dof_handler.distribute_dofs(fe.base_element(0)); + // We define a vector to extract pressures in cells. + // The size of the vector is the collective number of all degrees of freedom + // in the interior of all the elements. + Vector interior_solution(interior_dof_handler.n_dofs()); + { + // types::global_dof_index is used to know the global indices + // of degrees of freedom. So here, we get the global indices of local + // degrees of freedom and the global indices of interior degrees of + // freedom. + std::vector local_dof_indices(fe.dofs_per_cell); + std::vector interior_local_dof_indices( + fe.base_element(0).dofs_per_cell); + typename DoFHandler::active_cell_iterator + cell = dof_handler.begin_active(), + endc = dof_handler.end(), + interior_cell = interior_dof_handler.begin_active(); + + // In the loop of all cells and interior of the cell, + // we extract interior solutions from the global solution. + for (; cell != endc; ++cell, ++interior_cell) + { + cell->get_dof_indices(local_dof_indices); + interior_cell->get_dof_indices(interior_local_dof_indices); + + for (unsigned int i = 0; i < fe.base_element(0).dofs_per_cell; ++i) + interior_solution(interior_local_dof_indices[i]) = + solution(local_dof_indices[fe.component_to_system_index(0, i)]); + } + } + + // We define a vector that holds the norm of the error on each cell. + // Next, we use VectorTool::integrate_difference + // to compute the error in the $L_2$ norm on each cell. + // Finally, we get the global $L_2$ norm. + Vector difference_per_cell(triangulation.n_active_cells()); + VectorTools::integrate_difference(interior_dof_handler, + interior_solution, + Solution(), + difference_per_cell, + QGauss(fe.degree + 2), + VectorTools::L2_norm); + + const double L2_error = difference_per_cell.l2_norm(); + std::cout << "L2_error_pressure " << L2_error << std::endl; + } + + // @sect4{WGDarcyEquation::postprocess} + + // After we calculated the numerical pressure, we evaluate $L_2$ errors for + // the velocity on each cell and $L_2$ errors for the flux on faces. + + // We are going to evaluate velocities on each cell and calculate the + // difference between numerical and exact velocities. To calculate velocities, + // we need interior and face pressure values of each element, and some other + // cell matrices. + + template + void WGDarcyEquation::postprocess() + { + QGauss quadrature_formula(fe_rt.degree + 1); + QGauss face_quadrature_formula(fe_rt.degree + 1); + + FEValues fe_values_rt(fe_rt, + quadrature_formula, + update_values | update_gradients | + update_quadrature_points | update_JxW_values); + + FEValues fe_values(fe, + quadrature_formula, + update_values | update_quadrature_points | + update_JxW_values); + + FEFaceValues fe_face_values(fe, + face_quadrature_formula, + update_values | update_normal_vectors | + update_quadrature_points | + update_JxW_values); + + FEFaceValues fe_face_values_rt(fe_rt, + face_quadrature_formula, + update_values | update_normal_vectors | + update_quadrature_points | + update_JxW_values); + + const unsigned int dofs_per_cell_rt = fe_rt.dofs_per_cell; + const unsigned int dofs_per_cell = fe.dofs_per_cell; + + const unsigned int n_q_points_rt = fe_values_rt.get_quadrature().size(); + const unsigned int n_q_points = fe_values.get_quadrature().size(); + const unsigned int n_face_q_points = fe_face_values.get_quadrature().size(); + const unsigned int n_face_q_points_rt = + fe_face_values_rt.get_quadrature().size(); + + + std::vector local_dof_indices(dofs_per_cell); + FullMatrix cell_matrix_rt(dofs_per_cell_rt, dofs_per_cell_rt); + FullMatrix cell_matrix_F(dofs_per_cell, dofs_per_cell_rt); + FullMatrix cell_matrix_C(dofs_per_cell, dofs_per_cell_rt); + FullMatrix local_matrix(dofs_per_cell, dofs_per_cell); + FullMatrix cell_matrix_D(dofs_per_cell_rt, dofs_per_cell_rt); + FullMatrix cell_matrix_E(dofs_per_cell_rt, dofs_per_cell_rt); + Vector cell_rhs(dofs_per_cell); + Vector cell_solution(dofs_per_cell); + Tensor<1, dim> velocity_cell; + Tensor<1, dim> velocity_face; + Tensor<1, dim> exact_velocity_face; + double L2_err_velocity_cell_sqr_global; + L2_err_velocity_cell_sqr_global = 0; + double L2_err_flux_sqr; + L2_err_flux_sqr = 0; + + typename DoFHandler::active_cell_iterator cell = + dof_handler.begin_active(), + endc = dof_handler.end(); + + typename DoFHandler::active_cell_iterator cell_rt = + dof_handler_rt.begin_active(); + + const Coefficient coefficient; + std::vector> coefficient_values(n_q_points_rt); + const FEValuesExtractors::Vector velocities(0); + const FEValuesExtractors::Scalar pressure(dim); + const FEValuesExtractors::Scalar interior(0); + const FEValuesExtractors::Scalar face(1); + + Velocity exact_velocity; + + // In the loop over all cells, we will calculate $L_2$ errors of velocity + // and flux. + + // First, we calculate the $L_2$ velocity error. + // In the introduction, we explained how to calculate the numerical velocity + // on the cell. We need the pressure solution values on each cell, + // coefficients of the Gram matrix and coefficients of the $L_2$ projection. + // We have already calculated the global solution, so we will extract the + // cell solution from the global solution. The coefficients of the Gram + // matrix have been calculated when we assembled the system matrix for the + // pressures. We will do the same way here. For the coefficients of the + // projection, we do matrix multiplication, i.e., the inverse of the Gram + // matrix times the matrix with $(\mathbf{K} \mathbf{w}, \mathbf{w})$ as + // components. Then, we multiply all these coefficients and call them beta. + // The numerical velocity is the product of beta and the basis functions of + // the Raviart-Thomas space. + for (; cell != endc; ++cell, ++cell_rt) + { + fe_values_rt.reinit(cell_rt); + fe_values.reinit(cell); + coefficient.value_list(fe_values_rt.get_quadrature_points(), + coefficient_values); + + // The component of this cell_matrix_E is the integral of + // $(\mathbf{K} \mathbf{w}, \mathbf{w})$. cell_matrix_rt is + // the Gram matrix. + cell_matrix_E = 0; + cell_matrix_rt = 0; + for (unsigned int q = 0; q < n_q_points_rt; ++q) + { + for (unsigned int i = 0; i < dofs_per_cell_rt; ++i) + { + const Tensor<1, dim> phi_i_u = + fe_values_rt[velocities].value(i, q); + + for (unsigned int j = 0; j < dofs_per_cell_rt; ++j) + { + const Tensor<1, dim> phi_j_u = + fe_values_rt[velocities].value(j, q); + + cell_matrix_E(i, j) += (coefficient_values[q] * phi_j_u * + phi_i_u * fe_values_rt.JxW(q)); + cell_matrix_rt(i, j) += + (phi_i_u * phi_j_u * fe_values_rt.JxW(q)); + } + } + } + + // We take the inverse of the Gram matrix, take matrix multiplication + // and get the matrix with coefficients of projection. + cell_matrix_D = 0; + cell_matrix_rt.gauss_jordan(); + cell_matrix_rt.mmult(cell_matrix_D, cell_matrix_E); + + // This cell matrix will be used to calculate the coefficients of the + // Gram matrix. This part is the same as the part in evaluating + // pressure. + cell_matrix_F = 0; + for (unsigned int q = 0; q < n_q_points; ++q) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + for (unsigned int k = 0; k < dofs_per_cell_rt; ++k) + { + const double phi_k_u_div = + fe_values_rt[velocities].divergence(k, q); + cell_matrix_F(i, k) -= (fe_values[interior].value(i, q) * + phi_k_u_div * fe_values.JxW(q)); + } + } + } + + for (unsigned int face_n = 0; + face_n < GeometryInfo::faces_per_cell; + ++face_n) + { + fe_face_values.reinit(cell, face_n); + fe_face_values_rt.reinit(cell_rt, face_n); + for (unsigned int q = 0; q < n_face_q_points; ++q) + { + const Tensor<1, dim> normal = fe_face_values.normal_vector(q); + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + for (unsigned int k = 0; k < dofs_per_cell_rt; ++k) + { + const Tensor<1, dim> phi_k_u = + fe_face_values_rt[velocities].value(k, q); + cell_matrix_F(i, k) += + (fe_face_values[face].value(i, q) * + (phi_k_u * normal) * fe_face_values.JxW(q)); + } + } + } + } + cell_matrix_C = 0; + cell_matrix_F.mmult(cell_matrix_C, cell_matrix_rt); + + // This is to extract pressure values of the element. + cell->get_dof_indices(local_dof_indices); + cell_solution = 0; + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + cell_solution(i) = solution(local_dof_indices[i]); + } + + // From previous calculations we obtained all the coefficients needed to + // calculate beta. + Vector beta(dofs_per_cell_rt); + beta = 0; + for (unsigned int k = 0; k < dofs_per_cell_rt; ++k) + { + for (unsigned int j = 0; j < dofs_per_cell_rt; ++j) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + beta(k) += -(cell_solution(i) * cell_matrix_C(i, j) * + cell_matrix_D(k, j)); + } + } + } + + // Now, we can calculate the numerical velocity at each quadrature point + // and compute the $L_2$ error on each cell. + double L2_err_velocity_cell_sqr_local; + double difference_velocity_cell_sqr; + L2_err_velocity_cell_sqr_local = 0; + velocity_cell = 0; + for (unsigned int q = 0; q < n_q_points_rt; ++q) + { + difference_velocity_cell_sqr = 0; + velocity_cell = 0; + for (unsigned int k = 0; k < dofs_per_cell_rt; ++k) + { + const Tensor<1, dim> phi_k_u = + fe_values_rt[velocities].value(k, q); + velocity_cell += beta(k) * phi_k_u; + } + difference_velocity_cell_sqr = + (velocity_cell - + exact_velocity.value(fe_values_rt.quadrature_point(q))) * + (velocity_cell - + exact_velocity.value(fe_values_rt.quadrature_point(q))); + L2_err_velocity_cell_sqr_local += + difference_velocity_cell_sqr * fe_values_rt.JxW(q); + } + + L2_err_velocity_cell_sqr_global += L2_err_velocity_cell_sqr_local; + + // For reconstructing the flux we need the size of cells and faces. + // Since fluxes are calculated on faces, we have the loop over all four + // faces of each cell. To calculate face velocity, we use the + // coefficient beta we have calculated previously. Then, we calculate + // the squared velocity error in normal direction. Finally, we calculate + // $L_2$ flux error on the cell and add it to the global error. + double difference_velocity_face_sqr; + double L2_err_flux_face_sqr_local; + double err_flux_each_face; + double err_flux_face; + L2_err_flux_face_sqr_local = 0; + err_flux_face = 0; + const double cell_area = cell->measure(); + for (unsigned int face_n = 0; + face_n < GeometryInfo::faces_per_cell; + ++face_n) + { + const double face_length = cell->face(face_n)->measure(); + fe_face_values.reinit(cell, face_n); + fe_face_values_rt.reinit(cell_rt, face_n); + L2_err_flux_face_sqr_local = 0; + err_flux_each_face = 0; + for (unsigned int q = 0; q < n_face_q_points_rt; ++q) + { + difference_velocity_face_sqr = 0; + velocity_face = 0; + const Tensor<1, dim> normal = fe_face_values.normal_vector(q); + for (unsigned int k = 0; k < dofs_per_cell_rt; ++k) + { + const Tensor<1, dim> phi_k_u = + fe_face_values_rt[velocities].value(k, q); + velocity_face += beta(k) * phi_k_u; + } + exact_velocity_face = + exact_velocity.value(fe_face_values_rt.quadrature_point(q)); + difference_velocity_face_sqr = + (velocity_face * normal - exact_velocity_face * normal) * + (velocity_face * normal - exact_velocity_face * normal); + L2_err_flux_face_sqr_local += + difference_velocity_face_sqr * fe_face_values_rt.JxW(q); + } + err_flux_each_face = + L2_err_flux_face_sqr_local / (face_length) * (cell_area); + err_flux_face += err_flux_each_face; + } + L2_err_flux_sqr += err_flux_face; + } + + // After adding up errors over all cells, we take square root and get the + // $L_2$ errors of velocity and flux. + const double L2_err_velocity_cell = + std::sqrt(L2_err_velocity_cell_sqr_global); + std::cout << "L2_error_vel " << L2_err_velocity_cell << std::endl; + const double L2_err_flux_face = std::sqrt(L2_err_flux_sqr); + std::cout << "L2_error_flux " << L2_err_flux_face << std::endl; + } + + + // @sect4{WGDarcyEquation::output_results} + + // We have 2 sets of results to output: the interior solution + // and the skeleton solution. We use DataOut to visualize + // interior results. The graphical output for the skeleton results is done by + // using the DataOutFaces class. + template + void WGDarcyEquation::output_results() const + { + DataOut data_out; + data_out.attach_dof_handler(dof_handler); + data_out.add_data_vector(solution, "Pressure_Interior"); + data_out.build_patches(fe.degree); + std::ofstream output("Pressure_Interior.vtk"); + data_out.write_vtk(output); + + DataOutFaces data_out_face(false); + std::vector + face_component_type(2, DataComponentInterpretation::component_is_scalar); + data_out_face.add_data_vector(dof_handler, + solution, + "Pressure_Edge", + face_component_type); + data_out_face.build_patches(fe.degree); + std::ofstream face_output("Pressure_Edge.vtk"); + data_out_face.write_vtk(face_output); + } + + + // @sect4{WGDarcyEquation::run} + + // This is the final function of the main class. It calls the other functions + // of our class. + template + void WGDarcyEquation::run() + { + std::cout << "Solving problem in " << dim << " space dimensions." + << std::endl; + make_grid(); + setup_system(); + assemble_system(); + solve(); + process_solution(); + postprocess(); + output_results(); + } + +} // namespace Step61 + + +// @sect3{The main function} + +// This is the main function. We can change the dimension here to run in 3d. +int main() +{ + try + { + dealii::deallog.depth_console(2); + Step61::WGDarcyEquation<2> wg_darcy; + wg_darcy.run(); + } + catch (std::exception &exc) + { + std::cerr << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on processing: " << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + } + catch (...) + { + std::cerr << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + } + + return 0; +} diff --git a/examples/step-63/CMakeLists.txt b/examples/step-63/CMakeLists.txt new file mode 100644 index 000000000000..476f55c11e5c --- /dev/null +++ b/examples/step-63/CMakeLists.txt @@ -0,0 +1,39 @@ +## +# CMake script for the step-63 tutorial program: +## + +# Set the name of the project and target: +SET(TARGET "step-63") + +# Declare all source files the target consists of. Here, this is only +# the one step-X.cc file, but as you expand your project you may wish +# to add other source files as well. If your project becomes much larger, +# you may want to either replace the following statement by something like +# FILE(GLOB_RECURSE TARGET_SRC "source/*.cc") +# FILE(GLOB_RECURSE TARGET_INC "include/*.h") +# SET(TARGET_SRC ${TARGET_SRC} ${TARGET_INC}) +# or switch altogether to the large project CMakeLists.txt file discussed +# in the "CMake in user projects" page accessible from the "User info" +# page of the documentation. +SET(TARGET_SRC + ${TARGET}.cc + ) + +# Usually, you will not need to modify anything beyond this point... + +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) + +FIND_PACKAGE(deal.II 9.1.0 QUIET + HINTS ${deal.II_DIR} ${DEAL_II_DIR} ../ ../../ $ENV{DEAL_II_DIR} + ) +IF(NOT ${deal.II_FOUND}) + MESSAGE(FATAL_ERROR "\n" + "*** Could not locate a (sufficiently recent) version of deal.II. ***\n\n" + "You may want to either pass a flag -DDEAL_II_DIR=/path/to/deal.II to cmake\n" + "or set an environment variable \"DEAL_II_DIR\" that contains this path." + ) +ENDIF() + +DEAL_II_INITIALIZE_CACHED_VARIABLES() +PROJECT(${TARGET}) +DEAL_II_INVOKE_AUTOPILOT() diff --git a/examples/step-63/block_jacobi.prm b/examples/step-63/block_jacobi.prm new file mode 100644 index 000000000000..9e6f98326eaa --- /dev/null +++ b/examples/step-63/block_jacobi.prm @@ -0,0 +1,14 @@ +# Finite Element degree +set Fe degree = 1 + +# Smoother Type: SOR|Jacobi|block SOR|block Jacobi +set Smoother type = block Jacobi + +# DoF renumbering: no|downstream|upstream|random +set DoF renumbering = downstream + +# With streamline diffusion: true|false +set With streamline diffusion = true + +# Output: true|false +set Output = false diff --git a/examples/step-63/block_sor.prm b/examples/step-63/block_sor.prm new file mode 100644 index 000000000000..375e7e63cb32 --- /dev/null +++ b/examples/step-63/block_sor.prm @@ -0,0 +1,14 @@ +# Finite Element degree +set Fe degree = 1 + +# Smoother Type: SOR|Jacobi|block SOR|block Jacobi +set Smoother type = block SOR + +# DoF renumbering: no|downstream|upstream|random +set DoF renumbering = downstream + +# With streamline diffusion: true|false +set With streamline diffusion = true + +# Output: true|false +set Output = false \ No newline at end of file diff --git a/examples/step-63/doc/builds-on b/examples/step-63/doc/builds-on new file mode 100644 index 000000000000..42c284692101 --- /dev/null +++ b/examples/step-63/doc/builds-on @@ -0,0 +1 @@ +step-16 diff --git a/examples/step-63/doc/intro.dox b/examples/step-63/doc/intro.dox new file mode 100644 index 000000000000..4b90b10a306e --- /dev/null +++ b/examples/step-63/doc/intro.dox @@ -0,0 +1,9 @@ +
    + +This program was contributed by Thomas Clevenger and Timo Heister. + + +

    Introduction

    + +Please note: This is work in progress and will be an example for block +smoothers in geometric multigrid. diff --git a/examples/step-63/doc/kind b/examples/step-63/doc/kind new file mode 100644 index 000000000000..6816e9090f56 --- /dev/null +++ b/examples/step-63/doc/kind @@ -0,0 +1 @@ +unfinished diff --git a/examples/step-63/doc/results.dox b/examples/step-63/doc/results.dox new file mode 100644 index 000000000000..b5eaba9377b6 --- /dev/null +++ b/examples/step-63/doc/results.dox @@ -0,0 +1,2 @@ +

    Results

    + diff --git a/examples/step-63/doc/tooltip b/examples/step-63/doc/tooltip new file mode 100644 index 000000000000..9aad4b39bba7 --- /dev/null +++ b/examples/step-63/doc/tooltip @@ -0,0 +1 @@ +Block smoothers for Geometric Multigrid. diff --git a/examples/step-63/jacobi.prm b/examples/step-63/jacobi.prm new file mode 100644 index 000000000000..4c7365e06a7d --- /dev/null +++ b/examples/step-63/jacobi.prm @@ -0,0 +1,14 @@ +# Finite Element degree +set Fe degree = 1 + +# Smoother Type: SOR|Jacobi|block SOR|block Jacobi +set Smoother type = Jacobi + +# DoF renumbering: no|downstream|upstream|random +set DoF renumbering = downstream + +# With streamline diffusion: true|false +set With streamline diffusion = true + +# Output: true|false +set Output = false \ No newline at end of file diff --git a/examples/step-63/sor.prm b/examples/step-63/sor.prm new file mode 100644 index 000000000000..dbdc74c19810 --- /dev/null +++ b/examples/step-63/sor.prm @@ -0,0 +1,14 @@ +# Finite Element degree +set Fe degree = 1 + +# Smoother Type: SOR|Jacobi|block SOR|block Jacobi +set Smoother type = SOR + +# DoF renumbering: no|downstream|upstream|random +set DoF renumbering = downstream + +# With streamline diffusion: true|false +set With streamline diffusion = true + +# Output: true|false +set Output = false \ No newline at end of file diff --git a/examples/step-63/step-63.cc b/examples/step-63/step-63.cc new file mode 100644 index 000000000000..5b906c97ff31 --- /dev/null +++ b/examples/step-63/step-63.cc @@ -0,0 +1,1077 @@ +/* --------------------------------------------------------------------- + * + * Copyright (C) 2018 - 2019 by the deal.II authors + * + * This file is part of the deal.II library. + * + * The deal.II library is free software; you can use it, redistribute + * it, and/or modify it under the terms of the GNU Lesser General + * Public License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * The full text of the license can be found in the file LICENSE.md at + * the top level directory of deal.II. + * + * --------------------------------------------------------------------- + * + * Authors: Thomas Clevenger, Clemson University + * Timo Heister, University of Utah + */ + +// @note: This is work in progress and will be an example for block smoothers +// in geometric multigrid. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace Step63 +{ + using namespace dealii; + + + template + struct ScratchData + { + ScratchData(const FiniteElement &fe, + const unsigned int quadrature_degree) + : fe_values(fe, + QGauss(quadrature_degree), + update_values | update_gradients | update_hessians | + update_quadrature_points | update_JxW_values) + {} + + ScratchData(const ScratchData &scratch_data) + : fe_values(scratch_data.fe_values.get_fe(), + scratch_data.fe_values.get_quadrature(), + update_values | update_gradients | update_hessians | + update_quadrature_points | update_JxW_values) + {} + + FEValues fe_values; + }; + + + + struct CopyData + { + CopyData() = default; + + unsigned int level; + unsigned int dofs_per_cell; + + FullMatrix cell_matrix; + Vector cell_rhs; + std::vector local_dof_indices; + }; + + + struct Settings + { + enum DoFRenumberingStrategy + { + none, + downstream, + upstream, + random + }; + + void get_parameters(const std::string &prm_filename); + + unsigned int fe_degree; + std::string smoother_type; + DoFRenumberingStrategy dof_renumbering; + bool with_streamline_diffusion; + bool output; + }; + + void Settings::get_parameters(const std::string &prm_filename) + { + ParameterHandler prm; + + prm.declare_entry("Fe degree", + "1", + Patterns::Integer(0), + "Finite Element degree"); + prm.declare_entry("Smoother type", + "block SOR", + Patterns::Selection("sor|Jacobi|block SOR|block Jacobi"), + "Smoother Type: SOR|Jacobi|block SOR|block Jacobi"); + prm.declare_entry("DoF renumbering", + "downstream", + Patterns::Selection("none|downstream|upstream|random"), + "DoF renumbering: none|downstream|upstream|random"); + prm.declare_entry("With streamline diffusion", + "true", + Patterns::Bool(), + "With streamline diffusion: true|false"); + prm.declare_entry("Output", + "true", + Patterns::Bool(), + "Generate graphical output: true|false"); + + if (prm_filename.size() == 0) + { + prm.print_parameters(std::cout, ParameterHandler::Text); + AssertThrow( + false, ExcMessage("please pass a .prm file as the first argument!")); + } + + prm.parse_input(prm_filename); + + fe_degree = prm.get_integer("Fe degree"); + smoother_type = prm.get("Smoother type"); + + std::string renumbering = prm.get("DoF renumbering"); + if (renumbering == "none") + dof_renumbering = DoFRenumberingStrategy::none; + else if (renumbering == "downstream") + dof_renumbering = DoFRenumberingStrategy::downstream; + else if (renumbering == "upstream") + dof_renumbering = DoFRenumberingStrategy::upstream; + else if (renumbering == "random") + dof_renumbering = DoFRenumberingStrategy::random; + + with_streamline_diffusion = prm.get_bool("With streamline diffusion"); + output = prm.get_bool("Output"); + } + + + // Functions for creating permutation of cells for output and Block + // smoothers + template + std::vector + create_downstream_cell_ordering(const DoFHandler &dof, + const Tensor<1, dim> direction, + const unsigned int level) + { + std::vector::level_cell_iterator> ordered_cells; + ordered_cells.reserve(dof.get_triangulation().n_cells(level)); + const DoFRenumbering:: + CompareDownstream::level_cell_iterator, dim> + comparator(direction); + + typename DoFHandler::level_cell_iterator cell = dof.begin(level); + typename DoFHandler::level_cell_iterator endc = dof.end(level); + for (; cell != endc; ++cell) + ordered_cells.push_back(cell); + + std::sort(ordered_cells.begin(), ordered_cells.end(), comparator); + + std::vector ordered_indices; + ordered_indices.reserve(dof.get_triangulation().n_cells(level)); + + for (unsigned int i = 0; i < ordered_cells.size(); ++i) + ordered_indices.push_back(ordered_cells[i]->index()); + + return ordered_indices; + } + + template + std::vector + create_downstream_cell_ordering(const DoFHandler &dof, + const Tensor<1, dim> direction) + { + std::vector::active_cell_iterator> ordered_cells; + ordered_cells.reserve(dof.get_triangulation().n_active_cells()); + const DoFRenumbering:: + CompareDownstream::active_cell_iterator, dim> + comparator(direction); + + typename DoFHandler::active_cell_iterator cell = dof.begin_active(); + typename DoFHandler::active_cell_iterator endc = dof.end(); + for (; cell != endc; ++cell) + ordered_cells.push_back(cell); + + std::sort(ordered_cells.begin(), ordered_cells.end(), comparator); + + std::vector ordered_indices; + ordered_indices.reserve(dof.get_triangulation().n_active_cells()); + + for (unsigned int i = 0; i < ordered_cells.size(); ++i) + ordered_indices.push_back(ordered_cells[i]->index()); + + return ordered_indices; + } + + + + template + std::vector + create_random_cell_ordering(const DoFHandler &dof, + const unsigned int level) + { + const unsigned int n_cells = dof.get_triangulation().n_cells(level); + + std::vector ordered_cells; + ordered_cells.reserve(n_cells); + + typename DoFHandler::cell_iterator cell = dof.begin(level); + typename DoFHandler::cell_iterator endc = dof.end(level); + for (; cell != endc; ++cell) + ordered_cells.push_back(cell->index()); + + // shuffle the elements + std::mt19937 random_number_generator; + for (unsigned int i = 1; i < n_cells; ++i) + { + // get a random number between 0 and i (inclusive) + const unsigned int j = + std::uniform_int_distribution<>(0, i)(random_number_generator); + + // if possible, swap the elements + if (i != j) + std::swap(ordered_cells[i], ordered_cells[j]); + } + + return ordered_cells; + } + + template + std::vector + create_random_cell_ordering(const DoFHandler &dof) + { + const unsigned int n_cells = dof.get_triangulation().n_active_cells(); + + std::vector ordered_cells; + ordered_cells.reserve(n_cells); + + typename DoFHandler::active_cell_iterator cell = dof.begin_active(); + typename DoFHandler::active_cell_iterator endc = dof.end(); + for (; cell != endc; ++cell) + ordered_cells.push_back(cell->index()); + + // shuffle the elements + std::mt19937 random_number_generator; + for (unsigned int i = 1; i < n_cells; ++i) + { + // get a random number between 0 and i (inclusive) + const unsigned int j = + std::uniform_int_distribution<>(0, i)(random_number_generator); + + // if possible, swap the elements + if (i != j) + std::swap(ordered_cells[i], ordered_cells[j]); + } + + return ordered_cells; + } + + + + template + class RightHandSide : public Function + { + public: + RightHandSide() + : Function() + {} + + virtual double value(const Point & p, + const unsigned int component = 0) const; + + virtual void value_list(const std::vector> &points, + std::vector & values, + const unsigned int component = 0) const; + }; + + template + double RightHandSide::value(const Point & p, + const unsigned int component) const + { + Assert(component == 0, ExcIndexRange(component, 0, 1)); + (void)component; + (void)p; + + return 0.0; + } + + + + template + void RightHandSide::value_list(const std::vector> &points, + std::vector & values, + const unsigned int component) const + { + Assert(values.size() == points.size(), + ExcDimensionMismatch(values.size(), points.size())); + + for (unsigned int i = 0; i < points.size(); ++i) + values[i] = RightHandSide::value(points[i], component); + } + + + + template + class BoundaryValues : public Function + { + public: + BoundaryValues() + : Function() + {} + + virtual double value(const Point & p, + const unsigned int component = 0) const; + + virtual void value_list(const std::vector> &points, + std::vector & values, + const unsigned int component = 0) const; + }; + + + template + double BoundaryValues::value(const Point & p, + const unsigned int component) const + { + Assert(component == 0, ExcIndexRange(component, 0, 1)); + (void)component; + + if (std::fabs(p[0] - 1) < 1e-8 // x == 1 + || (std::fabs(p[1] + 1) < 1e-8 && p[0] >= 0.5) // y == -1, x > 0.5 + ) + { + return 1.0; + } + else + { + return 0.0; + } + } + + + + template + void BoundaryValues::value_list(const std::vector> &points, + std::vector & values, + const unsigned int component) const + { + Assert(values.size() == points.size(), + ExcDimensionMismatch(values.size(), points.size())); + + for (unsigned int i = 0; i < points.size(); ++i) + values[i] = BoundaryValues::value(points[i], component); + } + + template + double compute_stabilization_delta(const double hk, + const double eps, + const Tensor<1, dim> dir, + const double pk) + { + // Value defined in 'On discontinuity–capturing methods for + // convection–diffusion equations' + const double Peclet = dir.norm() * hk / (2.0 * eps * pk); + const double coth = + (1.0 + std::exp(-2.0 * Peclet)) / (1.0 - std::exp(-2.0 * Peclet)); + + return hk / (2.0 * dir.norm() * pk) * (coth - 1.0 / Peclet); + } + + + template + class AdvectionProblem + { + public: + AdvectionProblem(Settings settings); + void run(); + + private: + void setup_system(); + + template + void assemble_cell(const IteratorType &cell, + ScratchData & scratch_data, + CopyData & copy_data); + void assemble_system_and_multigrid(); + + void setup_smoother(); + + void solve(); + void refine_grid(); + void output_results(const unsigned int cycle) const; + + Triangulation triangulation; + DoFHandler dof_handler; + + const FE_Q fe; + const MappingQ mapping; + + AffineConstraints constraints; + + SparsityPattern sparsity_pattern; + SparseMatrix system_matrix; + + Vector solution; + Vector system_rhs; + + MGLevelObject mg_sparsity_patterns; + MGLevelObject mg_interface_sparsity_patterns; + + MGLevelObject> mg_matrices; + MGLevelObject> mg_interface_in; + MGLevelObject> mg_interface_out; + + mg::Matrix> mg_matrix; + mg::Matrix> mg_interface_matrix_in; + mg::Matrix> mg_interface_matrix_out; + + using SmootherType = + RelaxationBlock, double, Vector>; + using SmootherAdditionalDataType = SmootherType::AdditionalData; + std::unique_ptr>> mg_smoother; + + MGLevelObject smoother_data; + + MGConstrainedDoFs mg_constrained_dofs; + + const double epsilon; + Tensor<1, dim> advection_direction; + + const Settings settings; + }; + + + + template + AdvectionProblem::AdvectionProblem(Settings settings) + : triangulation(Triangulation::limit_level_difference_at_vertices) + , dof_handler(triangulation) + , fe(settings.fe_degree) + , mapping(settings.fe_degree) + , epsilon(0.005) + , settings(settings) + { + advection_direction[0] = -std::sin(numbers::PI / 6.0); + if (dim > 1) + advection_direction[1] = std::cos(numbers::PI / 6.0); + if (dim > 2) + advection_direction[2] = std::sin(numbers::PI / 6.0); + } + + + + template + void AdvectionProblem::setup_system() + { + const unsigned int n_levels = triangulation.n_levels(); + + dof_handler.distribute_dofs(fe); + + // We could renumber the active dofs with DoFRenumbering::downstream() + // here, but the smoothers only act on multigrid levels and as such, this + // wouldn't matter. Instead, we will renumber the DoFs on each multigrid + // level below. + + solution.reinit(dof_handler.n_dofs()); + system_rhs.reinit(dof_handler.n_dofs()); + + constraints.clear(); + DoFTools::make_hanging_node_constraints(dof_handler, constraints); + + VectorTools::interpolate_boundary_values( + mapping, dof_handler, 0, BoundaryValues(), constraints); + VectorTools::interpolate_boundary_values( + mapping, dof_handler, 1, BoundaryValues(), constraints); + constraints.close(); + + DynamicSparsityPattern dsp(dof_handler.n_dofs()); + DoFTools::make_sparsity_pattern(dof_handler, + dsp, + constraints, + /*keep_constrained_dofs = */ false); + + sparsity_pattern.copy_from(dsp); + + system_matrix.reinit(sparsity_pattern); + + + // Setup GMG DoFs + dof_handler.distribute_mg_dofs(); + + // Renumber DoFs on each level in downstream or upstream direction if + // needed. This is only necessary for point smoothers (SOR and Jacobi) as + // the block smoothers operate on cells (see create_smoother()): + if (settings.smoother_type == "SOR" || settings.smoother_type == "Jacobi") + { + if (settings.dof_renumbering == + Settings::DoFRenumberingStrategy::downstream || + settings.dof_renumbering == + Settings::DoFRenumberingStrategy::upstream) + { + const Tensor<1, dim> direction = + (settings.dof_renumbering == + Settings::DoFRenumberingStrategy::upstream ? + -1.0 : + 1.0) * + advection_direction; + + for (unsigned int level = 0; level < n_levels; ++level) + DoFRenumbering::downstream(dof_handler, + level, + direction, + /*dof_wise_renumbering = */ true); + } + else if (settings.dof_renumbering == + Settings::DoFRenumberingStrategy::random) + { + for (unsigned int level = 0; level < n_levels; ++level) + DoFRenumbering::random(dof_handler, level); + } + else + Assert(false, ExcNotImplemented()); + } + + mg_constrained_dofs.clear(); + mg_constrained_dofs.initialize(dof_handler); + + mg_constrained_dofs.make_zero_boundary_constraints(dof_handler, {0, 1}); + + mg_matrices.resize(0, n_levels - 1); + mg_matrices.clear_elements(); + mg_interface_in.resize(0, n_levels - 1); + mg_interface_in.clear_elements(); + mg_interface_out.resize(0, n_levels - 1); + mg_interface_out.clear_elements(); + mg_sparsity_patterns.resize(0, n_levels - 1); + mg_interface_sparsity_patterns.resize(0, n_levels - 1); + + for (unsigned int level = 0; level < n_levels; ++level) + { + { + DynamicSparsityPattern dsp(dof_handler.n_dofs(level), + dof_handler.n_dofs(level)); + MGTools::make_sparsity_pattern(dof_handler, dsp, level); + mg_sparsity_patterns[level].copy_from(dsp); + mg_matrices[level].reinit(mg_sparsity_patterns[level]); + } + { + DynamicSparsityPattern dsp(dof_handler.n_dofs(level), + dof_handler.n_dofs(level)); + MGTools::make_interface_sparsity_pattern(dof_handler, + mg_constrained_dofs, + dsp, + level); + mg_interface_sparsity_patterns[level].copy_from(dsp); + + // We need both interface in and out matrices since our problem is not + // symmetric + mg_interface_in[level].reinit(mg_interface_sparsity_patterns[level]); + mg_interface_out[level].reinit(mg_interface_sparsity_patterns[level]); + } + } + } + + + template + template + void AdvectionProblem::assemble_cell(const IteratorType &cell, + ScratchData & scratch_data, + CopyData & copy_data) + { + copy_data.level = cell->level(); + + const unsigned int dofs_per_cell = + scratch_data.fe_values.get_fe().dofs_per_cell; + copy_data.dofs_per_cell = dofs_per_cell; + copy_data.cell_matrix.reinit(dofs_per_cell, dofs_per_cell); + + const unsigned int n_q_points = + scratch_data.fe_values.get_quadrature().size(); + + if (cell->is_level_cell() == false) + copy_data.cell_rhs.reinit(dofs_per_cell); + + copy_data.local_dof_indices.resize(dofs_per_cell); + cell->get_active_or_mg_dof_indices(copy_data.local_dof_indices); + + scratch_data.fe_values.reinit(cell); + + const RightHandSide right_hand_side; + std::vector rhs_values(n_q_points); + + right_hand_side.value_list(scratch_data.fe_values.get_quadrature_points(), + rhs_values); + + const double delta = settings.with_streamline_diffusion ? + compute_stabilization_delta(cell->diameter(), + epsilon, + advection_direction, + settings.fe_degree) : + 0.0; + + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + for (unsigned int j = 0; j < dofs_per_cell; ++j) + { + copy_data.cell_matrix(i, j) += + (epsilon * scratch_data.fe_values.shape_grad(j, q_point) * + scratch_data.fe_values.shape_grad(i, q_point) * + scratch_data.fe_values.JxW(q_point)) + + ((advection_direction * + scratch_data.fe_values.shape_grad(j, q_point)) * + scratch_data.fe_values.shape_value(i, q_point)) * + scratch_data.fe_values.JxW(q_point); + + if (settings.with_streamline_diffusion) + copy_data.cell_matrix(i, j) += + delta * + (advection_direction * + scratch_data.fe_values.shape_grad(j, q_point)) * + (advection_direction * + scratch_data.fe_values.shape_grad(i, q_point)) * + scratch_data.fe_values.JxW(q_point) - + delta * epsilon * + trace(scratch_data.fe_values.shape_hessian(j, q_point)) * + (advection_direction * + scratch_data.fe_values.shape_grad(i, q_point)) * + scratch_data.fe_values.JxW(q_point); + } + if (cell->is_level_cell() == false) + { + copy_data.cell_rhs(i) += + scratch_data.fe_values.shape_value(i, q_point) * + rhs_values[q_point] * scratch_data.fe_values.JxW(q_point); + if (settings.with_streamline_diffusion) + copy_data.cell_rhs(i) += + delta * rhs_values[q_point] * advection_direction * + scratch_data.fe_values.shape_grad(i, q_point) * + scratch_data.fe_values.JxW(q_point); + } + } + } + + + template + void AdvectionProblem::assemble_system_and_multigrid() + { + auto cell_worker_active = + [&](const decltype(dof_handler.begin_active()) &cell, + ScratchData & scratch_data, + CopyData & copy_data) { + this->assemble_cell(cell, scratch_data, copy_data); + }; + + + + auto copier_active = [&](const CopyData ©_data) { + constraints.distribute_local_to_global(copy_data.cell_matrix, + copy_data.cell_rhs, + copy_data.local_dof_indices, + system_matrix, + system_rhs); + }; + + + MeshWorker::mesh_loop(dof_handler.begin_active(), + dof_handler.end(), + cell_worker_active, + copier_active, + ScratchData(fe, fe.degree + 1), + CopyData(), + MeshWorker::assemble_own_cells); + + std::vector> boundary_constraints( + triangulation.n_global_levels()); + for (unsigned int level = 0; level < triangulation.n_global_levels(); + ++level) + { + IndexSet locally_owned_level_dof_indices; + DoFTools::extract_locally_relevant_level_dofs( + dof_handler, level, locally_owned_level_dof_indices); + boundary_constraints[level].reinit(locally_owned_level_dof_indices); + boundary_constraints[level].add_lines( + mg_constrained_dofs.get_refinement_edge_indices(level)); + boundary_constraints[level].add_lines( + mg_constrained_dofs.get_boundary_indices(level)); + boundary_constraints[level].close(); + } + + auto cell_worker_mg = [&](const decltype(dof_handler.begin_mg()) &cell, + ScratchData &scratch_data, + CopyData & copy_data) { + this->assemble_cell(cell, scratch_data, copy_data); + }; + + auto copier_mg = [&](const CopyData ©_data) { + boundary_constraints[copy_data.level].distribute_local_to_global( + copy_data.cell_matrix, + copy_data.local_dof_indices, + mg_matrices[copy_data.level]); + + // If (i,j) is an interface_out dof pair, then (j,i) is an interface_in + // dof pair. Note: for interface_in, we load the transpose of the + // interface entries, i.e., the entry for dof pair (j,i) is stored in + // interface_in(i,j). + for (unsigned int i = 0; i < copy_data.dofs_per_cell; ++i) + for (unsigned int j = 0; j < copy_data.dofs_per_cell; ++j) + if (mg_constrained_dofs.is_interface_matrix_entry( + copy_data.level, + copy_data.local_dof_indices[i], + copy_data.local_dof_indices[j])) + { + mg_interface_out[copy_data.level].add( + copy_data.local_dof_indices[i], + copy_data.local_dof_indices[j], + copy_data.cell_matrix(i, j)); + mg_interface_in[copy_data.level].add( + copy_data.local_dof_indices[i], + copy_data.local_dof_indices[j], + copy_data.cell_matrix(j, i)); + } + }; + + MeshWorker::mesh_loop(dof_handler.begin_mg(), + dof_handler.end_mg(), + cell_worker_mg, + copier_mg, + ScratchData(fe, fe.degree + 1), + CopyData(), + MeshWorker::assemble_own_cells); + } + + + template + void AdvectionProblem::setup_smoother() + { + if (settings.smoother_type == "SOR") + { + using Smoother = PreconditionSOR>; + + auto smoother = + std_cxx14::make_unique, + Smoother, + Vector>>(); + smoother->initialize(mg_matrices, + Smoother::AdditionalData(fe.degree == 1 ? 1.0 : + 0.62)); + smoother->set_steps(2); + mg_smoother = std::move(smoother); + } + else if (settings.smoother_type == "Jacobi") + { + using Smoother = PreconditionJacobi>; + auto smoother = + std_cxx14::make_unique, + Smoother, + Vector>>(); + smoother->initialize(mg_matrices, + Smoother::AdditionalData(fe.degree == 1 ? 0.6667 : + 0.47)); + smoother->set_steps(4); + mg_smoother = std::move(smoother); + } + else if (settings.smoother_type == "block SOR" || + settings.smoother_type == "block Jacobi") + { + smoother_data.resize(0, triangulation.n_levels() - 1); + + for (unsigned int level = 0; level < triangulation.n_levels(); ++level) + { + DoFTools::make_cell_patches(smoother_data[level].block_list, + dof_handler, + level); + + smoother_data[level].relaxation = + (settings.smoother_type == "block SOR" ? 1.0 : 0.25); + smoother_data[level].inversion = PreconditionBlockBase::svd; + + std::vector ordered_indices; + switch (settings.dof_renumbering) + { + case Settings::DoFRenumberingStrategy::downstream: + ordered_indices = + create_downstream_cell_ordering(dof_handler, + advection_direction, + level); + break; + + case Settings::DoFRenumberingStrategy::upstream: + ordered_indices = + create_downstream_cell_ordering(dof_handler, + -1.0 * advection_direction, + level); + break; + + case Settings::DoFRenumberingStrategy::random: + ordered_indices = + create_random_cell_ordering(dof_handler, level); + break; + + case Settings::DoFRenumberingStrategy::none: // Do nothing + break; + + default: + AssertThrow(false, ExcNotImplemented()); + break; + } + + smoother_data[level].order = + std::vector>(1, ordered_indices); + } + + if (settings.smoother_type == "block SOR") + { + auto smoother = std_cxx14::make_unique, + RelaxationBlockSOR, double, Vector>, + Vector>>(); + smoother->initialize(mg_matrices, smoother_data); + smoother->set_steps(1); + mg_smoother = std::move(smoother); + } + else if (settings.smoother_type == "block Jacobi") + { + auto smoother = std_cxx14::make_unique< + MGSmootherPrecondition, + RelaxationBlockJacobi, + double, + Vector>, + Vector>>(); + smoother->initialize(mg_matrices, smoother_data); + smoother->set_steps(2); + mg_smoother = std::move(smoother); + } + } + else + AssertThrow(false, ExcNotImplemented()); + } + + + template + void AdvectionProblem::solve() + { + const unsigned int max_iters = 200; + const double solve_tolerance = 1e-8 * system_rhs.l2_norm(); + SolverControl solver_control(max_iters, solve_tolerance, true, true); + solver_control.enable_history_data(); + + using Transfer = MGTransferPrebuilt>; + Transfer mg_transfer(mg_constrained_dofs); + mg_transfer.build_matrices(dof_handler); + + FullMatrix coarse_matrix; + coarse_matrix.copy_from(mg_matrices[0]); + MGCoarseGridHouseholder> coarse_grid_solver; + coarse_grid_solver.initialize(coarse_matrix); + + setup_smoother(); + + mg_matrix.initialize(mg_matrices); + mg_interface_matrix_in.initialize(mg_interface_in); + mg_interface_matrix_out.initialize(mg_interface_out); + + Multigrid> mg( + mg_matrix, coarse_grid_solver, mg_transfer, *mg_smoother, *mg_smoother); + mg.set_edge_matrices(mg_interface_matrix_out, mg_interface_matrix_in); + + PreconditionMG, Transfer> preconditioner(dof_handler, + mg, + mg_transfer); + + std::cout << " Solving with GMRES to tol " << solve_tolerance << "..." + << std::endl; + SolverGMRES<> solver(solver_control); + + Timer time; + time.start(); + solver.solve(system_matrix, solution, system_rhs, preconditioner); + time.stop(); + + std::cout << " converged in " << solver_control.last_step() + << " iterations" + << " in " << time.last_wall_time() << " seconds " << std::endl; + + constraints.distribute(solution); + + mg_smoother.release(); + } + + + + template + void AdvectionProblem::output_results(const unsigned int cycle) const + { + // Here we generate an index for each cell to visualize the ordering used + // by the smoothers. Note that we do this only for the active cells + // instead of the levels, where the smoothers are actually used. For the + // point smoothers we renumber DoFs instead of cells, so this is only an + // approximation of what happens in reality. Finally, the random ordering + // is not the random ordering we actually use (see create_smoother() for + // that). + const unsigned int n_active_cells = triangulation.n_active_cells(); + Vector cell_indices(n_active_cells); + { + // First generate a permutation vector for the cell indices: + std::vector ordered_indices; + switch (settings.dof_renumbering) + { + case Settings::DoFRenumberingStrategy::downstream: + ordered_indices = + create_downstream_cell_ordering(dof_handler, advection_direction); + break; + + case Settings::DoFRenumberingStrategy::upstream: + ordered_indices = + create_downstream_cell_ordering(dof_handler, + -1.0 * advection_direction); + break; + + case Settings::DoFRenumberingStrategy::random: + ordered_indices = create_random_cell_ordering(dof_handler); + break; + + case Settings::DoFRenumberingStrategy::none: + ordered_indices.resize(n_active_cells); + for (unsigned int i = 0; i < n_active_cells; ++i) + ordered_indices[i] = i; + break; + + default: + AssertThrow(false, ExcNotImplemented()); + break; + } + + // Then copy the permutation in ordered_indices into an output vector: + for (unsigned int i = 0; i < n_active_cells; ++i) + cell_indices(ordered_indices[i]) = static_cast(i); + } + + DataOut data_out; + data_out.attach_dof_handler(dof_handler); + data_out.add_data_vector(solution, "solution"); + data_out.add_data_vector(cell_indices, "cell_index"); + data_out.build_patches(); + + std::string filename = + "solution-" + Utilities::int_to_string(cycle) + ".vtu"; + std::ofstream output(filename.c_str()); + data_out.write_vtu(output); + } + + + template + void AdvectionProblem::run() + { + for (unsigned int cycle = 0; cycle < (settings.fe_degree == 1 ? 7 : 5); + ++cycle) + { + std::cout << " Cycle " << cycle << ':' << std::endl; + + if (cycle == 0) + { + GridGenerator::hyper_cube_with_cylindrical_hole( + triangulation, 0.3, 1.0, 0.5, 1, false); + static const SphericalManifold manifold_description( + Point(0, 0)); + triangulation.set_manifold(1, manifold_description); + } + + triangulation.refine_global(); + + setup_system(); + + std::cout << " Number of active cells: " + << triangulation.n_active_cells() << " (" + << triangulation.n_levels() << " levels)" << std::endl; + std::cout << " Number of degrees of freedom: " + << dof_handler.n_dofs() << std::endl; + + assemble_system_and_multigrid(); + + solve(); + + if (settings.output) + output_results(cycle); + + std::cout << std::endl; + } + } +} // namespace Step63 + + + +int main(int argc, char *argv[]) +{ + try + { + Step63::Settings settings; + settings.get_parameters((argc > 1) ? (argv[1]) : ""); + + Step63::AdvectionProblem<2> advection_problem_2d(settings); + advection_problem_2d.run(); + } + catch (std::exception &exc) + { + std::cerr << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on processing: " << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + } + catch (...) + { + std::cerr << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + } + + return 0; +} diff --git a/examples/step-7/doc/results.dox b/examples/step-7/doc/results.dox index 667188626009..fdc5e9a67b08 100644 --- a/examples/step-7/doc/results.dox +++ b/examples/step-7/doc/results.dox @@ -53,15 +53,15 @@ Cycle 8: Number of degrees of freedom: 15912 cycle cells dofs L2 H1 Linfty - 0 64 81 1.576e-01 1.418e+00 2.707e-01 - 1 124 157 4.285e-02 1.285e+00 1.469e-01 - 2 280 341 1.593e-02 7.909e-01 8.034e-02 - 3 577 690 9.359e-03 5.096e-01 2.784e-02 - 4 1099 1264 2.865e-03 3.038e-01 9.822e-03 - 5 2191 2452 1.480e-03 2.106e-01 5.679e-03 - 6 4165 4510 6.907e-04 1.462e-01 2.338e-03 - 7 7915 8440 4.743e-04 1.055e-01 1.442e-03 - 8 15196 15912 1.920e-04 7.468e-02 7.259e-04 + 0 64 81 1.840e+00 2.858e+00 1.835e+00 + 1 124 157 5.190e-02 1.200e+00 1.344e-01 + 2 280 341 1.439e-02 7.892e-01 7.554e-02 + 3 577 690 8.627e-03 5.061e-01 2.805e-02 + 4 1099 1264 3.217e-03 3.030e-01 1.073e-02 + 5 2191 2452 1.445e-03 2.097e-01 5.073e-03 + 6 4165 4510 8.387e-04 1.460e-01 2.013e-03 + 7 7915 8440 7.051e-04 1.053e-01 1.804e-03 + 8 15196 15912 2.774e-04 7.463e-02 6.911e-04 Solving with Q1 elements, global refinement =========================================== @@ -83,18 +83,18 @@ Cycle 4: Number of degrees of freedom: 16641 cycle cells dofs L2 H1 Linfty - 0 64 81 1.576e-01 1.418e+00 2.707e-01 - 1 256 289 4.280e-02 1.285e+00 1.444e-01 - 2 1024 1089 1.352e-02 7.556e-01 7.772e-02 - 3 4096 4225 3.423e-03 3.822e-01 2.332e-02 - 4 16384 16641 8.586e-04 1.917e-01 6.097e-03 - -n cells H1 L2 -0 64 1.418e+00 - - 1.576e-01 - - -1 256 1.285e+00 1.10 0.14 4.280e-02 3.68 1.88 -2 1024 7.556e-01 1.70 0.77 1.352e-02 3.17 1.66 -3 4096 3.822e-01 1.98 0.98 3.423e-03 3.95 1.98 -4 16384 1.917e-01 1.99 1.00 8.586e-04 3.99 2.00 + 0 64 81 1.840e+00 2.858e+00 1.835e+00 + 1 256 289 3.570e-02 1.199e+00 1.307e-01 + 2 1024 1089 1.192e-02 7.565e-01 7.168e-02 + 3 4096 4225 3.047e-03 3.823e-01 2.128e-02 + 4 16384 16641 7.660e-04 1.917e-01 5.554e-03 + +n cells H1 L2 +0 64 2.858e+00 - - 1.840e+00 - - +1 256 1.199e+00 2.38 1.25 3.570e-02 51.54 5.69 +2 1024 7.565e-01 1.58 0.66 1.192e-02 2.99 1.58 +3 4096 3.823e-01 1.98 0.98 3.047e-03 3.91 1.97 +4 16384 1.917e-01 1.99 1.00 7.660e-04 3.98 1.99 Solving with Q2 elements, global refinement =========================================== @@ -169,7 +169,7 @@ cycle cells dofs L2 H1 Linfty 5 2059 9223 7.738e-05 1.974e-02 7.270e-04 6 3913 17887 2.925e-05 8.772e-03 1.463e-04 7 7441 33807 1.024e-05 4.121e-03 8.567e-05 - 8 14212 64731 3.761e-06 2.108e-03 2.167e-05 + 8 14212 64731 3.761e-06 2.108e-03 2.167e-05 @endcode @@ -192,11 +192,8 @@ here). Go ahead and run the program with higher order elements (Q3, Q4, ...). You will notice that assertions in several parts of the code will trigger (for -example in the generation of the filename for the data output). After fixing -these you will not see the correct convergence orders that the theory -predicts. This is because the orders for the quadrature formulas are -hard-coded in this program and this order is not enough for higher order -discretizations. What is a good way to pick the orders dynamically? +example in the generation of the filename for the data output). You might have to address these, +but it should not be very hard to get the program to work!

    Convergence Comparison

    diff --git a/examples/step-7/step-7.cc b/examples/step-7/step-7.cc index 97c0e7daa91c..f9c8fb1c6f34 100644 --- a/examples/step-7/step-7.cc +++ b/examples/step-7/step-7.cc @@ -378,7 +378,7 @@ namespace Step7 // // We will show here how the library managed to find out that there are // still active references to an object and the object is still alive - // frome the point of view of a using object. Basically, the method is along + // from the point of view of a using object. Basically, the method is along // the following line: all objects that are subject to such potentially // dangerous pointers are derived from a class called Subscriptor. For // example, the Triangulation, DoFHandler, and a base class of the @@ -541,8 +541,8 @@ namespace Step7 template void HelmholtzProblem::assemble_system() { - QGauss quadrature_formula(3); - QGauss face_quadrature_formula(3); + QGauss quadrature_formula(fe->degree + 1); + QGauss face_quadrature_formula(fe->degree + 1); const unsigned int n_q_points = quadrature_formula.size(); const unsigned int n_face_q_points = face_quadrature_formula.size(); @@ -797,7 +797,7 @@ namespace Step7 KellyErrorEstimator::estimate( dof_handler, - QGauss(3), + QGauss(fe->degree + 1), std::map *>(), solution, estimated_error_per_cell); @@ -853,7 +853,7 @@ namespace Step7 solution, Solution(), difference_per_cell, - QGauss(3), + QGauss(fe->degree + 1), VectorTools::L2_norm); const double L2_error = VectorTools::compute_global_error(triangulation, @@ -871,7 +871,7 @@ namespace Step7 solution, Solution(), difference_per_cell, - QGauss(3), + QGauss(fe->degree + 1), VectorTools::H1_seminorm); const double H1_error = VectorTools::compute_global_error(triangulation, @@ -883,8 +883,9 @@ namespace Step7 // points. Since this depends quite sensitively on the quadrature rule // being used, and since we would like to avoid false results due to // super-convergence effects at some points, we use a special quadrature - // rule that is obtained by iterating the trapezoidal rule five times in - // each space direction. Note that the constructor of the QIterated class + // rule that is obtained by iterating the trapezoidal rule by the degree of + // of the finite element times two plus one in each space direction. + // Note that the constructor of the QIterated class // takes a one-dimensional quadrature rule and a number that tells it how // often it shall use this rule in each space direction. // @@ -893,7 +894,7 @@ namespace Step7 // from the L infinity errors on each cell with a call to // VectorTools::compute_global_error. const QTrapez<1> q_trapez; - const QIterated q_iterated(q_trapez, 5); + const QIterated q_iterated(q_trapez, fe->degree * 2 + 1); VectorTools::integrate_difference(dof_handler, solution, Solution(), diff --git a/examples/step-8/step-8.cc b/examples/step-8/step-8.cc index 4927b72858b4..3f7318fd21c7 100644 --- a/examples/step-8/step-8.cc +++ b/examples/step-8/step-8.cc @@ -269,7 +269,7 @@ namespace Step8 template void ElasticProblem::assemble_system() { - QGauss quadrature_formula(2); + QGauss quadrature_formula(fe.degree + 1); FEValues fe_values(fe, quadrature_formula, @@ -490,7 +490,7 @@ namespace Step8 KellyErrorEstimator::estimate( dof_handler, - QGauss(2), + QGauss(fe.degree + 1), std::map *>(), solution, estimated_error_per_cell); diff --git a/include/deal.II/algorithms/general_data_storage.h b/include/deal.II/algorithms/general_data_storage.h new file mode 100644 index 000000000000..dfbc3bd07362 --- /dev/null +++ b/include/deal.II/algorithms/general_data_storage.h @@ -0,0 +1,501 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2019 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE.md at +// the top level directory of deal.II. +// +// --------------------------------------------------------------------- + +#ifndef dealii_algorithms_general_data_storage_h +#define dealii_algorithms_general_data_storage_h + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +DEAL_II_NAMESPACE_OPEN + + +/** + * This class facilitates the storage of any general data. + * It offers a mechanism to store any amount of data, of any type, + * which is then made accessible by an identifier string. + * + * When using this class, please cite + * + * @code{.bib} + * @article{SartoriGiulianiBardelloni-2018-a, + * Author = {Sartori, Alberto and Giuliani, Nicola and + * Bardelloni, Mauro and Heltai, Luca}, + * Journal = {SoftwareX}, + * Pages = {318--327}, + * Title = {{deal2lkit: A toolkit library for high performance + * programming in deal.II}}, + * Volume = {7}, + * Year = {2018}} + * @endcode + * + * @author Luca Heltai, Jean-Paul Pelteret, 2019 + */ +class GeneralDataStorage : public Subscriptor +{ +public: + /** + * Default constructor. + */ + GeneralDataStorage() = default; + + /** + * Copy constructor. + */ + GeneralDataStorage(const GeneralDataStorage &) = default; + + /** + * Move constructor. + */ + GeneralDataStorage(GeneralDataStorage &&) = default; + + /** + * Number of objects stored by this class instance. + */ + std::size_t + size() const; + + /** + * Merge the contents of @p other_data with this object. + */ + void + merge(const GeneralDataStorage &other_data); + + /** + * Print the contents of the internal cache to the @p stream. + * + * Each key and value pair in the @p any_data map are printed on an + * individual line, with the std::string<\tt> key listed first + * followed by the demangled type_id of the associated mapped + * type. + */ + template + void + print_info(Stream &stream); + + /** + * Clear all data stored in this class instance. + * + * When you call this function, it destroys all objects you asked to be stored + * as copies, and it forgets about the references to data you asked to store + * by reference. As a consequence, you are now free to destroy the objects to + * which references were stored at whatever time you want -- before or after + * the current `GeneralDataStorage` object is destroyed. + * + * To clarify this point, consider the following small example: + * + * @code + * GeneralDataStorage data; + * + * { + * const double some_number = ...; + * data.add_unique_reference("value", some_number); + * + * // Adding either of these next two lines could fix the + * // issue, by removing the association of some_number with data: + * // data.remove_object_with_name("value"); + * // data.reset(); + * } // some_number goes out of scope here + * + * const double some_other_number + * = data.get_object_with_name("value"); // Invalid call + * @endcode + * + * In the code above, the @p data object has a longer scope than + * some_number. By the time we fetch the "value" from + * @p data , the reference to @p some_number is no longer valid. + * + * Similarly, for data copied into a GeneralDataStorage object one should + * consider the scope under which it remains valid: + * + * @code + * double* ptr_to_some_number = null_ptr; + * + * { + * GeneralDataStorage data; + * const double some_number = ...; + * data.add_unique_copy("value", some_number); + * + * ptr_to_some_number = &(data.get_object_with_name("value")); + * } // The copy to some_number goes out of scope here + * + * const double some_other_number + * = *ptr_to_some_number; // Invalid call + * @endcode + * + * Similar to the first example, we must be conscious of the fact that the + * copies of any @p Type stored by @p data only remains valid while the + * GeneralDataStorage instance in which it is stored is alive. + * + * Furthermore, as elucidated in the last example, the copy of the + * class instance (owned by GeneralDataStorage) that is being pointed to + * is no longer alive when the reset() function is called, or when it is + * removed via a call to remove_object_with_name(). + * + * @code + * GeneralDataStorage data; + * double* ptr_to_some_number = null_ptr; + * + * { + * const double some_number = ...; + * data.add_unique_copy("value", some_number); + * + * ptr_to_some_number = &(data.get_object_with_name("value")); + * + * // The copy to some_number would go out of scope when either of + * // following two calls are made: + * data.remove_object_with_name("value"); + * data.reset(); + * } + * + * const double some_other_number + * = *ptr_to_some_number; // Invalid call + * @endcode + */ + void + reset(); + + /** + * @name Data storage and access + */ + //@{ + + /** + * Store internally a copy of the given object. The copied object is + * owned by this class, and is accessible via reference through the + * get_object_with_name() method. + * + * This function ensures that no @p entry with the given @name is + * already stored by this class instance. + */ + template + void + add_unique_copy(const std::string &name, const Type &entry); + + /** + * Store internally a copy of the given object. The copied object is + * owned by this class, and is accessible via reference through the + * get_object_with_name() method. + * + * This function does not perform any checks to ensure that the @p entry + * with the given @name is already stored by this class instance. If the + * @p name does in fact point to existing data, then this is overwritten. + */ + template + void + add_or_overwrite_copy(const std::string &name, const Type &entry); + + /** + * Add a reference to an already existing object. The object is not + * owned by this class, and the user has to guarantee that the + * referenced object lives longer than this class instance. The stored + * reference is accessible through the get_object_with_name() method. + * + * This function ensures that no @p entry with the given @name is + * already stored by this class instance. + */ + template + void + add_unique_reference(const std::string &name, Type &entry); + + /** + * Add a reference to an already existing object. The object is not + * owned by this class, and the user has to guarantee that the + * referenced object lives longer than this class instance. The stored + * reference is accessible through the get_object_with_name() method. + * + * This function does not perform any checks to ensure that the @p entry + * with the given @name is already stored by this class instance. If the + * @p name does in fact point to existing data, then this is overwritten. + */ + template + void + add_or_overwrite_reference(const std::string &name, Type &entry); + + /** + * Return a reference to the object with given name. If the object does + * not exist, then the input @p arguments will be used to construct an object + * of the given @p Type and a reference to this new object then be returned. + * + * A copy of an object of type @p Type , which is owned by this class + * instance, is generated by calling its constructor with the given set of + * arguments. For this function, the @p arguments are passed as + * lvalue references. + */ + template + Type & + get_or_add_object_with_name(const std::string &name, + Arg & argument, + Args &... arguments); + + /** + * Return a reference to the object with given name. If the object does + * not exist, then the input @p arguments will be used to construct an object + * of the given @p Type and a reference to this new object then be returned. + * + * A copy of an object of type @p Type , which is owned by this class + * instance, is generated by calling its constructor with the given set of + * arguments. In contrast to the previous function of the same name, for + * this function the @p arguments are passed as rvalue references. + */ + template + Type & + get_or_add_object_with_name(const std::string &name, + Arg && argument, + Args &&... arguments); + + /** + * Same as above for default constructors. + */ + template + Type & + get_or_add_object_with_name(const std::string &name); + + /** + * Return a reference to the object with given name. + * + * This function throws an exception if either an object with the given name + * is not stored in this class, or if the object with the given name is + * neither of the exact specified @p Type nor a pointer to the @p Type. + */ + template + Type & + get_object_with_name(const std::string &name); + + /** + * Return a constant reference to the object with the given name. + * + * This function throws an exception if either an object with the given name + * is not stored in this class, or if the object with the given name is + * neither of the exact specified @p Type nor a pointer to the @p Type. + */ + template + const Type & + get_object_with_name(const std::string &name) const; + + /** + * Find out if we store an object with given name. + */ + bool + stores_object_with_name(const std::string &name) const; + + /** + * Remove the object with given name. + */ + void + remove_object_with_name(const std::string &name); + + //@} + + /** + * An entry with this name does not exist in the internal boost::any map. + */ + DeclException1(ExcNameNotFound, + std::string, + << "No entry with the name " << arg1 << " exists."); + + /** + * An entry with this name does not exist in the internal boost::any map. + */ + DeclException1(ExcNameHasBeenFound, + std::string, + << "An entry with the name " << arg1 << " already exists."); + + /** + * The requested type and the stored type are different. + */ + DeclException3(ExcTypeMismatch, + std::string, + const char *, + const char *, + << "The stored type for entry with name \"" << arg1 << "\" is " + << arg2 << " but you requested type " << arg3 << "."); + +private: + /** + * Arbitrary user data, identified by a string. + */ + std::map any_data; +}; + + +/*----------------- Inline and template methods -----------------*/ + + +#ifndef DOXYGEN + + +template +void +GeneralDataStorage::print_info(Stream &os) +{ + for (auto it : any_data) + { + os << it.first << '\t' << '\t' + << boost::core::demangle(it.second.type().name()) << std::endl; + } +} + + +template +void +GeneralDataStorage::add_unique_copy(const std::string &name, const Type &entry) +{ + Assert(!stores_object_with_name(name), ExcNameHasBeenFound(name)); + add_or_overwrite_copy(name, entry); +} + + +template +void +GeneralDataStorage::add_or_overwrite_copy(const std::string &name, + const Type & entry) +{ + any_data[name] = entry; +} + + +template +void +GeneralDataStorage::add_unique_reference(const std::string &name, Type &entry) +{ + Assert(!stores_object_with_name(name), ExcNameHasBeenFound(name)); + add_or_overwrite_reference(name, entry); +} + + +template +void +GeneralDataStorage::add_or_overwrite_reference(const std::string &name, + Type & entry) +{ + Type *ptr = &entry; + any_data[name] = ptr; +} + + +template +Type & +GeneralDataStorage::get_object_with_name(const std::string &name) +{ + Assert(stores_object_with_name(name), ExcNameNotFound(name)); + + Type *p = nullptr; + + if (any_data[name].type() == typeid(Type *)) + { + p = boost::any_cast(any_data[name]); + } + else if (any_data[name].type() == typeid(Type)) + { + p = boost::any_cast(&any_data[name]); + } + else + { + Assert(false, + ExcTypeMismatch(name, + any_data[name].type().name(), + typeid(Type).name())); + } + + return *p; +} + + +template +const Type & +GeneralDataStorage::get_object_with_name(const std::string &name) const +{ + AssertThrow(stores_object_with_name(name), ExcNameNotFound(name)); + + const auto it = any_data.find(name); + + if (it->second.type() == typeid(Type *)) + { + const Type *p = boost::any_cast(it->second); + return *p; + } + else if (it->second.type() == typeid(Type)) + { + const Type *p = boost::any_cast(&it->second); + return *p; + } + else + { + Assert(false, + ExcTypeMismatch(name, + it->second.type().name(), + typeid(Type).name())); + const Type *p = nullptr; + return *p; + } +} + + +template +Type & +GeneralDataStorage::get_or_add_object_with_name(const std::string &name, + Arg & argument, + Args &... arguments) +{ + if (!stores_object_with_name(name)) + add_unique_copy(name, Type(argument, arguments...)); + + return get_object_with_name(name); +} + + +template +Type & +GeneralDataStorage::get_or_add_object_with_name(const std::string &name, + Arg && argument, + Args &&... arguments) +{ + if (!stores_object_with_name(name)) + add_unique_copy(name, + Type(std::forward(argument), + std::forward(arguments)...)); + + return get_object_with_name(name); +} + + +template +Type & +GeneralDataStorage::get_or_add_object_with_name(const std::string &name) +{ + if (!stores_object_with_name(name)) + add_unique_copy(name, Type()); + + return get_object_with_name(name); +} + + +#endif // DOXYGEN + + +DEAL_II_NAMESPACE_CLOSE + +#endif // dealii_algorithms_general_data_storage_h diff --git a/include/deal.II/base/array_view.h b/include/deal.II/base/array_view.h index 9fdcbb3b6b20..e51f984b6346 100644 --- a/include/deal.II/base/array_view.h +++ b/include/deal.II/base/array_view.h @@ -93,6 +93,11 @@ class ArrayView */ using const_iterator = const ElementType *; + /** + * Default constructor. + */ + ArrayView(); + /** * Constructor. * @@ -159,6 +164,28 @@ class ArrayView */ ArrayView(std::vector::type> &vector); + /** + * Reinitialize a view. + * + * @param[in] starting_element A pointer to the first element of the array + * this object should represent. + * @param[in] n_elements The length (in elements) of the chunk of memory + * this object should represent. + * + * @note The object that is constructed from these arguments has no + * knowledge how large the object into which it points really is. As a + * consequence, whenever you call ArrayView::operator[], the array view can + * check that the given index is within the range of the view, but it can't + * check that the view is indeed a subset of the valid range of elements of + * the underlying object that allocated that range. In other words, you need + * to ensure that the range of the view specified by the two arguments to + * this constructor is in fact a subset of the elements of the array into + * which it points. The appropriate way to do this is to use the + * make_array_view() functions. + */ + void + reinit(value_type *starting_element, const std::size_t n_elements); + /** * Compare two ArrayView objects of the same type. Two objects are considered * equal if they have the same size and the same starting pointer. @@ -252,12 +279,12 @@ class ArrayView * A pointer to the first element of the range of locations in memory that * this object represents. */ - value_type *const starting_element; + value_type *starting_element; /** * The length of the array this object represents. */ - const std::size_t n_elements; + std::size_t n_elements; friend class ArrayView; }; @@ -305,6 +332,14 @@ namespace internal +template +inline ArrayView::ArrayView() + : starting_element(nullptr) + , n_elements(0) +{} + + + template inline ArrayView::ArrayView( value_type * starting_element, @@ -322,6 +357,16 @@ inline ArrayView::ArrayView( +template +inline void +ArrayView::reinit(value_type *starting_element, + const std::size_t n_elements) +{ + *this = ArrayView(starting_element, n_elements); +} + + + template inline ArrayView::ArrayView( const ArrayView::type, MemorySpaceType> @@ -1134,6 +1179,25 @@ make_array_view(const Table<2, ElementType> & table, +/* + * Create a view that doesn't allow the container it points to to be modified. + * This is useful if the object passed in is not `const` already and a function + * requires a view to constant memory in its signature. + * + * This function returns an object of type `ArrayView` where `T` is the + * element type of the container. + * + * @relatesalso ArrayView + */ +template +inline auto +make_const_array_view(const Container &container) + -> decltype(make_array_view(container)) +{ + return make_array_view(container); +} + + DEAL_II_NAMESPACE_CLOSE #endif diff --git a/include/deal.II/base/bounding_box.h b/include/deal.II/base/bounding_box.h index d4c594c55a63..8922fa6b3676 100644 --- a/include/deal.II/base/bounding_box.h +++ b/include/deal.II/base/bounding_box.h @@ -140,6 +140,19 @@ class BoundingBox bool point_inside(const Point &p) const; + /** + * Increase (or decrease) the size of the bounding box by the given amount. + * After calling this method, the lower left corner of the bounding box will + * have each coordinate decreased by @p amount, and the upper right corner + * of the bounding box will have each coordinate increased by @p amount. + * + * If you call this method with a negative number, and one of the axes of the + * original bounding box is smaller than amount/2, the method will trigger + * an assertion. + */ + void + extend(const Number &amount); + /** * Compute the volume (i.e. the dim-dimensional measure) of the BoundingBox. */ @@ -176,6 +189,20 @@ inline BoundingBox::BoundingBox( this->boundary_points = boundary_points; } +template +inline void +BoundingBox::extend(const Number &amount) +{ + for (unsigned int d = 0; d < spacedim; ++d) + { + boundary_points.first[d] -= amount; + boundary_points.second[d] += amount; + Assert(boundary_points.first[d] <= boundary_points.second[d], + ExcMessage("Bounding Box can't be shrunk this much: the points' " + "order should remain bottom left, top right.")); + } +} + template template diff --git a/include/deal.II/base/config.h.in b/include/deal.II/base/config.h.in index 7801a2397f44..edf13bc8030b 100644 --- a/include/deal.II/base/config.h.in +++ b/include/deal.II/base/config.h.in @@ -1,6 +1,6 @@ // --------------------------------------------------------------------- // -// Copyright (C) 2012 - 2016 by the deal.II authors +// Copyright (C) 2012 - 2018 by the deal.II authors // // This file is part of the deal.II library. // @@ -43,6 +43,7 @@ #cmakedefine DEAL_II_WITH_CUDA_AWARE_MPI #cmakedefine DEAL_II_WITH_CXX14 #cmakedefine DEAL_II_WITH_CXX17 +#cmakedefine DEAL_II_WITH_GINKGO #cmakedefine DEAL_II_WITH_GSL #cmakedefine DEAL_II_WITH_GMSH #cmakedefine DEAL_II_WITH_HDF5 @@ -60,6 +61,7 @@ #cmakedefine DEAL_II_WITH_SCALAPACK #cmakedefine DEAL_II_WITH_SLEPC #cmakedefine DEAL_II_WITH_SUNDIALS +#cmakedefine DEAL_II_WITH_SYMENGINE #cmakedefine DEAL_II_WITH_THREADS #cmakedefine DEAL_II_WITH_TRILINOS #cmakedefine DEAL_II_WITH_UMFPACK @@ -114,7 +116,14 @@ */ #cmakedefine DEAL_II_WORDS_BIGENDIAN -#define DEAL_II_COMPILER_VECTORIZATION_LEVEL @DEAL_II_COMPILER_VECTORIZATION_LEVEL@ +// We need to disable SIMD vectorization for CUDA device code. +// Otherwise, nvcc compilers from version 9 on will emit an error message like: +// "[...] contains a vector, which is not supported in device code" +#ifdef __CUDA_ARCH__ +# define DEAL_II_COMPILER_VECTORIZATION_LEVEL 0 +#else +# define DEAL_II_COMPILER_VECTORIZATION_LEVEL @DEAL_II_COMPILER_VECTORIZATION_LEVEL@ +#endif #define DEAL_II_OPENMP_SIMD_PRAGMA @DEAL_II_OPENMP_SIMD_PRAGMA@ @@ -163,12 +172,16 @@ #cmakedefine DEAL_II_ARPACK_WITH_PARPACK /* cmake/modules/FindPETSC.cmake */ +#cmakedefine DEAL_II_PETSC_WITH_COMPLEX #cmakedefine DEAL_II_PETSC_WITH_HYPRE #cmakedefine DEAL_II_PETSC_WITH_MUMPS /* cmake/modules/FindSUNDIALS.cmake */ #cmakedefine DEAL_II_SUNDIALS_WITH_IDAS +/* cmake/modules/FindSYMENGINE.cmake */ +#cmakedefine DEAL_II_SYMENGINE_WITH_LLVM + /* cmake/configure/configure_1_threads.cmake */ #cmakedefine DEAL_II_USE_MT_POSIX #cmakedefine DEAL_II_USE_MT_POSIX_NO_BARRIERS @@ -178,6 +191,7 @@ #cmakedefine DEAL_II_TRILINOS_WITH_EPETRAEXT #cmakedefine DEAL_II_TRILINOS_WITH_ROL #cmakedefine DEAL_II_TRILINOS_WITH_SACADO +#cmakedefine DEAL_II_TRILINOS_WITH_TPETRA #cmakedefine DEAL_II_TRILINOS_WITH_ZOLTAN @@ -237,30 +251,29 @@ (major)*1000000 + (minor)*10000 + (subminor)*100 + (patch)) #endif - /* - * SUNDIALS: - * - * Note: The following definitions will be set in sundials_config.h, - * so we don't repeat them here. - * - * SUNDIALS_VERSION_MAJOR - * SUNDIALS_VERSION_MINOR - * SUNDIALS_VERSION_PATCH - */ - - #define DEAL_II_SUNDIALS_VERSION_GTE(major,minor,subminor) \ - ((SUNDIALS_VERSION_MAJOR * 10000 + \ - SUNDIALS_VERSION_MINOR * 100 + \ - SUNDIALS_VERSION_SUBMINOR) \ +/* + * SUNDIALS: + */ + +#ifdef DEAL_II_WITH_SUNDIALS + # define DEAL_II_SUNDIALS_VERSION_MAJOR @SUNDIALS_VERSION_MAJOR@ + # define DEAL_II_SUNDIALS_VERSION_MINOR @SUNDIALS_VERSION_MINOR@ + # define DEAL_II_SUNDIALS_VERSION_PATCH @SUNDIALS_VERSION_PATCH@ + + #define DEAL_II_SUNDIALS_VERSION_GTE(major,minor,patch) \ + ((DEAL_II_SUNDIALS_VERSION_MAJOR * 10000 + \ + DEAL_II_SUNDIALS_VERSION_MINOR * 100 + \ + DEAL_II_SUNDIALS_VERSION_PATCH) \ >= \ - (major)*10000 + (minor)*100 + (subminor)) + (major)*10000 + (minor)*100 + (patch)) - #define DEAL_II_SUNDIALS_VERSION_LT(major,minor,subminor) \ - ((SUNDIALS_VERSION_MAJOR * 10000 + \ - SUNDIALS_VERSION_MINOR * 100 + \ - SUNDIALS_VERSION_SUBMINOR) \ + #define DEAL_II_SUNDIALS_VERSION_LT(major,minor,patch) \ + ((DEAL_II_SUNDIALS_VERSION_MAJOR * 10000 + \ + DEAL_II_SUNDIALS_VERSION_MINOR * 100 + \ + DEAL_II_SUNDIALS_VERSION_PATCH) \ < \ - (major)*10000 + (minor)*100 + (subminor)) + (major)*10000 + (minor)*100 + (patch)) +#endif /* * PETSc: diff --git a/include/deal.II/base/cuda_size.h b/include/deal.II/base/cuda_size.h index 26e0a3c4d990..274b418f9a75 100644 --- a/include/deal.II/base/cuda_size.h +++ b/include/deal.II/base/cuda_size.h @@ -23,14 +23,16 @@ DEAL_II_NAMESPACE_OPEN namespace CUDAWrappers { /** - * Define the size of a block when launching a CUDA kernel. + * Define the size of a block when launching a CUDA kernel. This number can be + * changed depending on the architecture the code is running on. */ constexpr int block_size = 512; /** - * Define the size of chunk of data worked on by a thread. + * Define the size of chunk of data worked on by a thread. This number can be + * changed depending on the architecture the code is running on. */ - constexpr int chunk_size = 8; + constexpr int chunk_size = 1; } // namespace CUDAWrappers DEAL_II_NAMESPACE_CLOSE diff --git a/include/deal.II/base/data_out_base.h b/include/deal.II/base/data_out_base.h index 8e05a6aacbdd..2a6da9fd79e1 100644 --- a/include/deal.II/base/data_out_base.h +++ b/include/deal.II/base/data_out_base.h @@ -26,6 +26,9 @@ #include +// To be able to serialize XDMFEntry +#include + #include #include #include @@ -3599,7 +3602,7 @@ class XDMFEntry serialize(Archive &ar, const unsigned int /*version*/) { ar &valid &h5_sol_filename &h5_mesh_filename &entry_time &num_nodes - &num_cells &dimension &attribute_dims; + &num_cells &dimension &space_dimension &attribute_dims; } /** diff --git a/include/deal.II/base/derivative_form.h b/include/deal.II/base/derivative_form.h index 016540eeada5..261a96ecdf8d 100644 --- a/include/deal.II/base/derivative_form.h +++ b/include/deal.II/base/derivative_form.h @@ -21,24 +21,26 @@ DEAL_II_NAMESPACE_OPEN /** - * This class represents the (tangential) derivatives of a function $ f: + * This class represents the (tangential) derivatives of a function $ \mathbf F: * {\mathbb R}^{\text{dim}} \rightarrow {\mathbb R}^{\text{spacedim}}$. Such * functions are always used to map the reference dim-dimensional cell into * spacedim-dimensional space. For such objects, the first derivative of the * function is a linear map from ${\mathbb R}^{\text{dim}}$ to ${\mathbb * R}^{\text{spacedim}}$, i.e., it can be represented as a matrix in ${\mathbb * R}^{\text{spacedim}\times \text{dim}}$. This makes sense since one would - * represent the first derivative, $\nabla f(\mathbf x)$ with $\mathbf x\in + * represent the first derivative, $\nabla \mathbf F(\mathbf x)$ with $\mathbf + * x\in * {\mathbb R}^{\text{dim}}$, in such a way that the directional derivative in * direction $\mathbf d\in {\mathbb R}^{\text{dim}}$ so that * @f{align*}{ - * \nabla f(\mathbf x) \mathbf d + * \nabla \mathbf F(\mathbf x) \mathbf d * = \lim_{\varepsilon\rightarrow 0} - * \frac{f(\mathbf x + \varepsilon \mathbf d) - f(\mathbf x)}{\varepsilon}, + * \frac{\mathbf F(\mathbf x + \varepsilon \mathbf d) - \mathbf F(\mathbf + * x)}{\varepsilon}, * @f} - * i.e., one needs to be able to multiply the matrix $\nabla f(\mathbf x)$ by - * a vector in ${\mathbb R}^{\text{dim}}$, and the result is a difference of - * function values, which are in ${\mathbb R}^{\text{spacedim}}$. + * i.e., one needs to be able to multiply the matrix $\nabla \mathbf F(\mathbf + * x)$ by a vector in ${\mathbb R}^{\text{dim}}$, and the result is a difference + * of function values, which are in ${\mathbb R}^{\text{spacedim}}$. * Consequently, the matrix must be of size $\text{spacedim}\times\text{dim}$. * * Similarly, the second derivative is a bilinear map from ${\mathbb @@ -89,19 +91,19 @@ class DerivativeForm operator=(const Tensor<1, dim, Number> &); /** - * Converts a DerivativeForm to Tensor. - * In particular, if order==1 and the derivative is the Jacobian of F, then - * Tensor[i] = grad(F^i). + * Converts a DerivativeForm to Tensor. In particular, if order == 1 and the derivative is the Jacobian of + * $\mathbf F(\mathbf x)$, then Tensor[i] = $\nabla F_i(\mathbf x)$. */ operator Tensor() const; /** - * Converts a DerivativeForm <1, dim, 1> to Tensor<1,dim,Number>. + * Converts a DerivativeForm<1, dim, 1, Number> to Tensor<1, dim, Number>. */ operator Tensor<1, dim, Number>() const; /** - * Return the transpose of a rectangular DerivativeForm, that is to say + * Return the transpose of a rectangular DerivativeForm, * viewed as a two dimensional matrix. */ DerivativeForm<1, spacedim, dim, Number> @@ -109,26 +111,28 @@ class DerivativeForm /** * Compute the Frobenius norm of this form, i.e., the expression - * $\sqrt{\sum_{ij} |DF_{ij}|^2}$. + * $\sqrt{\sum_{ij} |DF_{ij}|^2} = + * \sqrt{\sum_{ij} |\frac{\partial F_i}{\partial x_j}|^2}$. */ typename numbers::NumberTraits::real_type norm() const; /** * Compute the volume element associated with the jacobian of the - * transformation F. That is to say if $DF$ is square, it computes - * $\det(DF)$, in case DF is not square returns $\sqrt{\det(DF^T * DF)}$. + * transformation $\mathbf F$. That is to say if $DF$ is square, it computes + * $\det(DF)$, in case DF is not square returns $\sqrt{\det(DF^T \,DF)}$. */ Number determinant() const; /** * Assuming that the current object stores the Jacobian of a mapping - * $F$, then the current function computes the covariant form - * of the derivative, namely $(\nabla F)G^{-1}$, where $G = (\nabla - * F)^{T}*(\nabla F)$. If $\nabla F$ is a square matrix (i.e., $F: + * $\mathbf F$, then the current function computes the covariant form + * of the derivative, namely $(\nabla \mathbf F) {\mathbf G}^{-1}$, where + * $\mathbf G = (\nabla \mathbf F)^{T}(\nabla \mathbf F)$. If $\nabla \mathbf + * F$ is a square matrix (i.e., $\mathbf F: * {\mathbb R}^n \mapsto {\mathbb R}^n$), then this function - * simplifies to computing $\nabla F^{-T}$. + * simplifies to computing $\nabla {\mathbf F}^{-T}$. */ DerivativeForm<1, dim, spacedim, Number> covariant_form() const; @@ -149,7 +153,8 @@ class DerivativeForm private: /** - * Auxiliary function that computes (*this) * $T^{T}$ + * Auxiliary function that computes $A T^{T}$ where A represents the current + * object. */ DerivativeForm<1, dim, spacedim, Number> times_T_t(const Tensor<2, dim, Number> &T) const; @@ -366,50 +371,76 @@ DerivativeForm::memory_consumption() /** - * One of the uses of DerivativeForm is to apply it as a transformation. This - * is what this function does. If @p T is DerivativeForm<1,dim,1> it computes - * $DF * T$, if @p T is DerivativeForm<1,dim,rank> it computes $T*DF^{T}$. + * One of the uses of DerivativeForm is to apply it as a linear transformation. + * This function returns $\nabla \mathbf F(\mathbf x) \Delta \mathbf x$, which + * approximates the change in $\mathbf F(\mathbf x)$ when $\mathbf x$ is changed + * by the amount $\Delta \mathbf x$ + * @f[ + * \nabla \mathbf F(\mathbf x) \; \Delta \mathbf x + * \approx + * \mathbf F(\mathbf x + \Delta \mathbf x) - \mathbf F(\mathbf x). + * @f] + * The transformation corresponds to + * @f[ + * [\text{result}]_{i_1,\dots,i_k} = i\sum_{j} + * \left[\nabla \mathbf F(\mathbf x)\right]_{i_1,\dots,i_k, j} + * \Delta x_j + * @f] + * in index notation and corresponds to + * $[\Delta \mathbf x] [\nabla \mathbf F(\mathbf x)]^T$ in matrix notation. * * @relatesalso DerivativeForm - * @author Sebastian Pauletti, 2011 + * @author Sebastian Pauletti, 2011, Reza Rastak, 2019 */ template inline Tensor<1, spacedim, Number> -apply_transformation(const DerivativeForm<1, dim, spacedim, Number> &DF, - const Tensor<1, dim, Number> & T) +apply_transformation(const DerivativeForm<1, dim, spacedim, Number> &grad_F, + const Tensor<1, dim, Number> & d_x) { Tensor<1, spacedim, Number> dest; for (unsigned int i = 0; i < spacedim; ++i) - dest[i] = DF[i] * T; + dest[i] = grad_F[i] * d_x; return dest; } /** - * Similar to previous apply_transformation. It computes $T*DF^{T}$. + * Similar to the previous apply_transformation(). + * Each row of the result corresponds to one of the rows of @p D_X transformed + * by @p grad_F, equivalent to $\text{D\_X} \, \text{grad\_F}^T$ in matrix notation. * * @relatesalso DerivativeForm - * @author Sebastian Pauletti, 2011 + * @author Sebastian Pauletti, 2011, Reza Rastak, 2019 */ // rank=2 template inline DerivativeForm<1, spacedim, dim> -apply_transformation(const DerivativeForm<1, dim, spacedim, Number> &DF, - const Tensor<2, dim, Number> & T) +apply_transformation(const DerivativeForm<1, dim, spacedim, Number> &grad_F, + const Tensor<2, dim, Number> & D_X) { DerivativeForm<1, spacedim, dim> dest; for (unsigned int i = 0; i < dim; ++i) - dest[i] = apply_transformation(DF, T[i]); + dest[i] = apply_transformation(grad_F, D_X[i]); return dest; } /** - * Similar to previous apply_transformation. It computes $DF2*DF1^{T}$ + * Similar to the previous apply_transformation(). In matrix notation, it + * computes $DF2 \, DF1^{T}$. Moreover, the result of this operation $\mathbf A$ + * can be interpreted as a metric tensor in + * ${\mathbb R}^\text{spacedim}$ which corresponds to the Euclidean metric + * tensor in + * ${\mathbb R}^\text{dim}$. For every pair of vectors + * $\mathbf u, \mathbf v \in {\mathbb R}^\text{spacedim}$, we have: + * @f[ + * \mathbf u \cdot \mathbf A \mathbf v = + * \text{DF2}^{-1}(\mathbf u) \cdot \text{DF1}^{-1}(\mathbf v) + * @f] * * @relatesalso DerivativeForm - * @author Sebastian Pauletti, 2011 + * @author Sebastian Pauletti, 2011, Reza Rastak, 2019 */ template inline Tensor<2, spacedim, Number> diff --git a/include/deal.II/base/exceptions.h b/include/deal.II/base/exceptions.h index 2f254faf9020..7ae5571d7d91 100644 --- a/include/deal.II/base/exceptions.h +++ b/include/deal.II/base/exceptions.h @@ -185,7 +185,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -210,7 +210,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -246,7 +246,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -283,7 +283,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -322,7 +322,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -363,7 +363,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -409,7 +409,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -461,7 +461,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -485,7 +485,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -507,7 +507,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -530,7 +530,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -553,7 +553,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -576,7 +576,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -602,7 +602,7 @@ class ExceptionBase : public std::exception * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1393,7 +1393,7 @@ namespace deal_II_exceptions * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1456,7 +1456,7 @@ namespace deal_II_exceptions * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1505,7 +1505,7 @@ namespace deal_II_exceptions * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1555,7 +1555,7 @@ namespace deal_II_exceptions * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1583,7 +1583,7 @@ namespace deal_II_exceptions * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1625,7 +1625,7 @@ namespace internal * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1657,7 +1657,7 @@ namespace internal * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1682,7 +1682,7 @@ namespace internal * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1709,7 +1709,7 @@ namespace internal * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1737,7 +1737,7 @@ namespace internal * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1766,7 +1766,7 @@ namespace internal * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1797,7 +1797,7 @@ namespace internal * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other @@ -1829,7 +1829,7 @@ namespace internal * them unique to deal.II. As a consequence, it is possible that other * libraries your code interfaces with define the same name, and the result * will be name collisions (see - * https://en.wikipedia.org/wiki/Name_collision). One can #undef + * https://en.wikipedia.org/wiki/Name_collision). One can \#undef * this macro, as well as all other macros defined by deal.II that are not * prefixed with either DEAL or deal, by including * the header deal.II/base/undefine_macros.h after all other diff --git a/include/deal.II/base/function.h b/include/deal.II/base/function.h index cb5789440959..606d7fa1aa3f 100644 --- a/include/deal.II/base/function.h +++ b/include/deal.II/base/function.h @@ -704,6 +704,7 @@ class ComponentSelectFunction : public ConstantFunction * @endcode * The savings in work to write this are apparent. * + * @ingroup functions * @author Wolfgang Bangerth, 2011 */ template @@ -761,7 +762,8 @@ class ScalarFunctionFromFunctionObject : public Function * return 1.0; * } * - * VectorFunctionFromScalarFunctionObject<2> component_mask(&one, 1, 3); + * VectorFunctionFromScalarFunctionObject<2, RangeNumberType> + * component_mask(&one, 1, 3); * @endcode * Here, component_mask then represents a Function object that * for every point returns the vector $(0, 1, 0)^T$, i.e. a mask function that @@ -770,6 +772,7 @@ class ScalarFunctionFromFunctionObject : public Function * obviously easily extended to functions that are non-constant in their one * component. * + * @ingroup functions * @author Wolfgang Bangerth, 2011 */ template @@ -825,6 +828,143 @@ class VectorFunctionFromScalarFunctionObject }; +/** + * This class is similar to the ScalarFunctionFromFunctionObject and + * VectorFunctionFromFunctionObject classes in that it allows for the easy + * conversion of a vector of function objects to something that satisfies the + * interface of the Function base class. + * + * The difference is that here the Function object generated may be vector + * valued, and you can specify the gradients of the function. The number of + * vector components is deduced from the size of the vector in the constructor. + * + * To be more concrete, let us consider the following example: + * @code + * RangeNumberType + * first_component(const Point<2> &p) + * { + * return 1.0; + * } + * + * RangeNumberType + * second_component(const Point<2> &p) + * { + * return 2.0; + * } + * + * Tensor<1, 2, RangeNumberType> + * zero_gradient(const Point<2> &) { + * return Tensor<1, 2, RangeNumberType>(); + * } + * + * FunctionFromFunctionObjects<2, RangeNumberType> + * custom_function({&first_component, &second_component}, + * {&zero_gradient, &zero_gradient}); + * @endcode + * + * @author Luca Heltai, 2019 + */ +template +class FunctionFromFunctionObjects : public Function +{ +public: + /** + * Default constructor. + * + * This constructor does not initialize the internal methods. To have a + * usable function, you need to call at least the set_function_values() + * method. If you need also the gradients of the solution, then you must + * also call the set_function_gradients() method. + */ + explicit FunctionFromFunctionObjects(const unsigned int n_components = 1, + const double initial_time = 0); + + /** + * Constructor for functions of which you only know the values. + * + * The resulting function will have a number of components equal to the size + * of the vector @p values. A call to the FunctionFromFunctionObject::gradient() + * method will trigger an exception, unless you first call the + * set_function_gradients() method. + */ + FunctionFromFunctionObjects( + const std::vector &)>> + & values, + const double initial_time = 0.0); + + /** + * Constructor for functions of which you know both the values and the + * gradients. + * + * The resulting function will have a number of components equal to the size + * of the vector @p values. If the size of @p values and @p gradients does not + * match, an exception is triggered. + */ + FunctionFromFunctionObjects( + const std::vector &)>> + &values, + const std::vector< + std::function(const Point &)>> + & gradients, + const double initial_time = 0.0); + + + /** + * Return the value of the function at the given point. Unless there is only + * one component (i.e. the function is scalar), you should state the + * component you want to have evaluated; it defaults to zero, i.e. the first + * component. + */ + virtual RangeNumberType + value(const Point &p, const unsigned int component = 0) const override; + + /** + * Return the gradient of the function at the given point. Unless there is + * only one component (i.e. the function is scalar), you should state the + * component you want to have evaluated; it defaults to zero, i.e. the first + * component. + */ + virtual Tensor<1, dim, RangeNumberType> + gradient(const Point & p, + const unsigned int component = 0) const override; + + /** + * Reset the function values of this object. An assertion is thrown if the + * size of the @p values parameter does not match the number of components of + * this object. + */ + void + set_function_values( + const std::vector &)>> + &values); + + /** + * Reset the function gradients of this object. An assertion is thrown if the + * size of the @p gradients parameter does not match the number of components of + * this object. + */ + void + set_function_gradients( + const std::vector< + std::function(const Point &)>> + &gradients); + +private: + /** + * The actual function values. + */ + std::vector &)>> + function_values; + + /** + * The actual function gradients. + */ + std::vector< + std::function(const Point &)>> + function_gradients; +}; + + /** * This class is built as a means of translating the Tensor<1,dim, * RangeNumberType> values produced by objects of type TensorFunction @@ -858,6 +998,7 @@ class VectorFunctionFromScalarFunctionObject * where the dim components of the tensor function are placed * into the first dim components of the function object. * + * @ingroup functions * @author Spencer Patty, 2013 */ template diff --git a/include/deal.II/base/function.templates.h b/include/deal.II/base/function.templates.h index 3cab781f8188..8fd0d49d08ac 100644 --- a/include/deal.II/base/function.templates.h +++ b/include/deal.II/base/function.templates.h @@ -783,6 +783,96 @@ VectorFunctionFromTensorFunction::vector_value_list( } + +template +FunctionFromFunctionObjects::FunctionFromFunctionObjects( + const unsigned int n_components, + const double initial_time) + : Function(n_components, initial_time) + , function_values(n_components) + , function_gradients(n_components) +{} + + + +template +FunctionFromFunctionObjects::FunctionFromFunctionObjects( + const std::vector &)>> &values, + const double initial_time) + : Function(values.size(), initial_time) + , function_values(values) + , function_gradients(values.size()) +{} + + + +template +FunctionFromFunctionObjects::FunctionFromFunctionObjects( + const std::vector &)>> &values, + const std::vector< + std::function(const Point &)>> + & gradients, + const double initial_time) + : Function(values.size(), initial_time) + , function_values(values) + , function_gradients(gradients) +{} + + + +template +RangeNumberType +FunctionFromFunctionObjects::value( + const Point & p, + const unsigned int component) const +{ + AssertIndexRange(component, this->n_components); + Assert(function_values[component], + ExcMessage("Accessing value() in FunctionFromFunctionObjects requires " + "setting the std::function objects for the value")); + return function_values[component](p); +} + + + +template +Tensor<1, dim, RangeNumberType> +FunctionFromFunctionObjects::gradient( + const Point & p, + const unsigned int component) const +{ + AssertIndexRange(component, this->n_components); + Assert(function_gradients[component], + ExcMessage( + "Accessing gradient() in FunctionFromFunctionObjects " + "requires setting the std::function objects for the gradient")); + return function_gradients[component](p); +} + + + +template +void +FunctionFromFunctionObjects::set_function_values( + const std::vector &)>> &values) +{ + AssertDimension(this->n_components, values.size()); + function_values = values; +} + + + +template +void +FunctionFromFunctionObjects::set_function_gradients( + const std::vector< + std::function(const Point &)>> + &gradients) +{ + AssertDimension(this->n_components, gradients.size()); + function_gradients = gradients; +} + DEAL_II_NAMESPACE_CLOSE #endif /* dealii_function_templates_h */ diff --git a/include/deal.II/base/function_bessel.h b/include/deal.II/base/function_bessel.h index eb8824b6816d..6597f0a69fae 100644 --- a/include/deal.II/base/function_bessel.h +++ b/include/deal.II/base/function_bessel.h @@ -29,6 +29,7 @@ namespace Functions /** * The Bessel functions of first kind or positive integer order. * + * @ingroup functions * @author Guido Kanschat * @date 2010 */ diff --git a/include/deal.II/base/function_cspline.h b/include/deal.II/base/function_cspline.h index 2442827db7fd..9d6d99ce0d05 100644 --- a/include/deal.II/base/function_cspline.h +++ b/include/deal.II/base/function_cspline.h @@ -68,6 +68,7 @@ namespace Functions * * @note This function is only implemented for dim==1 . * + * @ingroup functions * @author Denis Davydov * @date 2016 */ diff --git a/include/deal.II/base/function_lib.h b/include/deal.II/base/function_lib.h index 30a49f3d0481..4e8645b7df65 100644 --- a/include/deal.II/base/function_lib.h +++ b/include/deal.II/base/function_lib.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -912,8 +913,12 @@ namespace Functions * radius of the supporting ball of a cut-off function. It also stores the * number of the non-zero component, if the function is vector-valued. * + * This class can also be used for approximated Dirac delta functions. These + * are special cut-off functions whose integral is always equal to one, + * independently of the radius of the supporting ball. + * * @ingroup functions - * @author Guido Kanschat, 2002 + * @author Guido Kanschat, 2002, Luca Heltai, 2019. */ template class CutOffFunctionBase : public Function @@ -926,29 +931,79 @@ namespace Functions static const unsigned int no_component = numbers::invalid_unsigned_int; /** - * Constructor. Arguments are the center of the ball and its radius. + * Constructor. * - * If an argument select is given and not -1, the cut-off - * function will be non-zero for this component only. + * @param[in] radius Radius of the ball + * @param[in] center Center of the ball + * @param[in] n_components Number of components of this function object + * @param[in] select If this is different from + * CutOffFunctionBase::no_component, then the function will be non-zero + * for this component only + * @param[in] integrate_to_one Rescale the value of the function whenever a + * new radius is set, to guarantee that the integral is equal to one + * @param[in] unitary_integral_value Value of the integral when the radius + * is equal to 1.0. Derived classes will need to supply this value, to + * guarantee that the rescaling is performed correctly. */ CutOffFunctionBase( - const double radius = 1., - const Point = Point(), + const double radius = 1., + const Point center = Point(), const unsigned int n_components = 1, - const unsigned int select = CutOffFunctionBase::no_component); + const unsigned int select = CutOffFunctionBase::no_component, + const bool integrate_to_one = false, + const double unitary_integral_value = 1.0); + + /** + * Virtual destructor. + */ + virtual ~CutOffFunctionBase() = default; /** * Move the center of the ball to new point p. + * + * @deprecated Use set_center() instead. */ - void + DEAL_II_DEPRECATED void new_center(const Point &p); /** * Set the radius of the ball to r. + * + * @deprecated Use set_radius() instead. */ - void + DEAL_II_DEPRECATED void new_radius(const double r); + /** + * Set the center of the ball to the point @p p. + */ + virtual void + set_center(const Point &p); + + /** + * Set the radius of the ball to @p r + */ + virtual void + set_radius(const double r); + + /** + * Return the center stored in this object. + */ + const Point & + get_center() const; + + /** + * Return the radius stored in this object. + */ + double + get_radius() const; + + /** + * Return a boolean indicating whether this function integrates to one. + */ + bool + integrates_to_one() const; + protected: /** * Center of the integration ball. @@ -965,6 +1020,92 @@ namespace Functions * in all components. */ const unsigned int selected; + + /** + * Flag that controls whether we rescale the value when the radius changes. + */ + bool integrate_to_one; + + /** + * The reference integral value. Derived classes should specify what their + * integral is when @p radius = 1.0. + */ + const double unitary_integral_value; + + /** + * Current rescaling to apply the the cut-off function. + */ + double rescaling; + }; + + + /** + * Tensor product of CutOffFunctionBase objects. + * + * Instead of using the distance to compute the cut-off function, this class + * performs a tensor product of the same CutOffFunctionBase object in each + * coordinate direction. + * + * @ingroup functions + * @author Luca Heltai, 2019. + */ + template + class CutOffFunctionTensorProduct : public CutOffFunctionBase + { + public: + /** + * Construct an empty CutOffFunctionTensorProduct object. + * + * Before you can use this class, you have to call the set_base() method + * with a class derived from the CutOffFunctionBase object. + * + * If you try to use this class before you call the set_base() method, + * and exception will be triggered. + */ + CutOffFunctionTensorProduct( + double radius = 1.0, + const Point & center = Point(), + const unsigned int n_components = 1, + const unsigned int select = CutOffFunctionBase::no_component, + const bool integrate_to_one = false); + + /** + * Initialize the class with an object of type + * @tparam CutOffFunctionBaseType<1>. + */ + template