From 6462b87e2e2bf691f04c89190c4ba1e72dac0f90 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 6 Dec 2018 14:37:14 +0100 Subject: [PATCH 001/507] Refactor the AD drivers classes. This commit significantly reworks the implementation of the AD driver classes. Firstly, all class methods are moved to the associated source file. The (logically) static class methods have been removed, so all methods must be called through an instance of a driver class. The previously implemented logic for existant ADOL-C tapes has been superceeded by low-level calls to the library itself. The ADHelper classes are updated to accommodate the changes to the driver classes. Fixes #7335 Fixes #7372 --- .../deal.II/differentiation/ad/ad_drivers.h | 1577 +++--------- .../deal.II/differentiation/ad/ad_helpers.h | 3 + source/differentiation/ad/CMakeLists.txt | 5 +- source/differentiation/ad/ad_drivers.cc | 2258 +++++++++++++++++ source/differentiation/ad/ad_drivers.inst1.in | 73 + source/differentiation/ad/ad_drivers.inst2.in | 83 + source/differentiation/ad/ad_helpers.cc | 61 +- 7 files changed, 2808 insertions(+), 1252 deletions(-) create mode 100644 source/differentiation/ad/ad_drivers.cc create mode 100644 source/differentiation/ad/ad_drivers.inst1.in create mode 100644 source/differentiation/ad/ad_drivers.inst2.in diff --git a/include/deal.II/differentiation/ad/ad_drivers.h b/include/deal.II/differentiation/ad/ad_drivers.h index 05ec55840673..5af046665bf6 100644 --- a/include/deal.II/differentiation/ad/ad_drivers.h +++ b/include/deal.II/differentiation/ad/ad_drivers.h @@ -20,12 +20,9 @@ #include #include -#include #include #include -#include -#include #include #include @@ -33,10 +30,7 @@ #ifdef DEAL_II_WITH_ADOLC DEAL_II_DISABLE_EXTRA_DIAGNOSTICS -# include -# include # include -# include DEAL_II_ENABLE_EXTRA_DIAGNOSTICS #endif // DEAL_II_WITH_ADOLC @@ -136,7 +130,7 @@ namespace Differentiation /** - * A driver class for taped auto-differentiable numbers. + * A prototype driver class for taped auto-differentiable numbers. * * It is intended that this class be specialized for the valid * combinations of auto-differentiable numbers and output scalar @@ -258,6 +252,12 @@ namespace Differentiation const typename Types::tape_index active_tape_index, const bool write_tapes_to_file); + /** + * Return a list of registered tape indices. + */ + std::vector::tape_index> + get_registered_tape_indices() const; + /** * Select a tape to record to or read from. * @@ -275,6 +275,39 @@ namespace Differentiation void activate_tape(const typename Types::tape_index tape_index); + /** + * Return a flag that, when true, indicates that the retaping + * of the dependent function for the chosen @p tape_index is necessary for + * a reliable computation to be performed. + * This may be necessary a sign comparison within branched operations + * yields different results to those computed at the original tape + * evaluation point. + * + * @note The chosen tape index must be greater than + * Numbers::invalid_tape_index and less than + * Numbers::max_tape_index. + */ + bool + requires_retaping( + const typename Types::tape_index tape_index) const; + + /** + * Return a flag that, when true, indicates that the retaping + * of the dependent function is necessary for a reliable computation to be + * performed on the active tape. + * This may be necessary a sign comparison within branched operations + * yields different results to those computed at the original tape + * evaluation point. + */ + bool + last_action_requires_retaping() const; + + /** + * Completely erases the tape with the given @p tape_index. + */ + void + remove_tape(const typename Types::tape_index tape_index); + /** * Reset the state of the class. * @@ -302,10 +335,10 @@ namespace Differentiation * @param[out] stream The output stream to which the values are to be * written. */ - static void + void print_tape_stats( const typename Types::tape_index tape_index, - std::ostream & stream); + std::ostream & stream) const; //@} @@ -324,9 +357,9 @@ namespace Differentiation * * @return The scalar value of the function. */ - static ScalarType + ScalarType value(const typename Types::tape_index active_tape_index, - const std::vector &independent_variables); + const std::vector &independent_variables) const; /** * Compute the gradient of the scalar field with respect to all @@ -341,10 +374,10 @@ namespace Differentiation * correct size (with length * n_independent_variables). */ - static void + void gradient(const typename Types::tape_index active_tape_index, const std::vector &independent_variables, - Vector & gradient); + Vector & gradient) const; /** * Compute the Hessian of the scalar field with respect to all @@ -359,10 +392,10 @@ namespace Differentiation * size (with dimensions * n_independent_variables$\times$n_independent_variables). */ - static void + void hessian(const typename Types::tape_index active_tape_index, const std::vector &independent_variables, - FullMatrix & hessian); + FullMatrix & hessian) const; //@} @@ -383,11 +416,11 @@ namespace Differentiation * It is expected that this vector be of the correct size * (with length n_dependent_variables). */ - static void + void values(const typename Types::tape_index active_tape_index, const unsigned int n_dependent_variables, const std::vector &independent_variables, - Vector & values); + Vector & values) const; /** * Compute the Jacobian of the vector field. @@ -407,11 +440,11 @@ namespace Differentiation * size (with dimensions * n_dependent_variables$\times$n_independent_variables). */ - static void + void jacobian(const typename Types::tape_index active_tape_index, const unsigned int n_dependent_variables, const std::vector &independent_variables, - FullMatrix & jacobian); + FullMatrix & jacobian) const; //@} }; @@ -510,8 +543,8 @@ namespace Differentiation * * @return The scalar value of the function. */ - static ScalarType - value(const std::vector &dependent_variables); + ScalarType + value(const std::vector &dependent_variables) const; /** * Compute the gradient of the scalar field with respect to all @@ -526,10 +559,10 @@ namespace Differentiation * correct size (with length * n_independent_variables). */ - static void + void gradient(const std::vector &independent_variables, const std::vector &dependent_variables, - Vector & gradient); + Vector & gradient) const; /** * Compute the Hessian of the scalar field with respect to all @@ -544,10 +577,10 @@ namespace Differentiation * size (with dimensions * n_independent_variables$\times$n_independent_variables). */ - static void + void hessian(const std::vector &independent_variables, const std::vector &dependent_variables, - FullMatrix & hessian); + FullMatrix & hessian) const; //@} @@ -565,9 +598,9 @@ namespace Differentiation * It is expected that this vector be of the correct size * (with length n_dependent_variables). */ - static void + void values(const std::vector &dependent_variables, - Vector & values); + Vector & values) const; /** * Compute the Jacobian of the vector field. @@ -586,10 +619,10 @@ namespace Differentiation * size (with dimensions * n_dependent_variables$\times$n_independent_variables). */ - static void + void jacobian(const std::vector &independent_variables, const std::vector &dependent_variables, - FullMatrix & jacobian); + FullMatrix & jacobian) const; //@} }; @@ -608,170 +641,6 @@ namespace Differentiation { namespace AD { - // ------------- TapedDrivers ------------- - - - template - bool - TapedDrivers::is_recording() const - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - return false; - } - - - template - typename Types::tape_index - TapedDrivers::active_tape_index() const - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - return Numbers::invalid_tape_index; - } - - - template - bool - TapedDrivers::is_registered_tape( - const typename Types::tape_index) const - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - return false; - } - - - template - bool - TapedDrivers::keep_independent_values() const - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - return false; - } - - - template - void - TapedDrivers::set_tape_buffer_sizes( - const typename Types::tape_buffer_sizes, - const typename Types::tape_buffer_sizes, - const typename Types::tape_buffer_sizes, - const typename Types::tape_buffer_sizes) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapedDrivers::start_taping( - const typename Types::tape_index, - const bool) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapedDrivers::stop_taping( - const typename Types::tape_index, - const bool) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapedDrivers::activate_tape( - const typename Types::tape_index) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapedDrivers::reset(const bool) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapedDrivers::print(std::ostream &) const - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapedDrivers::print_tape_stats( - const typename Types::tape_index, - std::ostream &) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - ScalarType - TapedDrivers::value( - const typename Types::tape_index, - const std::vector &) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - return ScalarType(0.0); - } - - - template - void - TapedDrivers::gradient( - const typename Types::tape_index, - const std::vector &, - Vector &) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapedDrivers::hessian( - const typename Types::tape_index, - const std::vector &, - FullMatrix &) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapedDrivers::values( - const typename Types::tape_index, - const unsigned int, - const std::vector &, - Vector &) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapedDrivers::jacobian( - const typename Types::tape_index, - const unsigned int, - const std::vector &, - FullMatrix &) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - # ifdef DEAL_II_WITH_ADOLC /** @@ -846,309 +715,114 @@ namespace Differentiation { using scalar_type = double; - TapedDrivers() - : active_tape(Numbers::invalid_tape_index) - , keep_values(true) - , is_recording_flag(false) - , use_stored_taped_buffer_sizes(false) - , obufsize(0u) - , lbufsize(0u) - , vbufsize(0u) - , tbufsize(0u) - {} + /** + * Constructor + */ + TapedDrivers(); + - // === Taping === + /** + * @name Taping + */ + //@{ bool - is_recording() const - { - return is_recording_flag; - } + is_recording() const; typename Types::tape_index - active_tape_index() const - { - return active_tape; - } + active_tape_index() const; bool - keep_independent_values() const - { - return keep_values; - } + keep_independent_values() const; bool is_registered_tape( - const typename Types::tape_index tape_index) const - { - // See https://gitlab.com/adol-c/adol-c/issues/11#note_108341333 - try - { - std::vector counts(STAT_SIZE); - ::tapestats(tape_index, counts.data()); - return true; - } - catch (const ::FatalError &exc) - { - return false; - } - } + const typename Types::tape_index tape_index) const; void set_tape_buffer_sizes( const typename Types::tape_buffer_sizes in_obufsize, const typename Types::tape_buffer_sizes in_lbufsize, const typename Types::tape_buffer_sizes in_vbufsize, - const typename Types::tape_buffer_sizes in_tbufsize) - { - // When valid for the chosen AD number type, these values will be used - // the next time start_recording_operations() is called. - obufsize = in_obufsize; - lbufsize = in_lbufsize; - vbufsize = in_vbufsize; - tbufsize = in_tbufsize; - use_stored_taped_buffer_sizes = true; - } + const typename Types::tape_buffer_sizes in_tbufsize); void start_taping(const typename Types::tape_index tape_index, - const bool keep_independent_values) - { - if (use_stored_taped_buffer_sizes) - trace_on(tape_index, - keep_independent_values, - obufsize, - lbufsize, - vbufsize, - tbufsize); - else - trace_on(tape_index, keep_independent_values); - - // Set some other flags to their indicated / required values - keep_values = keep_independent_values; - is_recording_flag = true; - } + const bool keep_independent_values); void stop_taping( const typename Types::tape_index active_tape_index, - const bool write_tapes_to_file) - { - if (write_tapes_to_file) - trace_off(active_tape_index); // Slow - else - trace_off(); // Fast(er) - - // Now that we've turned tracing off, we've definitely - // stopped all tape recording. - is_recording_flag = false; - - // If the keep_values flag is set, then we expect the user to use this - // tape immediately after recording it. There is therefore no need to - // invalidate it. However, there is now also no way to double-check - // that the newly recorded tape is indeed the active tape. - if (keep_independent_values() == false) - active_tape = Numbers::invalid_tape_index; - } - - void - activate_tape(const typename Types::tape_index tape_index) - { - active_tape = tape_index; - } - - void - reset(const bool clear_registered_tapes) - { - active_tape = Numbers::invalid_tape_index; - is_recording_flag = false; - if (clear_registered_tapes) - { - const std::vector::tape_index> - registered_tape_indices = get_registered_tape_indices(); - for (const auto &tape_index : registered_tape_indices) - removeTape(tape_index, TapeRemovalType::ADOLC_REMOVE_COMPLETELY); - } - } - - void - print(std::ostream &stream) const - { - const std::vector::tape_index> - registered_tape_indices = get_registered_tape_indices(); - stream << "Registered tapes: "; - auto it_registered_tape = registered_tape_indices.begin(); - for (unsigned int i = 0; i < registered_tape_indices.size(); - ++i, ++it_registered_tape) - stream << *it_registered_tape - << (i < (registered_tape_indices.size() - 1) ? "," : ""); - stream << "\n"; - - stream << "Keep values? " << keep_independent_values() << "\n"; - stream << "Use stored tape buffer sizes? " - << use_stored_taped_buffer_sizes << "\n"; - } + const bool write_tapes_to_file); - static void + std::vector::tape_index> + get_registered_tape_indices() const; + + void + activate_tape(const typename Types::tape_index tape_index); + + bool + requires_retaping( + const typename Types::tape_index tape_index) const; + + bool + last_action_requires_retaping() const; + + void + remove_tape(const typename Types::tape_index tape_index); + + void + reset(const bool clear_registered_tapes); + + void + print(std::ostream &stream) const; + + void print_tape_stats( const typename Types::tape_index tape_index, - std::ostream & stream) - { - // See ADOL-C manual section 2.1 - // and adolc/taping.h - std::vector counts(STAT_SIZE); - ::tapestats(tape_index, counts.data()); - Assert(counts.size() >= 18, ExcInternalError()); - stream - << "Tape index: " << tape_index << "\n" - << "Number of independent variables: " << counts[0] << "\n" - << "Number of dependent variables: " << counts[1] << "\n" - << "Max number of live, active variables: " << counts[2] << "\n" - << "Size of taylor stack (number of overwrites): " << counts[3] - << "\n" - << "Operations buffer size: " << counts[4] << "\n" - << "Total number of recorded operations: " << counts[5] << "\n" - << "Operations file written or not: " << counts[6] << "\n" - << "Overall number of locations: " << counts[7] << "\n" - << "Locations file written or not: " << counts[8] << "\n" - << "Overall number of values: " << counts[9] << "\n" - << "Values file written or not: " << counts[10] << "\n" - << "Locations buffer size: " << counts[11] << "\n" - << "Values buffer size: " << counts[12] << "\n" - << "Taylor buffer size: " << counts[13] << "\n" - << "Number of eq_*_prod for sparsity pattern: " << counts[14] << "\n" - << "Use of 'min_op', deferred to 'abs_op' for piecewise calculations: " - << counts[15] << "\n" - << "Number of 'abs' calls that can switch branch: " << counts[16] - << "\n" - << "Number of parameters (doubles) interchangeable without retaping: " - << counts[17] << "\n" - << std::flush; - } - - - // === Scalar drivers === - - static scalar_type - value(const typename Types::tape_index active_tape_index, - const std::vector &independent_variables) - { - scalar_type value = 0.0; + std::ostream & stream) const; + + //@} - ::function(active_tape_index, - 1, // Only one dependent variable - independent_variables.size(), - const_cast(independent_variables.data()), - &value); + /** + * @name Drivers for scalar functions (one dependent variable) + */ + //@{ - return value; - } + scalar_type + value(const typename Types::tape_index active_tape_index, + const std::vector &independent_variables) const; - static void + void gradient(const typename Types::tape_index active_tape_index, const std::vector &independent_variables, - Vector & gradient) - { - Assert( - AD::ADNumberTraits::n_supported_derivative_levels >= 1, - ExcSupportedDerivativeLevels( - AD::ADNumberTraits::n_supported_derivative_levels, - 1)); - Assert(gradient.size() == independent_variables.size(), - ExcDimensionMismatch(gradient.size(), - independent_variables.size())); - - // Note: ADOL-C's ::gradient function expects a *double as the last - // parameter. Here we take advantage of the fact that the data in the - // Vector class is aligned (e.g. stored as an Array) - ::gradient(active_tape_index, - independent_variables.size(), - const_cast(independent_variables.data()), - gradient.data()); - } + Vector & gradient) const; - static void + void hessian(const typename Types::tape_index active_tape_index, const std::vector &independent_variables, - FullMatrix & hessian) - { - Assert( - AD::ADNumberTraits::n_supported_derivative_levels >= 2, - ExcSupportedDerivativeLevels( - AD::ADNumberTraits::n_supported_derivative_levels, - 2)); - Assert(hessian.m() == independent_variables.size(), - ExcDimensionMismatch(hessian.m(), independent_variables.size())); - Assert(hessian.n() == independent_variables.size(), - ExcDimensionMismatch(hessian.n(), independent_variables.size())); - - const unsigned int n_independent_variables = - independent_variables.size(); - std::vector H(n_independent_variables); - for (unsigned int i = 0; i < n_independent_variables; ++i) - H[i] = &hessian[i][0]; - - ::hessian(active_tape_index, - n_independent_variables, - const_cast(independent_variables.data()), - H.data()); - - // ADOL-C builds only the lower-triangular part of the - // symmetric Hessian, so we should copy the relevant - // entries into the upper triangular part. - for (unsigned int i = 0; i < n_independent_variables; i++) - for (unsigned int j = 0; j < i; j++) - hessian[j][i] = hessian[i][j]; // Symmetry - } - - // === Vector drivers === + FullMatrix & hessian) const; - static void + //@} + + /** + * @name Drivers for vector functions (multiple dependent variables) + */ + //@{ + + void values(const typename Types::tape_index active_tape_index, const unsigned int n_dependent_variables, const std::vector &independent_variables, - Vector & values) - { - Assert(values.size() == n_dependent_variables, - ExcDimensionMismatch(values.size(), n_dependent_variables)); - - // Note: ADOL-C's ::function function expects a *double as the last - // parameter. Here we take advantage of the fact that the data in the - // Vector class is aligned (e.g. stored as an Array) - ::function(active_tape_index, - n_dependent_variables, - independent_variables.size(), - const_cast(independent_variables.data()), - values.data()); - } + Vector & values) const; - static void + void jacobian(const typename Types::tape_index active_tape_index, const unsigned int n_dependent_variables, const std::vector &independent_variables, - FullMatrix & jacobian) - { - Assert( - AD::ADNumberTraits::n_supported_derivative_levels >= 1, - ExcSupportedDerivativeLevels( - AD::ADNumberTraits::n_supported_derivative_levels, - 1)); - Assert(jacobian.m() == n_dependent_variables, - ExcDimensionMismatch(jacobian.m(), n_dependent_variables)); - Assert(jacobian.n() == independent_variables.size(), - ExcDimensionMismatch(jacobian.n(), - independent_variables.size())); - - std::vector J(n_dependent_variables); - for (unsigned int i = 0; i < n_dependent_variables; ++i) - J[i] = &jacobian[i][0]; - - ::jacobian(active_tape_index, - n_dependent_variables, - independent_variables.size(), - independent_variables.data(), - J.data()); - } + FullMatrix & jacobian) const; + + //@} protected: /** @@ -1171,6 +845,33 @@ namespace Differentiation */ bool is_recording_flag; + /** + * The status of the last function or derivative evaluation performed on + * the selected tape. As quoted from the ADOL-C manual, this can take + * on one of six different values with the following interpretation: + * + * - +3: The function is locally analytic. + * - +2: The function is locally analytic but the sparsity + * structure (compared to the situation at the taping point) may have + * changed, e.g. while at taping arguments fmax(a,b) + * returned a, we get b at the argument + * currently used. + * - +1: At least one of the functions fmin, + * fmax or fabs is evaluated at a tie or + * zero, respectively. Hence, the function to be differentiated is + * Lipschitz-continuous but possibly non-differentiable. + * - 0: Some arithmetic comparison involving adoubles yields a + * tie. Hence, the function to be differentiated may be discontinuous. + * - -1: An adouble comparison yields different + * results from the evaluation point at which the tape was generated. + * - -2: The argument of a user-defined quadrature has changed from + * the evaluation point at which the tape was generated. + * + * When the @p status variable takes a negative value, retaping of the dependent + * function is necessary for a reliable computation to be performed. + */ + mutable std::map::tape_index, int> status; + /** * A flag indicating that we should preferentially use the user-defined * taped buffer sizes as opposed to either the default values selected @@ -1198,30 +899,9 @@ namespace Differentiation * ADOL-C Taylor buffer size. */ typename Types::tape_buffer_sizes tbufsize; - - /** - * Return a list of registered tape indices - */ - std::vector::tape_index> - get_registered_tape_indices() const - { - // We've chosen to use unsigned shorts for the tape - // index type (a safety precaution) so we need to - // perform a conversion betwwen ADOL-C's native tape - // index type and that chosen by us. - std::vector registered_tape_indices_s; - cachedTraceTags(registered_tape_indices_s); - - std::vector::tape_index> - registered_tape_indices(registered_tape_indices_s.size()); - std::copy(registered_tape_indices_s.begin(), - registered_tape_indices_s.end(), - registered_tape_indices.begin()); - return registered_tape_indices; - } }; -# else // DEAL_II_WITH_ADOLC +# else /** * Specialization for taped ADOL-C auto-differentiable numbers. @@ -1229,7 +909,7 @@ namespace Differentiation * Although we could revert to the default definition for the * unspecialized TapedDrivers class, we add this specialization * to provide a more descriptive error message if any of its - * static member functions are called. + * member functions are called. */ template struct TapedDrivers< @@ -1240,134 +920,107 @@ namespace Differentiation { using scalar_type = double; - // === Taping === + /** + * @name Taping + */ + //@{ bool - is_recording() const - { - AssertThrow(false, ExcRequiresADOLC()); - return false; - } + is_recording() const; typename Types::tape_index - active_tape_index() const - { - AssertThrow(false, ExcRequiresADOLC()); - return Numbers::invalid_tape_index; - } + active_tape_index() const; bool - keep_independent_values() const - { - AssertThrow(false, ExcRequiresADOLC()); - return false; - } + keep_independent_values() const; bool - is_registered_tape(const typename Types::tape_index) const - { - AssertThrow(false, ExcRequiresADOLC()); - return false; - } + is_registered_tape( + const typename Types::tape_index tape_index) const; void set_tape_buffer_sizes( const typename Types::tape_buffer_sizes, const typename Types::tape_buffer_sizes, const typename Types::tape_buffer_sizes, - const typename Types::tape_buffer_sizes) - { - AssertThrow(false, ExcRequiresADOLC()); - } + const typename Types::tape_buffer_sizes); void - start_taping(const typename Types::tape_index, const bool) - { - AssertThrow(false, ExcRequiresADOLC()); - } + start_taping(const typename Types::tape_index, const bool); void - stop_taping(const typename Types::tape_index, const bool) - { - AssertThrow(false, ExcRequiresADOLC()); - } + stop_taping(const typename Types::tape_index, const bool); + + std::vector::tape_index> + get_registered_tape_indices() const; void - activate_tape(const typename Types::tape_index) - { - AssertThrow(false, ExcRequiresADOLC()); - } + activate_tape(const typename Types::tape_index); + + bool + requires_retaping(const typename Types::tape_index) const; + + bool + last_action_requires_retaping() const; void - reset(const bool) - { - AssertThrow(false, ExcRequiresADOLC()); - } + remove_tape(const typename Types::tape_index); void - print(std::ostream &) const - { - AssertThrow(false, ExcRequiresADOLC()); - } + reset(const bool); - static void + void + print(std::ostream &stream) const; + + void print_tape_stats(const typename Types::tape_index, - std::ostream &) - { - AssertThrow(false, ExcRequiresADOLC()); - } + std::ostream &) const; + //@} - // === Scalar drivers === + /** + * @name Drivers for scalar functions (one dependent variable) + */ + //@{ - static scalar_type + scalar_type value(const typename Types::tape_index, - const std::vector &) - { - AssertThrow(false, ExcRequiresADOLC()); - return 0.0; - } + const std::vector &) const; - static void + void gradient(const typename Types::tape_index, const std::vector &, - Vector &) - { - AssertThrow(false, ExcRequiresADOLC()); - } + Vector &) const; - static void + void hessian(const typename Types::tape_index, const std::vector &, - FullMatrix &) - { - AssertThrow(false, ExcRequiresADOLC()); - } + FullMatrix &) const; - // === Vector drivers === + //@} - static void + /** + * @name Drivers for vector functions (multiple dependent variables) + */ + //@{ + + void values(const typename Types::tape_index, const unsigned int, const std::vector &, - Vector &) - { - AssertThrow(false, ExcRequiresADOLC()); - } + Vector &) const; - static void + void jacobian(const typename Types::tape_index, const unsigned int, const std::vector &, - FullMatrix &) - { - AssertThrow(false, ExcRequiresADOLC()); - } + FullMatrix &) const; + + //@} }; # endif // DEAL_II_WITH_ADOLC - /** * Specialization for ADOL-C taped numbers. It is expected that the * scalar return type for this class is a float. @@ -1385,191 +1038,115 @@ namespace Differentiation { using scalar_type = float; - // === Taping === + /** + * @name Taping + */ + //@{ bool - is_recording() const - { - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - return taped_driver.is_recording(); - } + is_recording() const; typename Types::tape_index - active_tape_index() const - { - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - return taped_driver.active_tape_index(); - } + active_tape_index() const; bool - keep_independent_values() const - { - return taped_driver.keep_independent_values(); - } + keep_independent_values() const; bool is_registered_tape( - const typename Types::tape_index tape_index) const - { - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - return taped_driver.is_registered_tape(tape_index); - } + const typename Types::tape_index tape_index) const; void set_tape_buffer_sizes( const typename Types::tape_buffer_sizes obufsize, const typename Types::tape_buffer_sizes lbufsize, const typename Types::tape_buffer_sizes vbufsize, - const typename Types::tape_buffer_sizes tbufsize) - { - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - taped_driver.set_tape_buffer_sizes(obufsize, - lbufsize, - vbufsize, - tbufsize); - } + const typename Types::tape_buffer_sizes tbufsize); void start_taping(const typename Types::tape_index tape_index, - const bool keep_independent_values) - { - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - taped_driver.start_taping(tape_index, keep_independent_values); - } + const bool keep_independent_values); void stop_taping( const typename Types::tape_index active_tape_index, - const bool write_tapes_to_file) - { - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - taped_driver.stop_taping(active_tape_index, write_tapes_to_file); - } + const bool write_tapes_to_file); + + std::vector::tape_index> + get_registered_tape_indices() const; + + void + activate_tape(const typename Types::tape_index tape_index); + + bool + requires_retaping( + const typename Types::tape_index tape_index) const; + + bool + last_action_requires_retaping() const; void - activate_tape(const typename Types::tape_index tape_index) - { - taped_driver.activate_tape(tape_index); - } + remove_tape(const typename Types::tape_index tape_index); void - reset(const bool clear_registered_tapes) - { - taped_driver.reset(clear_registered_tapes); - } + reset(const bool clear_registered_tapes); void - print(std::ostream &stream) const - { - taped_driver.print(stream); - } + print(std::ostream &stream) const; - static void + void print_tape_stats( const typename Types::tape_index tape_index, - std::ostream & stream) - { - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - TapedDrivers::print_tape_stats(tape_index, - stream); - } + std::ostream & stream) const; + + //@} - // === Scalar drivers === + /** + * @name Drivers for scalar functions (one dependent variable) + */ + //@{ - static scalar_type + scalar_type value(const typename Types::tape_index active_tape_index, - const std::vector &independent_variables) - { - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - return TapedDrivers::value( - active_tape_index, vector_float_to_double(independent_variables)); - } + const std::vector &independent_variables) const; - static void + void gradient(const typename Types::tape_index active_tape_index, const std::vector &independent_variables, - Vector & gradient) - { - Vector gradient_double(gradient.size()); - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - TapedDrivers::gradient(active_tape_index, - vector_float_to_double( - independent_variables), - gradient_double); - gradient = gradient_double; - } + Vector & gradient) const; - static void + void hessian(const typename Types::tape_index active_tape_index, const std::vector &independent_variables, - FullMatrix & hessian) - { - FullMatrix hessian_double(hessian.m(), hessian.n()); - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - TapedDrivers::hessian(active_tape_index, - vector_float_to_double( - independent_variables), - hessian_double); - hessian = hessian_double; - } - - // === Vector drivers === + FullMatrix & hessian) const; - static void + //@} + + /** + * @name Drivers for vector functions (multiple dependent variables) + */ + //@{ + + void values(const typename Types::tape_index active_tape_index, const unsigned int n_dependent_variables, const std::vector &independent_variables, - Vector & values) - { - Vector values_double(values.size()); - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - TapedDrivers::values(active_tape_index, - n_dependent_variables, - vector_float_to_double( - independent_variables), - values_double); - values = values_double; - } + Vector & values) const; - static void + void jacobian(const typename Types::tape_index active_tape_index, const unsigned int n_dependent_variables, const std::vector &independent_variables, - FullMatrix & jacobian) - { - FullMatrix jacobian_double(jacobian.m(), jacobian.n()); - // ADOL-C only supports 'double', not 'float', so we can forward to - // the 'double' implementation of this function - TapedDrivers::jacobian(active_tape_index, - n_dependent_variables, - vector_float_to_double( - independent_variables), - jacobian_double); - jacobian = jacobian_double; - } + FullMatrix & jacobian) const; + + //@} private: /** * Copy a vector of floats into a vector of doubles */ - static std::vector - vector_float_to_double(const std::vector &in) - { - std::vector out(in.size()); - std::copy(in.begin(), in.end(), out.begin()); - return out; - } + std::vector + vector_float_to_double(const std::vector &in) const; /** * The object that actually takes care of the taping @@ -1581,235 +1158,6 @@ namespace Differentiation // ------------- TapelessDrivers ------------- - template - void - TapelessDrivers::initialize_global_environment( - const unsigned int) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - template - void - TapelessDrivers:: - allow_dependent_variable_marking() - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - template - void - TapelessDrivers:: - prevent_dependent_variable_marking() - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - template - bool - TapelessDrivers:: - is_dependent_variable_marking_allowed() const - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - return false; - } - - - template - ScalarType - TapelessDrivers::value( - const std::vector &) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - return ScalarType(0.0); - } - - - template - void - TapelessDrivers::gradient( - const std::vector &, - const std::vector &, - Vector &) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapelessDrivers::hessian( - const std::vector &, - const std::vector &, - FullMatrix &) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapelessDrivers::values( - const std::vector &, - Vector &) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - template - void - TapelessDrivers::jacobian( - const std::vector &, - const std::vector &, - FullMatrix &) - { - AssertThrow(false, ExcRequiresADNumberSpecialization()); - } - - - namespace internal - { - /** - * A dummy function to define the active dependent variable when using - * reverse-mode AD. - */ - template - typename std::enable_if::type_code == - NumberTypes::sacado_rad || - ADNumberTraits::type_code == - NumberTypes::sacado_rad_dfad)>::type - reverse_mode_dependent_variable_activation(ADNumberType &) - {} - -# ifdef DEAL_II_TRILINOS_WITH_SACADO - - - /** - * Define the active dependent variable when using reverse-mode AD. - * - * If there are multiple dependent variables then it is necessary to - * inform the independent variables, from which the adjoints are computed, - * which dependent variable they are computing the gradients with respect - * to. This function broadcasts this information. - */ - template - typename std::enable_if::type_code == - NumberTypes::sacado_rad || - ADNumberTraits::type_code == - NumberTypes::sacado_rad_dfad>::type - reverse_mode_dependent_variable_activation( - ADNumberType &dependent_variable) - { - // Compute all gradients (adjoints) for this - // reverse-mode Sacado dependent variable. - // For reverse-mode Sacado numbers it is necessary to broadcast to - // all independent variables that it is time to compute gradients. - // For one dependent variable one would just need to call - // ADNumberType::Gradcomp(), but since we have a more - // generic implementation for vectors of dependent variables - // (vector mode) we default to the complex case. - ADNumberType::Outvar_Gradcomp(dependent_variable); - } - -# endif - - - /** - * A dummy function to enable vector mode for tapeless - * auto-differentiable numbers. - */ - template - typename std::enable_if::type_code == - NumberTypes::adolc_tapeless)>::type - configure_tapeless_mode(const unsigned int) - {} - - -# ifdef DEAL_II_WITH_ADOLC - - - /** - * Enable vector mode for ADOL-C tapeless numbers. - * - * This function checks to see if its legal to increase the maximum - * number of directional derivatives to be considered during calculations. - * If not then it throws an error. - */ - template - typename std::enable_if::type_code == - NumberTypes::adolc_tapeless>::type - configure_tapeless_mode(const unsigned int n_directional_derivatives) - { -# ifdef DEAL_II_ADOLC_WITH_TAPELESS_REFCOUNTING - // See ADOL-C manual section 7.1 - // - // NOTE: It is critical that this is done for tapeless mode BEFORE - // any adtl::adouble are created. If this is not done, then we see - // this scary warning: - // - // " - // ADOL-C Warning: Tapeless: Setting numDir could change memory - // allocation of derivatives in existing adoubles and may lead to - // erroneous results or memory corruption - // " - // - // So we use this dummy function to configure this setting before - // we create and initialize our class data - const std::size_t n_live_variables = adtl::refcounter::getNumLiveVar(); - if (n_live_variables == 0) - { - adtl::setNumDir(n_directional_derivatives); - } - else - { - // So there are some live active variables floating around. Here we - // check if we ask to increase the number of computable - // directional derivatives. If this really is necessary then it's - // absolutely vital that there exist no live variables before doing - // so. - const std::size_t n_set_directional_derivatives = adtl::getNumDir(); - if (n_directional_derivatives > n_set_directional_derivatives) - AssertThrow( - n_live_variables == 0, - ExcMessage( - "There are currently " + - Utilities::to_string(n_live_variables) + - " live " - "adtl::adouble variables in existence. They currently " - "assume " + - Utilities::to_string(n_set_directional_derivatives) + - " directional derivatives " - "but you wish to increase this to " + - Utilities::to_string(n_directional_derivatives) + - ". \n" - "To safely change (or more specifically in this case, " - "increase) the number of directional derivatives, there " - "must be no tapeless doubles in local/global scope.")); - } -# else - // If ADOL-C is not configured with tapeless number reference counting - // then there is no way that we can guarantee that the following call - // is safe. No comment... :-/ - adtl::setNumDir(n_directional_derivatives); -# endif - } - -# else // DEAL_II_WITH_ADOLC - - template - typename std::enable_if::type_code == - NumberTypes::adolc_tapeless>::type - configure_tapeless_mode(const unsigned int /*n_directional_derivatives*/) - { - AssertThrow(false, ExcRequiresADOLC()); - } - -# endif - - } // namespace internal - - /** * Specialization for auto-differentiable numbers that use * reverse mode to compute the first derivatives (and, if supported, @@ -1824,192 +1172,72 @@ namespace Differentiation ADNumberTraits::type_code == NumberTypes::sacado_rad_dfad>::type> { - TapelessDrivers() - : dependent_variable_marking_safe(false) - {} + /** + * Constructor + */ + TapelessDrivers(); - // === Configuration === + /** + * @name Configuration + */ + //@{ static void - initialize_global_environment(const unsigned int n_independent_variables) - { - internal::configure_tapeless_mode( - n_independent_variables); - } + initialize_global_environment(const unsigned int n_independent_variables); + + //@} + + /** + * Operation status + */ + //@{ - // === Operation status === void - allow_dependent_variable_marking() - { - dependent_variable_marking_safe = true; - } + allow_dependent_variable_marking(); void - prevent_dependent_variable_marking() - { - dependent_variable_marking_safe = false; - } + prevent_dependent_variable_marking(); bool - is_dependent_variable_marking_allowed() const - { - return dependent_variable_marking_safe; - } - - // === Scalar drivers === - - static ScalarType - value(const std::vector &dependent_variables) - { - Assert(dependent_variables.size() == 1, - ExcDimensionMismatch(dependent_variables.size(), 1)); - return ADNumberTraits::get_scalar_value( - dependent_variables[0]); - } + is_dependent_variable_marking_allowed() const; - static void + //@} + + /** + * @name Drivers for scalar functions + */ + //@{ + + ScalarType + value(const std::vector &dependent_variables) const; + + void gradient(const std::vector &independent_variables, const std::vector &dependent_variables, - Vector & gradient) - { - Assert( - AD::ADNumberTraits::n_supported_derivative_levels >= 1, - ExcSupportedDerivativeLevels( - AD::ADNumberTraits::n_supported_derivative_levels, - 1)); - Assert(dependent_variables.size() == 1, - ExcDimensionMismatch(dependent_variables.size(), 1)); - Assert(gradient.size() == independent_variables.size(), - ExcDimensionMismatch(gradient.size(), - independent_variables.size())); - - // In reverse mode, the gradients are computed from the - // independent variables (i.e. the adjoint) - internal::reverse_mode_dependent_variable_activation( - const_cast(dependent_variables[0])); - const std::size_t n_independent_variables = - independent_variables.size(); - for (unsigned int i = 0; i < n_independent_variables; i++) - gradient[i] = internal::NumberType::value( - ADNumberTraits::get_directional_derivative( - independent_variables[i], - 0 /*This number doesn't really matter*/)); - } + Vector & gradient) const; - static void + void hessian(const std::vector &independent_variables, const std::vector &dependent_variables, - FullMatrix & hessian) - { - Assert( - AD::ADNumberTraits::n_supported_derivative_levels >= 2, - ExcSupportedDerivativeLevels( - AD::ADNumberTraits::n_supported_derivative_levels, - 2)); - Assert(dependent_variables.size() == 1, - ExcDimensionMismatch(dependent_variables.size(), 1)); - Assert(hessian.m() == independent_variables.size(), - ExcDimensionMismatch(hessian.m(), independent_variables.size())); - Assert(hessian.n() == independent_variables.size(), - ExcDimensionMismatch(hessian.n(), independent_variables.size())); - - // In reverse mode, the gradients are computed from the - // independent variables (i.e. the adjoint) - internal::reverse_mode_dependent_variable_activation( - const_cast(dependent_variables[0])); - const std::size_t n_independent_variables = - independent_variables.size(); - for (unsigned int i = 0; i < n_independent_variables; i++) - { - using derivative_type = - typename ADNumberTraits::derivative_type; - const derivative_type gradient_i = - ADNumberTraits::get_directional_derivative( - independent_variables[i], i); - - for (unsigned int j = 0; j <= i; ++j) // Symmetry - { - // Extract higher-order directional derivatives. Depending on - // the AD number type, the result may be another AD number or a - // floating point value. - const ScalarType hessian_ij = - internal::NumberType::value( - ADNumberTraits::get_directional_derivative( - gradient_i, j)); - hessian[i][j] = hessian_ij; - if (i != j) - hessian[j][i] = hessian_ij; // Symmetry - } - } - } - - // === Vector drivers === + FullMatrix & hessian) const; - static void - values(const std::vector &dependent_variables, - Vector & values) - { - Assert(values.size() == dependent_variables.size(), - ExcDimensionMismatch(values.size(), dependent_variables.size())); + //@} - const std::size_t n_dependent_variables = dependent_variables.size(); - for (unsigned int i = 0; i < n_dependent_variables; i++) - values[i] = ADNumberTraits::get_scalar_value( - dependent_variables[i]); - } + /** + * @name Drivers for vector functions + */ + //@{ - static void + void + values(const std::vector &dependent_variables, + Vector & values) const; + + void jacobian(const std::vector &independent_variables, const std::vector &dependent_variables, - FullMatrix & jacobian) - { - Assert( - AD::ADNumberTraits::n_supported_derivative_levels >= 1, - ExcSupportedDerivativeLevels( - AD::ADNumberTraits::n_supported_derivative_levels, - 1)); - Assert(jacobian.m() == dependent_variables.size(), - ExcDimensionMismatch(jacobian.m(), dependent_variables.size())); - Assert(jacobian.n() == independent_variables.size(), - ExcDimensionMismatch(jacobian.n(), - independent_variables.size())); - - const std::size_t n_independent_variables = - independent_variables.size(); - const std::size_t n_dependent_variables = dependent_variables.size(); - - // In reverse mode, the gradients are computed from the - // independent variables (i.e. the adjoint). - // For a demonstration of why this accumulation process is - // required, see the unit tests - // sacado/basic_01b.cc and sacado/basic_02b.cc - // Here we also take into consideration the derivative type: - // The Sacado number may be of the nested variety, in which - // case the effect of the accumulation process on the - // sensitivities of the nested number need to be accounted for. - using accumulation_type = - typename ADNumberTraits::derivative_type; - std::vector rad_accumulation( - n_independent_variables, - dealii::internal::NumberType::value(0.0)); - - for (unsigned int i = 0; i < n_dependent_variables; i++) - { - internal::reverse_mode_dependent_variable_activation( - const_cast(dependent_variables[i])); - for (unsigned int j = 0; j < n_independent_variables; j++) - { - const accumulation_type df_i_dx_j = - ADNumberTraits::get_directional_derivative( - independent_variables[j], - i /*This number doesn't really matter*/) - - rad_accumulation[j]; - jacobian[i][j] = - internal::NumberType::value(df_i_dx_j); - rad_accumulation[j] += df_i_dx_j; - } - } - } + FullMatrix & jacobian) const; + + //@} private: /** @@ -2036,163 +1264,72 @@ namespace Differentiation ADNumberTraits::type_code == NumberTypes::sacado_dfad_dfad>::type> { - TapelessDrivers() - : dependent_variable_marking_safe(false) - {} + /** + * Constructor + */ + TapelessDrivers(); - // === Configuration === + /** + * @name Configuration + */ + //@{ static void - initialize_global_environment(const unsigned int n_independent_variables) - { - internal::configure_tapeless_mode( - n_independent_variables); - } + initialize_global_environment(const unsigned int n_independent_variables); + + //@} + + /** + * Operation status + */ + //@{ - // === Operation status === void - allow_dependent_variable_marking() - { - dependent_variable_marking_safe = true; - } + allow_dependent_variable_marking(); void - prevent_dependent_variable_marking() - { - dependent_variable_marking_safe = false; - } + prevent_dependent_variable_marking(); bool - is_dependent_variable_marking_allowed() const - { - return dependent_variable_marking_safe; - } - - // === Scalar drivers === - - static ScalarType - value(const std::vector &dependent_variables) - { - Assert(dependent_variables.size() == 1, - ExcDimensionMismatch(dependent_variables.size(), 1)); - return ADNumberTraits::get_scalar_value( - dependent_variables[0]); - } + is_dependent_variable_marking_allowed() const; - static void + //@} + + /** + * @name Drivers for scalar functions + */ + //@{ + + ScalarType + value(const std::vector &dependent_variables) const; + + void gradient(const std::vector &independent_variables, const std::vector &dependent_variables, - Vector & gradient) - { - Assert( - AD::ADNumberTraits::n_supported_derivative_levels >= 1, - ExcSupportedDerivativeLevels( - AD::ADNumberTraits::n_supported_derivative_levels, - 1)); - Assert(dependent_variables.size() == 1, - ExcDimensionMismatch(dependent_variables.size(), 1)); - Assert(gradient.size() == independent_variables.size(), - ExcDimensionMismatch(gradient.size(), - independent_variables.size())); - - // In forward mode, the gradients are computed from the - // dependent variables - const std::size_t n_independent_variables = - independent_variables.size(); - for (unsigned int i = 0; i < n_independent_variables; i++) - gradient[i] = internal::NumberType::value( - ADNumberTraits::get_directional_derivative( - dependent_variables[0], i)); - } + Vector & gradient) const; - static void + void hessian(const std::vector &independent_variables, const std::vector &dependent_variables, - FullMatrix & hessian) - { - Assert( - AD::ADNumberTraits::n_supported_derivative_levels >= 2, - ExcSupportedDerivativeLevels( - AD::ADNumberTraits::n_supported_derivative_levels, - 2)); - Assert(dependent_variables.size() == 1, - ExcDimensionMismatch(dependent_variables.size(), 1)); - Assert(hessian.m() == independent_variables.size(), - ExcDimensionMismatch(hessian.m(), independent_variables.size())); - Assert(hessian.n() == independent_variables.size(), - ExcDimensionMismatch(hessian.n(), independent_variables.size())); - - // In forward mode, the gradients are computed from the - // dependent variables - const std::size_t n_independent_variables = - independent_variables.size(); - for (unsigned int i = 0; i < n_independent_variables; i++) - { - using derivative_type = - typename ADNumberTraits::derivative_type; - const derivative_type gradient_i = - ADNumberTraits::get_directional_derivative( - dependent_variables[0], i); - - for (unsigned int j = 0; j <= i; ++j) // Symmetry - { - // Extract higher-order directional derivatives. Depending on - // the AD number type, the result may be another AD number or a - // floating point value. - const ScalarType hessian_ij = - internal::NumberType::value( - ADNumberTraits::get_directional_derivative( - gradient_i, j)); - hessian[i][j] = hessian_ij; - if (i != j) - hessian[j][i] = hessian_ij; // Symmetry - } - } - } - - // === Vector drivers === + FullMatrix & hessian) const; - static void - values(const std::vector &dependent_variables, - Vector & values) - { - Assert(values.size() == dependent_variables.size(), - ExcDimensionMismatch(values.size(), dependent_variables.size())); + //@} - const std::size_t n_dependent_variables = dependent_variables.size(); - for (unsigned int i = 0; i < n_dependent_variables; i++) - values[i] = ADNumberTraits::get_scalar_value( - dependent_variables[i]); - } + /** + * @name Drivers for vector functions + */ + //@{ - static void + void + values(const std::vector &dependent_variables, + Vector & values) const; + + void jacobian(const std::vector &independent_variables, const std::vector &dependent_variables, - FullMatrix & jacobian) - { - Assert( - AD::ADNumberTraits::n_supported_derivative_levels >= 1, - ExcSupportedDerivativeLevels( - AD::ADNumberTraits::n_supported_derivative_levels, - 1)); - Assert(jacobian.m() == dependent_variables.size(), - ExcDimensionMismatch(jacobian.m(), dependent_variables.size())); - Assert(jacobian.n() == independent_variables.size(), - ExcDimensionMismatch(jacobian.n(), - independent_variables.size())); - - const std::size_t n_independent_variables = - independent_variables.size(); - const std::size_t n_dependent_variables = dependent_variables.size(); - - // In forward mode, the gradients are computed from the - // dependent variables - for (unsigned int i = 0; i < n_dependent_variables; i++) - for (unsigned int j = 0; j < n_independent_variables; j++) - jacobian[i][j] = internal::NumberType::value( - ADNumberTraits::get_directional_derivative( - dependent_variables[i], j)); - } + FullMatrix & jacobian) const; + + //@} private: /** diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index 83e8a899c571..7aad5de7edab 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -328,6 +328,9 @@ namespace Differentiation * image space. * @param[in] clear_registered_tapes A flag that indicates the that * list of @p registered_tapes must be cleared. + * If set to true then the data structure that tracks which + * tapes have been recorded is cleared as well. It is then expected that + * any preexisting tapes be re-recorded. * * @note This also resets the active tape number to an invalid number, and * deactivates the recording mode for taped variables. diff --git a/source/differentiation/ad/CMakeLists.txt b/source/differentiation/ad/CMakeLists.txt index 81e83bb6339c..9a2f31e4dc67 100644 --- a/source/differentiation/ad/CMakeLists.txt +++ b/source/differentiation/ad/CMakeLists.txt @@ -1,6 +1,6 @@ ## --------------------------------------------------------------------- ## -## Copyright (C) 2017 by the deal.II authors +## Copyright (C) 2017 - 2018 by the deal.II authors ## ## This file is part of the deal.II library. ## @@ -16,12 +16,15 @@ INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) SET(_src + ad_drivers.cc ad_helpers.cc adolc_number_types.cc sacado_number_types.cc ) SET(_inst + ad_drivers.inst1.in + ad_drivers.inst2.in ad_helpers.inst1.in ad_helpers.inst2.in adolc_number_types.inst.in diff --git a/source/differentiation/ad/ad_drivers.cc b/source/differentiation/ad/ad_drivers.cc new file mode 100644 index 000000000000..a0447c8d7702 --- /dev/null +++ b/source/differentiation/ad/ad_drivers.cc @@ -0,0 +1,2258 @@ +// --------------------------------------------------------------------- +// +// 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 at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#include + +#if defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO) + +# include +# include +# include + +# include +# include +# include +# include +# include + +# include +# include + +# ifdef DEAL_II_WITH_ADOLC + +DEAL_II_DISABLE_EXTRA_DIAGNOSTICS +# include +# include +# include +DEAL_II_ENABLE_EXTRA_DIAGNOSTICS + +# endif // DEAL_II_WITH_ADOLC + +# include + + +DEAL_II_NAMESPACE_OPEN + + +namespace Differentiation +{ + namespace AD + { + // ------------- TapedDrivers ------------- + + + template + bool + TapedDrivers::is_recording() const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + return false; + } + + + template + typename Types::tape_index + TapedDrivers::active_tape_index() const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + return Numbers::invalid_tape_index; + } + + + template + bool + TapedDrivers::is_registered_tape( + const typename Types::tape_index) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + return false; + } + + + template + bool + TapedDrivers::keep_independent_values() const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + return false; + } + + + template + void + TapedDrivers::set_tape_buffer_sizes( + const typename Types::tape_buffer_sizes, + const typename Types::tape_buffer_sizes, + const typename Types::tape_buffer_sizes, + const typename Types::tape_buffer_sizes) + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + void + TapedDrivers::start_taping( + const typename Types::tape_index, + const bool) + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + void + TapedDrivers::stop_taping( + const typename Types::tape_index, + const bool) + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + std::vector::tape_index> + TapedDrivers::get_registered_tape_indices() + const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + return std::vector::tape_index>(); + } + + + template + void + TapedDrivers::activate_tape( + const typename Types::tape_index) + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + bool + TapedDrivers::requires_retaping( + const typename Types::tape_index) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + return false; + } + + + template + bool + TapedDrivers::last_action_requires_retaping() + const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + return false; + } + + + template + void + TapedDrivers::remove_tape( + const typename Types::tape_index) + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + void + TapedDrivers::reset(const bool) + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + void + TapedDrivers::print(std::ostream &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + void + TapedDrivers::print_tape_stats( + const typename Types::tape_index, + std::ostream &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + ScalarType + TapedDrivers::value( + const typename Types::tape_index, + const std::vector &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + return ScalarType(0.0); + } + + + template + void + TapedDrivers::gradient( + const typename Types::tape_index, + const std::vector &, + Vector &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + void + TapedDrivers::hessian( + const typename Types::tape_index, + const std::vector &, + FullMatrix &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + void + TapedDrivers::values( + const typename Types::tape_index, + const unsigned int, + const std::vector &, + Vector &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + void + TapedDrivers::jacobian( + const typename Types::tape_index, + const unsigned int, + const std::vector &, + FullMatrix &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + +# ifdef DEAL_II_WITH_ADOLC + + // Specialization for taped ADOL-C auto-differentiable numbers. + + template + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>::TapedDrivers() + : active_tape(Numbers::invalid_tape_index) + , keep_values(true) + , is_recording_flag(false) + , use_stored_taped_buffer_sizes(false) + , obufsize(0u) + , lbufsize(0u) + , vbufsize(0u) + , tbufsize(0u) + {} + + + template + bool + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>::is_recording() + const + { + return is_recording_flag; + } + + + template + typename Types::tape_index + TapedDrivers::type_code == + NumberTypes::adolc_taped>::type>::active_tape_index() const + { + return active_tape; + } + + + template + bool + TapedDrivers::type_code == + NumberTypes::adolc_taped>::type>::keep_independent_values() + const + { + return keep_values; + } + + + template + bool + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + is_registered_tape( + const typename Types::tape_index tape_index) const + { + // Sigh... This is a mess :-/ + // The most succinct way to get this piece of information, would be to + // use the getTapeInfos() function, but would come at the expense of + // creating an inactive tape data within ADOL-C's global store. For + // hints as to why this is the way it is, see the getTapeInfos() + // function in + // https://gitlab.com/adol-c/adol-c/blob/master/ADOL-C/src/tape_handling.cpp + // An alternative solution would be to manually access the tape data; + // see the removeTape() function in + // https://gitlab.com/adol-c/adol-c/blob/master/ADOL-C/src/tape_handling.cpp + // with the consideration of the #defines in + // https://gitlab.com/adol-c/adol-c/blob/master/ADOL-C/src/taping_p.h + // as to how this would be performed. + // Doing things "manually" (the second way) without creating the + // additional data object would be a lot more work... + // + // Both of the above solutions would be possible IF ADOL-C exposed + // this data object or a method to access it to the outside world. + // But they don't :-( + // Instead, what we'll have to do is get the statistics for this tape + // and make our own determination as to whether or not this tape exists. + // This effectively executes the first solution, with even more + // overhead! If the tape is in existence, we can assume that it should a + // non-zero number of dependent and independent variables. Those are + // stored in the zeroth and first entries of the statistics vector. + // + // But, oh wait... Surprise! This will trigger an error if the tape + // doesn't exist at all! So lets first check their tape info cache to + // see if the tape REALLY exists (i.e. has been touched, even if nothing + // has been written to it) before trying to access it. It'll only take + // an O(n) search, but at this point who really cares about efficiency? + // + // It has been suggested in + // https://gitlab.com/adol-c/adol-c/issues/11 + // that a simply try-catch block around ::tapestats is the solution that + // we want here. Unfortunately this results in unwanted pollution of + // the terminal, of the form + // ADOL-C error: reading integer tape number 4! + // >>> File or directory not found! <<< + // , every time a query is made about a non-existant tape. + // So either way we have to guard that check with something more + // conervative so that we don't output useless messages for our users. + const std::vector::tape_index> + registered_tape_indices = get_registered_tape_indices(); + const auto it = std::find(registered_tape_indices.begin(), + registered_tape_indices.end(), + tape_index); + if (it == registered_tape_indices.end()) + return false; + + // See https://gitlab.com/adol-c/adol-c/issues/11#note_108341333 + try + { + std::vector counts(STAT_SIZE); + ::tapestats(tape_index, counts.data()); + return true; + } + catch (const ::FatalError &exc) + { + return false; + } + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + set_tape_buffer_sizes( + const typename Types::tape_buffer_sizes in_obufsize, + const typename Types::tape_buffer_sizes in_lbufsize, + const typename Types::tape_buffer_sizes in_vbufsize, + const typename Types::tape_buffer_sizes in_tbufsize) + { + // When valid for the chosen AD number type, these values will be used + // the next time start_recording_operations() is called. + obufsize = in_obufsize; + lbufsize = in_lbufsize; + vbufsize = in_vbufsize; + tbufsize = in_tbufsize; + use_stored_taped_buffer_sizes = true; + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + start_taping(const typename Types::tape_index tape_index, + const bool keep_independent_values) + { + if (use_stored_taped_buffer_sizes) + trace_on(tape_index, + keep_independent_values, + obufsize, + lbufsize, + vbufsize, + tbufsize); + else + trace_on(tape_index, keep_independent_values); + + // Set some other flags to their indicated / required values + keep_values = keep_independent_values; + is_recording_flag = true; + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + stop_taping( + const typename Types::tape_index active_tape_index, + const bool write_tapes_to_file) + { + if (write_tapes_to_file) + trace_off(active_tape_index); // Slow + else + trace_off(); // Fast(er) + + // Now that we've turned tracing off, we've definitely + // stopped all tape recording. + is_recording_flag = false; + + // If the keep_values flag is set, then we expect the user to use this + // tape immediately after recording it. There is therefore no need to + // invalidate it. However, there is now also no way to double-check + // that the newly recorded tape is indeed the active tape. + if (keep_independent_values() == false) + active_tape = Numbers::invalid_tape_index; + } + + + template + std::vector::tape_index> + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + get_registered_tape_indices() const + { + // We've chosen to use unsigned shorts for the tape + // index type (a safety precaution) so we need to + // perform a conversion betwwen ADOL-C's native tape + // index type and that chosen by us. + std::vector registered_tape_indices_s; + cachedTraceTags(registered_tape_indices_s); + + std::vector::tape_index> + registered_tape_indices(registered_tape_indices_s.size()); + std::copy(registered_tape_indices_s.begin(), + registered_tape_indices_s.end(), + registered_tape_indices.begin()); + return registered_tape_indices; + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + activate_tape(const typename Types::tape_index tape_index) + { + active_tape = tape_index; + } + + + template + bool + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + requires_retaping( + const typename Types::tape_index tape_index) const + { + Assert( + is_registered_tape(tape_index) == true, + ExcMessage( + "Cannot ask for the status of a tape that has not yet been recorded and used.")); + + const auto it_status_tape = status.find(tape_index); + + // This tape's status has not been found in the map. This could be + // because a non-existant tape_index has been used as an argument, or + // because the tape exists but has not been used (in a way that + // initiated a status update). For example, on can create a tape in one + // section of code and then query the status of all existing tapes in a + // completely different section of code that knows nothing about the + // first tape. There is no prerequisite that the first tape is ever + // used, and it can therefore not have a status. So, in this case + // there's not much we can do other than to report that the tape does + // not require retaping. + if (it_status_tape == status.end()) + return false; + + const auto status_tape = it_status_tape->second; + + // See ADOL-C manual section 1.7 and comments in last paragraph of + // section 3.1 + Assert(status_tape < 4 && status_tape >= -2, + ExcIndexRange(status_tape, -2, 4)); + return (status_tape < 0); + } + + + template + bool + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + last_action_requires_retaping() const + { + return requires_retaping(active_tape); + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + remove_tape(const typename Types::tape_index tape_index) + { + Assert(is_registered_tape(tape_index), + ExcMessage( + "This tape does not exist, and therefore cannot be cleared.")); + removeTape(tape_index, TapeRemovalType::ADOLC_REMOVE_COMPLETELY); + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + reset(const bool clear_registered_tapes) + { + active_tape = Numbers::invalid_tape_index; + is_recording_flag = false; + status.clear(); + if (clear_registered_tapes) + { + const std::vector::tape_index> + registered_tape_indices = get_registered_tape_indices(); + for (const auto &tape_index : registered_tape_indices) + remove_tape(tape_index); + } + } + + + template + void + TapedDrivers::type_code == + NumberTypes::adolc_taped>::type>::print(std::ostream &stream) + const + { + const std::vector::tape_index> + registered_tape_indices = get_registered_tape_indices(); + stream << "Registered tapes and their status: "; + auto it_registered_tape = registered_tape_indices.begin(); + for (unsigned int i = 0; i < registered_tape_indices.size(); + ++i, ++it_registered_tape) + { + const auto tape_index = *it_registered_tape; + const auto it_status_tape = status.find(tape_index); + Assert(it_status_tape != status.end(), + ExcMessage( + "This tape's status has not been found in the map.")); + const auto status_tape = it_status_tape->second; + + stream << tape_index << "->" << status_tape + << (i < (registered_tape_indices.size() - 1) ? "," : ""); + } + stream << "\n"; + + stream << "Keep values? " << keep_independent_values() << "\n"; + stream << "Use stored tape buffer sizes? " + << use_stored_taped_buffer_sizes << "\n"; + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + print_tape_stats( + const typename Types::tape_index tape_index, + std::ostream & stream) const + { + // See ADOL-C manual section 2.1 + // and adolc/taping.h + std::vector counts(STAT_SIZE); + ::tapestats(tape_index, counts.data()); + Assert(counts.size() >= 18, ExcInternalError()); + stream + << "Tape index: " << tape_index << "\n" + << "Number of independent variables: " << counts[0] << "\n" + << "Number of dependent variables: " << counts[1] << "\n" + << "Max number of live, active variables: " << counts[2] << "\n" + << "Size of taylor stack (number of overwrites): " << counts[3] << "\n" + << "Operations buffer size: " << counts[4] << "\n" + << "Total number of recorded operations: " << counts[5] << "\n" + << "Operations file written or not: " << counts[6] << "\n" + << "Overall number of locations: " << counts[7] << "\n" + << "Locations file written or not: " << counts[8] << "\n" + << "Overall number of values: " << counts[9] << "\n" + << "Values file written or not: " << counts[10] << "\n" + << "Locations buffer size: " << counts[11] << "\n" + << "Values buffer size: " << counts[12] << "\n" + << "Taylor buffer size: " << counts[13] << "\n" + << "Number of eq_*_prod for sparsity pattern: " << counts[14] << "\n" + << "Use of 'min_op', deferred to 'abs_op' for piecewise calculations: " + << counts[15] << "\n" + << "Number of 'abs' calls that can switch branch: " << counts[16] + << "\n" + << "Number of parameters (doubles) interchangeable without retaping: " + << counts[17] << "\n" + << std::flush; + } + + + template + typename TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>::scalar_type + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + value(const typename Types::tape_index active_tape_index, + const std::vector &independent_variables) const + { + Assert(is_registered_tape(active_tape_index), + ExcMessage("This tape has not yet been recorded.")); + + scalar_type value = 0.0; + + status[active_tape_index] = + ::function(active_tape_index, + 1, // Only one dependent variable + independent_variables.size(), + const_cast(independent_variables.data()), + &value); + + return value; + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + gradient(const typename Types::tape_index active_tape_index, + const std::vector &independent_variables, + Vector & gradient) const + { + Assert(AD::ADNumberTraits::n_supported_derivative_levels >= + 1, + ExcSupportedDerivativeLevels( + AD::ADNumberTraits::n_supported_derivative_levels, + 1)); + Assert(gradient.size() == independent_variables.size(), + ExcDimensionMismatch(gradient.size(), + independent_variables.size())); + Assert(is_registered_tape(active_tape_index), + ExcMessage("This tape has not yet been recorded.")); + + // Note: ADOL-C's ::gradient function expects a *double as the last + // parameter. Here we take advantage of the fact that the data in the + // Vector class is aligned (e.g. stored as an Array) + status[active_tape_index] = + ::gradient(active_tape_index, + independent_variables.size(), + const_cast(independent_variables.data()), + gradient.data()); + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + hessian(const typename Types::tape_index active_tape_index, + const std::vector &independent_variables, + FullMatrix & hessian) const + { + Assert(AD::ADNumberTraits::n_supported_derivative_levels >= + 2, + ExcSupportedDerivativeLevels( + AD::ADNumberTraits::n_supported_derivative_levels, + 2)); + Assert(hessian.m() == independent_variables.size(), + ExcDimensionMismatch(hessian.m(), independent_variables.size())); + Assert(hessian.n() == independent_variables.size(), + ExcDimensionMismatch(hessian.n(), independent_variables.size())); + Assert(is_registered_tape(active_tape_index), + ExcMessage("This tape has not yet been recorded.")); + + const unsigned int n_independent_variables = independent_variables.size(); + std::vector H(n_independent_variables); + for (unsigned int i = 0; i < n_independent_variables; ++i) + H[i] = &hessian[i][0]; + + status[active_tape_index] = + ::hessian(active_tape_index, + n_independent_variables, + const_cast(independent_variables.data()), + H.data()); + + // ADOL-C builds only the lower-triangular part of the + // symmetric Hessian, so we should copy the relevant + // entries into the upper triangular part. + for (unsigned int i = 0; i < n_independent_variables; i++) + for (unsigned int j = 0; j < i; j++) + hessian[j][i] = hessian[i][j]; // Symmetry + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + values(const typename Types::tape_index active_tape_index, + const unsigned int n_dependent_variables, + const std::vector &independent_variables, + Vector & values) const + { + Assert(values.size() == n_dependent_variables, + ExcDimensionMismatch(values.size(), n_dependent_variables)); + Assert(is_registered_tape(active_tape_index), + ExcMessage("This tape has not yet been recorded.")); + + // Note: ADOL-C's ::function function expects a *double as the last + // parameter. Here we take advantage of the fact that the data in the + // Vector class is aligned (e.g. stored as an Array) + status[active_tape_index] = + ::function(active_tape_index, + n_dependent_variables, + independent_variables.size(), + const_cast(independent_variables.data()), + values.data()); + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + jacobian(const typename Types::tape_index active_tape_index, + const unsigned int n_dependent_variables, + const std::vector &independent_variables, + FullMatrix & jacobian) const + { + Assert(AD::ADNumberTraits::n_supported_derivative_levels >= + 1, + ExcSupportedDerivativeLevels( + AD::ADNumberTraits::n_supported_derivative_levels, + 1)); + Assert(jacobian.m() == n_dependent_variables, + ExcDimensionMismatch(jacobian.m(), n_dependent_variables)); + Assert(jacobian.n() == independent_variables.size(), + ExcDimensionMismatch(jacobian.n(), independent_variables.size())); + Assert(is_registered_tape(active_tape_index), + ExcMessage("This tape has not yet been recorded.")); + + std::vector J(n_dependent_variables); + for (unsigned int i = 0; i < n_dependent_variables; ++i) + J[i] = &jacobian[i][0]; + + status[active_tape_index] = ::jacobian(active_tape_index, + n_dependent_variables, + independent_variables.size(), + independent_variables.data(), + J.data()); + } + +# else + + // Specialization for taped ADOL-C auto-differentiable numbers. + + template + bool + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>::is_recording() + const + { + AssertThrow(false, ExcRequiresADOLC()); + return false; + } + + + template + typename Types::tape_index + TapedDrivers::type_code == + NumberTypes::adolc_taped>::type>::active_tape_index() const + { + AssertThrow(false, ExcRequiresADOLC()); + return Numbers::invalid_tape_index; + } + + + template + bool + TapedDrivers::type_code == + NumberTypes::adolc_taped>::type>::keep_independent_values() + const + { + AssertThrow(false, ExcRequiresADOLC()); + return false; + } + + + template + bool + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + is_registered_tape( + const typename Types::tape_index tape_index) const + { + AssertThrow(false, ExcRequiresADOLC()); + return false; + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + set_tape_buffer_sizes( + const typename Types::tape_buffer_sizes, + const typename Types::tape_buffer_sizes, + const typename Types::tape_buffer_sizes, + const typename Types::tape_buffer_sizes) + { + AssertThrow(false, ExcRequiresADOLC()); + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + start_taping(const typename Types::tape_index, const bool) + { + AssertThrow(false, ExcRequiresADOLC()); + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + stop_taping(const typename Types::tape_index, const bool) + { + AssertThrow(false, ExcRequiresADOLC()); + } + + std::vector::tape_index> + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + get_registered_tape_indices() const + { + AssertThrow(false, ExcRequiresADOLC()); + return std::vector::tape_index>(); + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + activate_tape(const typename Types::tape_index) + { + AssertThrow(false, ExcRequiresADOLC()); + } + + + template + bool + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + requires_retaping(const typename Types::tape_index) const + { + AssertThrow(false, ExcRequiresADOLC()); + return false; + } + + + template + bool + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + last_action_requires_retaping() const + { + AssertThrow(false, ExcRequiresADOLC()); + return false; + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + remove_tape(const typename Types::tape_index) + { + AssertThrow(false, ExcRequiresADOLC()); + } + + + template + void + TapedDrivers::type_code == + NumberTypes::adolc_taped>::type>::reset(const bool) + { + AssertThrow(false, ExcRequiresADOLC()); + } + + + template + void + TapedDrivers::type_code == + NumberTypes::adolc_taped>::type>::print(std::ostream &stream) + const + { + AssertThrow(false, ExcRequiresADOLC()); + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + print_tape_stats(const typename Types::tape_index, + std::ostream &) const + { + AssertThrow(false, ExcRequiresADOLC()); + } + + + template + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>::scalar_type + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + value(const typename Types::tape_index, + const std::vector &) const + { + AssertThrow(false, ExcRequiresADOLC()); + return 0.0; + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + gradient(const typename Types::tape_index, + const std::vector &, + Vector &) const + { + AssertThrow(false, ExcRequiresADOLC()); + } + + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + hessian(const typename Types::tape_index, + const std::vector &, + FullMatrix &) const + { + AssertThrow(false, ExcRequiresADOLC()); + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + values(const typename Types::tape_index, + const unsigned int, + const std::vector &, + Vector &) const + { + AssertThrow(false, ExcRequiresADOLC()); + } + + + template + void + TapedDrivers< + ADNumberType, + double, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + jacobian(const typename Types::tape_index, + const unsigned int, + const std::vector &, + FullMatrix &) const + { + AssertThrow(false, ExcRequiresADOLC()); + } + +# endif // DEAL_II_WITH_ADOLC + + + // Specialization for ADOL-C taped numbers. It is expected that the + // scalar return type for this class is a float. + + template + bool + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>::is_recording() + const + { + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + return taped_driver.is_recording(); + } + + + template + typename Types::tape_index + TapedDrivers::type_code == + NumberTypes::adolc_taped>::type>::active_tape_index() const + { + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + return taped_driver.active_tape_index(); + } + + + template + bool + TapedDrivers::type_code == + NumberTypes::adolc_taped>::type>::keep_independent_values() + const + { + return taped_driver.keep_independent_values(); + } + + + template + bool + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + is_registered_tape( + const typename Types::tape_index tape_index) const + { + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + return taped_driver.is_registered_tape(tape_index); + } + + + template + void + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + set_tape_buffer_sizes( + const typename Types::tape_buffer_sizes obufsize, + const typename Types::tape_buffer_sizes lbufsize, + const typename Types::tape_buffer_sizes vbufsize, + const typename Types::tape_buffer_sizes tbufsize) + { + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + taped_driver.set_tape_buffer_sizes(obufsize, + lbufsize, + vbufsize, + tbufsize); + } + + + template + void + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + start_taping(const typename Types::tape_index tape_index, + const bool keep_independent_values) + { + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + taped_driver.start_taping(tape_index, keep_independent_values); + } + + + template + void + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + stop_taping( + const typename Types::tape_index active_tape_index, + const bool write_tapes_to_file) + { + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + taped_driver.stop_taping(active_tape_index, write_tapes_to_file); + } + + + template + std::vector::tape_index> + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + get_registered_tape_indices() const + { + return taped_driver.get_registered_tape_indices(); + } + + + template + void + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + activate_tape(const typename Types::tape_index tape_index) + { + taped_driver.activate_tape(tape_index); + } + + + template + bool + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + requires_retaping( + const typename Types::tape_index tape_index) const + { + return taped_driver.requires_retaping(tape_index); + } + + + template + bool + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + last_action_requires_retaping() const + { + return taped_driver.last_action_requires_retaping(); + } + + + template + void + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + remove_tape(const typename Types::tape_index tape_index) + { + taped_driver.remove_tape(tape_index); + } + + + template + void + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + reset(const bool clear_registered_tapes) + { + taped_driver.reset(clear_registered_tapes); + } + + + template + void + TapedDrivers::type_code == + NumberTypes::adolc_taped>::type>::print(std::ostream &stream) + const + { + taped_driver.print(stream); + } + + + template + void + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + print_tape_stats( + const typename Types::tape_index tape_index, + std::ostream & stream) const + { + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + taped_driver.print_tape_stats(tape_index, stream); + } + + + template + typename TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>::scalar_type + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + value(const typename Types::tape_index active_tape_index, + const std::vector &independent_variables) const + { + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + return taped_driver.value(active_tape_index, + vector_float_to_double(independent_variables)); + } + + + template + void + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + gradient(const typename Types::tape_index active_tape_index, + const std::vector &independent_variables, + Vector & gradient) const + { + Vector gradient_double(gradient.size()); + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + taped_driver.gradient(active_tape_index, + vector_float_to_double(independent_variables), + gradient_double); + gradient = gradient_double; + } + + + template + void + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + hessian(const typename Types::tape_index active_tape_index, + const std::vector &independent_variables, + FullMatrix & hessian) const + { + FullMatrix hessian_double(hessian.m(), hessian.n()); + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + taped_driver.hessian(active_tape_index, + vector_float_to_double(independent_variables), + hessian_double); + hessian = hessian_double; + } + + + template + void + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + values(const typename Types::tape_index active_tape_index, + const unsigned int n_dependent_variables, + const std::vector &independent_variables, + Vector & values) const + { + Vector values_double(values.size()); + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + taped_driver.values(active_tape_index, + n_dependent_variables, + vector_float_to_double(independent_variables), + values_double); + values = values_double; + } + + + template + void + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + jacobian(const typename Types::tape_index active_tape_index, + const unsigned int n_dependent_variables, + const std::vector &independent_variables, + FullMatrix & jacobian) const + { + FullMatrix jacobian_double(jacobian.m(), jacobian.n()); + // ADOL-C only supports 'double', not 'float', so we can forward to + // the 'double' implementation of this function + taped_driver.jacobian(active_tape_index, + n_dependent_variables, + vector_float_to_double(independent_variables), + jacobian_double); + jacobian = jacobian_double; + } + + + template + std::vector + TapedDrivers< + ADNumberType, + float, + typename std::enable_if::type_code == + NumberTypes::adolc_taped>::type>:: + vector_float_to_double(const std::vector &in) const + { + std::vector out(in.size()); + std::copy(in.begin(), in.end(), out.begin()); + return out; + } + + + // ------------- TapelessDrivers ------------- + + + template + void + TapelessDrivers::initialize_global_environment( + const unsigned int) + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + template + void + TapelessDrivers:: + allow_dependent_variable_marking() + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + template + void + TapelessDrivers:: + prevent_dependent_variable_marking() + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + template + bool + TapelessDrivers:: + is_dependent_variable_marking_allowed() const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + return false; + } + + + template + ScalarType + TapelessDrivers::value( + const std::vector &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + return ScalarType(0.0); + } + + + template + void + TapelessDrivers::gradient( + const std::vector &, + const std::vector &, + Vector &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + void + TapelessDrivers::hessian( + const std::vector &, + const std::vector &, + FullMatrix &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + void + TapelessDrivers::values( + const std::vector &, + Vector &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + template + void + TapelessDrivers::jacobian( + const std::vector &, + const std::vector &, + FullMatrix &) const + { + AssertThrow(false, ExcRequiresADNumberSpecialization()); + } + + + namespace internal + { + /** + * A dummy function to define the active dependent variable when using + * reverse-mode AD. + */ + template + typename std::enable_if::type_code == + NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad)>::type + reverse_mode_dependent_variable_activation(ADNumberType &) + {} + +# ifdef DEAL_II_TRILINOS_WITH_SACADO + + + /** + * Define the active dependent variable when using reverse-mode AD. + * + * If there are multiple dependent variables then it is necessary to + * inform the independent variables, from which the adjoints are computed, + * which dependent variable they are computing the gradients with respect + * to. This function broadcasts this information. + */ + template + typename std::enable_if::type_code == + NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad>::type + reverse_mode_dependent_variable_activation( + ADNumberType &dependent_variable) + { + // Compute all gradients (adjoints) for this + // reverse-mode Sacado dependent variable. + // For reverse-mode Sacado numbers it is necessary to broadcast to + // all independent variables that it is time to compute gradients. + // For one dependent variable one would just need to call + // ADNumberType::Gradcomp(), but since we have a more + // generic implementation for vectors of dependent variables + // (vector mode) we default to the complex case. + ADNumberType::Outvar_Gradcomp(dependent_variable); + } + +# endif + + + /** + * A dummy function to enable vector mode for tapeless + * auto-differentiable numbers. + */ + template + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless)>::type + configure_tapeless_mode(const unsigned int) + {} + + +# ifdef DEAL_II_WITH_ADOLC + + + /** + * Enable vector mode for ADOL-C tapeless numbers. + * + * This function checks to see if its legal to increase the maximum + * number of directional derivatives to be considered during calculations. + * If not then it throws an error. + */ + template + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless>::type + configure_tapeless_mode(const unsigned int n_directional_derivatives) + { +# ifdef DEAL_II_ADOLC_WITH_TAPELESS_REFCOUNTING + // See ADOL-C manual section 7.1 + // + // NOTE: It is critical that this is done for tapeless mode BEFORE + // any adtl::adouble are created. If this is not done, then we see + // this scary warning: + // + // " + // ADOL-C Warning: Tapeless: Setting numDir could change memory + // allocation of derivatives in existing adoubles and may lead to + // erroneous results or memory corruption + // " + // + // So we use this dummy function to configure this setting before + // we create and initialize our class data + const std::size_t n_live_variables = adtl::refcounter::getNumLiveVar(); + if (n_live_variables == 0) + { + adtl::setNumDir(n_directional_derivatives); + } + else + { + // So there are some live active variables floating around. Here we + // check if we ask to increase the number of computable + // directional derivatives. If this really is necessary then it's + // absolutely vital that there exist no live variables before doing + // so. + const std::size_t n_set_directional_derivatives = adtl::getNumDir(); + if (n_directional_derivatives > n_set_directional_derivatives) + AssertThrow( + n_live_variables == 0, + ExcMessage( + "There are currently " + + Utilities::to_string(n_live_variables) + + " live " + "adtl::adouble variables in existence. They currently " + "assume " + + Utilities::to_string(n_set_directional_derivatives) + + " directional derivatives " + "but you wish to increase this to " + + Utilities::to_string(n_directional_derivatives) + + ". \n" + "To safely change (or more specifically in this case, " + "increase) the number of directional derivatives, there " + "must be no tapeless doubles in local/global scope.")); + } +# else + // If ADOL-C is not configured with tapeless number reference counting + // then there is no way that we can guarantee that the following call + // is safe. No comment... :-/ + adtl::setNumDir(n_directional_derivatives); +# endif + } + +# else // DEAL_II_WITH_ADOLC + + template + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless>::type + configure_tapeless_mode(const unsigned int /*n_directional_derivatives*/) + { + AssertThrow(false, ExcRequiresADOLC()); + } + +# endif + + } // namespace internal + + + + // Specialization for auto-differentiable numbers that use + // reverse mode to compute the first derivatives (and, if supported, + // forward mode for the second). + + template + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if< + ADNumberTraits::type_code == NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad>::type>::TapelessDrivers() + : dependent_variable_marking_safe(false) + {} + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad>::type>:: + initialize_global_environment(const unsigned int n_independent_variables) + { + internal::configure_tapeless_mode(n_independent_variables); + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad>::type>:: + allow_dependent_variable_marking() + { + dependent_variable_marking_safe = true; + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad>::type>:: + prevent_dependent_variable_marking() + { + dependent_variable_marking_safe = false; + } + + + template + bool + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad>::type>:: + is_dependent_variable_marking_allowed() const + { + return dependent_variable_marking_safe; + } + + + template + ScalarType + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad>::type>:: + value(const std::vector &dependent_variables) const + { + Assert(dependent_variables.size() == 1, + ExcDimensionMismatch(dependent_variables.size(), 1)); + return ADNumberTraits::get_scalar_value( + dependent_variables[0]); + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad>::type>:: + gradient(const std::vector &independent_variables, + const std::vector &dependent_variables, + Vector & gradient) const + { + Assert(AD::ADNumberTraits::n_supported_derivative_levels >= + 1, + ExcSupportedDerivativeLevels( + AD::ADNumberTraits::n_supported_derivative_levels, + 1)); + Assert(dependent_variables.size() == 1, + ExcDimensionMismatch(dependent_variables.size(), 1)); + Assert(gradient.size() == independent_variables.size(), + ExcDimensionMismatch(gradient.size(), + independent_variables.size())); + + // In reverse mode, the gradients are computed from the + // independent variables (i.e. the adjoint) + internal::reverse_mode_dependent_variable_activation( + const_cast(dependent_variables[0])); + const std::size_t n_independent_variables = independent_variables.size(); + for (unsigned int i = 0; i < n_independent_variables; i++) + gradient[i] = internal::NumberType::value( + ADNumberTraits::get_directional_derivative( + independent_variables[i], 0 /*This number doesn't really matter*/)); + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad>::type>:: + hessian(const std::vector &independent_variables, + const std::vector &dependent_variables, + FullMatrix & hessian) const + { + Assert(AD::ADNumberTraits::n_supported_derivative_levels >= + 2, + ExcSupportedDerivativeLevels( + AD::ADNumberTraits::n_supported_derivative_levels, + 2)); + Assert(dependent_variables.size() == 1, + ExcDimensionMismatch(dependent_variables.size(), 1)); + Assert(hessian.m() == independent_variables.size(), + ExcDimensionMismatch(hessian.m(), independent_variables.size())); + Assert(hessian.n() == independent_variables.size(), + ExcDimensionMismatch(hessian.n(), independent_variables.size())); + + // In reverse mode, the gradients are computed from the + // independent variables (i.e. the adjoint) + internal::reverse_mode_dependent_variable_activation( + const_cast(dependent_variables[0])); + const std::size_t n_independent_variables = independent_variables.size(); + for (unsigned int i = 0; i < n_independent_variables; i++) + { + using derivative_type = + typename ADNumberTraits::derivative_type; + const derivative_type gradient_i = + ADNumberTraits::get_directional_derivative( + independent_variables[i], i); + + for (unsigned int j = 0; j <= i; ++j) // Symmetry + { + // Extract higher-order directional derivatives. Depending on + // the AD number type, the result may be another AD number or a + // floating point value. + const ScalarType hessian_ij = + internal::NumberType::value( + ADNumberTraits::get_directional_derivative( + gradient_i, j)); + hessian[i][j] = hessian_ij; + if (i != j) + hessian[j][i] = hessian_ij; // Symmetry + } + } + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad>::type>:: + values(const std::vector &dependent_variables, + Vector & values) const + { + Assert(values.size() == dependent_variables.size(), + ExcDimensionMismatch(values.size(), dependent_variables.size())); + + const std::size_t n_dependent_variables = dependent_variables.size(); + for (unsigned int i = 0; i < n_dependent_variables; i++) + values[i] = ADNumberTraits::get_scalar_value( + dependent_variables[i]); + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::sacado_rad || + ADNumberTraits::type_code == + NumberTypes::sacado_rad_dfad>::type>:: + jacobian(const std::vector &independent_variables, + const std::vector &dependent_variables, + FullMatrix & jacobian) const + { + Assert(AD::ADNumberTraits::n_supported_derivative_levels >= + 1, + ExcSupportedDerivativeLevels( + AD::ADNumberTraits::n_supported_derivative_levels, + 1)); + Assert(jacobian.m() == dependent_variables.size(), + ExcDimensionMismatch(jacobian.m(), dependent_variables.size())); + Assert(jacobian.n() == independent_variables.size(), + ExcDimensionMismatch(jacobian.n(), independent_variables.size())); + + const std::size_t n_independent_variables = independent_variables.size(); + const std::size_t n_dependent_variables = dependent_variables.size(); + + // In reverse mode, the gradients are computed from the + // independent variables (i.e. the adjoint). + // For a demonstration of why this accumulation process is + // required, see the unit tests + // sacado/basic_01b.cc and sacado/basic_02b.cc + // Here we also take into consideration the derivative type: + // The Sacado number may be of the nested variety, in which + // case the effect of the accumulation process on the + // sensitivities of the nested number need to be accounted for. + using accumulation_type = + typename ADNumberTraits::derivative_type; + std::vector rad_accumulation( + n_independent_variables, + dealii::internal::NumberType::value(0.0)); + + for (unsigned int i = 0; i < n_dependent_variables; i++) + { + internal::reverse_mode_dependent_variable_activation( + const_cast(dependent_variables[i])); + for (unsigned int j = 0; j < n_independent_variables; j++) + { + const accumulation_type df_i_dx_j = + ADNumberTraits::get_directional_derivative( + independent_variables[j], + i /*This number doesn't really matter*/) - + rad_accumulation[j]; + jacobian[i][j] = + internal::NumberType::value(df_i_dx_j); + rad_accumulation[j] += df_i_dx_j; + } + } + } + + + + // Specialization for auto-differentiable numbers that use + // forward mode to compute the first (and, if supported, second) + // derivatives. + + template + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if< + ADNumberTraits::type_code == + NumberTypes::adolc_tapeless || + ADNumberTraits::type_code == NumberTypes::sacado_dfad || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad_dfad>::type>::TapelessDrivers() + : dependent_variable_marking_safe(false) + {} + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad_dfad>::type>:: + initialize_global_environment(const unsigned int n_independent_variables) + { + internal::configure_tapeless_mode(n_independent_variables); + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad_dfad>::type>:: + allow_dependent_variable_marking() + { + dependent_variable_marking_safe = true; + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad_dfad>::type>:: + prevent_dependent_variable_marking() + { + dependent_variable_marking_safe = false; + } + + + template + bool + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad_dfad>::type>:: + is_dependent_variable_marking_allowed() const + { + return dependent_variable_marking_safe; + } + + + template + ScalarType + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad_dfad>::type>:: + value(const std::vector &dependent_variables) const + { + Assert(dependent_variables.size() == 1, + ExcDimensionMismatch(dependent_variables.size(), 1)); + return ADNumberTraits::get_scalar_value( + dependent_variables[0]); + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad_dfad>::type>:: + gradient(const std::vector &independent_variables, + const std::vector &dependent_variables, + Vector & gradient) const + { + Assert(AD::ADNumberTraits::n_supported_derivative_levels >= + 1, + ExcSupportedDerivativeLevels( + AD::ADNumberTraits::n_supported_derivative_levels, + 1)); + Assert(dependent_variables.size() == 1, + ExcDimensionMismatch(dependent_variables.size(), 1)); + Assert(gradient.size() == independent_variables.size(), + ExcDimensionMismatch(gradient.size(), + independent_variables.size())); + + // In forward mode, the gradients are computed from the + // dependent variables + const std::size_t n_independent_variables = independent_variables.size(); + for (unsigned int i = 0; i < n_independent_variables; i++) + gradient[i] = internal::NumberType::value( + ADNumberTraits::get_directional_derivative( + dependent_variables[0], i)); + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad_dfad>::type>:: + hessian(const std::vector &independent_variables, + const std::vector &dependent_variables, + FullMatrix & hessian) const + { + Assert(AD::ADNumberTraits::n_supported_derivative_levels >= + 2, + ExcSupportedDerivativeLevels( + AD::ADNumberTraits::n_supported_derivative_levels, + 2)); + Assert(dependent_variables.size() == 1, + ExcDimensionMismatch(dependent_variables.size(), 1)); + Assert(hessian.m() == independent_variables.size(), + ExcDimensionMismatch(hessian.m(), independent_variables.size())); + Assert(hessian.n() == independent_variables.size(), + ExcDimensionMismatch(hessian.n(), independent_variables.size())); + + // In forward mode, the gradients are computed from the + // dependent variables + const std::size_t n_independent_variables = independent_variables.size(); + for (unsigned int i = 0; i < n_independent_variables; i++) + { + using derivative_type = + typename ADNumberTraits::derivative_type; + const derivative_type gradient_i = + ADNumberTraits::get_directional_derivative( + dependent_variables[0], i); + + for (unsigned int j = 0; j <= i; ++j) // Symmetry + { + // Extract higher-order directional derivatives. Depending on + // the AD number type, the result may be another AD number or a + // floating point value. + const ScalarType hessian_ij = + internal::NumberType::value( + ADNumberTraits::get_directional_derivative( + gradient_i, j)); + hessian[i][j] = hessian_ij; + if (i != j) + hessian[j][i] = hessian_ij; // Symmetry + } + } + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad_dfad>::type>:: + values(const std::vector &dependent_variables, + Vector & values) const + { + Assert(values.size() == dependent_variables.size(), + ExcDimensionMismatch(values.size(), dependent_variables.size())); + + const std::size_t n_dependent_variables = dependent_variables.size(); + for (unsigned int i = 0; i < n_dependent_variables; i++) + values[i] = ADNumberTraits::get_scalar_value( + dependent_variables[i]); + } + + + template + void + TapelessDrivers< + ADNumberType, + ScalarType, + typename std::enable_if::type_code == + NumberTypes::adolc_tapeless || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad || + ADNumberTraits::type_code == + NumberTypes::sacado_dfad_dfad>::type>:: + jacobian(const std::vector &independent_variables, + const std::vector &dependent_variables, + FullMatrix & jacobian) const + { + Assert(AD::ADNumberTraits::n_supported_derivative_levels >= + 1, + ExcSupportedDerivativeLevels( + AD::ADNumberTraits::n_supported_derivative_levels, + 1)); + Assert(jacobian.m() == dependent_variables.size(), + ExcDimensionMismatch(jacobian.m(), dependent_variables.size())); + Assert(jacobian.n() == independent_variables.size(), + ExcDimensionMismatch(jacobian.n(), independent_variables.size())); + + const std::size_t n_independent_variables = independent_variables.size(); + const std::size_t n_dependent_variables = dependent_variables.size(); + + // In forward mode, the gradients are computed from the + // dependent variables + for (unsigned int i = 0; i < n_dependent_variables; i++) + for (unsigned int j = 0; j < n_independent_variables; j++) + jacobian[i][j] = internal::NumberType::value( + ADNumberTraits::get_directional_derivative( + dependent_variables[i], j)); + } + + + } // namespace AD +} // namespace Differentiation + + +/* --- Explicit instantiations --- */ +# ifdef DEAL_II_WITH_ADOLC +# include "ad_drivers.inst1" +# endif +# ifdef DEAL_II_TRILINOS_WITH_SACADO +# include "ad_drivers.inst2" +# endif + + +DEAL_II_NAMESPACE_CLOSE + + +#endif // defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO) diff --git a/source/differentiation/ad/ad_drivers.inst1.in b/source/differentiation/ad/ad_drivers.inst1.in new file mode 100644 index 000000000000..f0829398fb98 --- /dev/null +++ b/source/differentiation/ad/ad_drivers.inst1.in @@ -0,0 +1,73 @@ +// --------------------------------------------------------------------- +// +// 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 at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +// TODO: Include complex types + +for (number : REAL_SCALARS) +{ + namespace Differentiation + \{ + namespace AD + \{ + + // -------------------------- TapedDrivers ---------------------- + + template + struct TapedDrivers::ad_type,number>; + + template + struct TapedDrivers::ad_type,number>; + + // -------------------------- TapelessDrivers ---------------------- + + template + struct TapelessDrivers::ad_type,number>; + + template + struct TapelessDrivers::ad_type,number>; + + \} + \} +} + +// Instantiations for ADHelpers for which the underlying number type is fixed +for () +{ + namespace Differentiation + \{ + namespace AD + \{ + + + + // -------------------------- Types ---------------------- + + template + struct Types::ad_type>; + + template + struct Types::ad_type>; + + // -------------------------- Numbers ---------------------- + + template + struct Numbers::ad_type>; + + template + struct Numbers::ad_type>; + + \} + \} +} \ No newline at end of file diff --git a/source/differentiation/ad/ad_drivers.inst2.in b/source/differentiation/ad/ad_drivers.inst2.in new file mode 100644 index 000000000000..f8aa39e134b7 --- /dev/null +++ b/source/differentiation/ad/ad_drivers.inst2.in @@ -0,0 +1,83 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 - 2017 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. +// +// --------------------------------------------------------------------- + +// TODO: Include complex types + +for (number : REAL_SCALARS) +{ + namespace Differentiation + \{ + namespace AD + \{ + + // -------------------------- Types ---------------------- + + template + struct Types::ad_type>; + + template + struct Types::ad_type>; + + template + struct Types::ad_type>; + + template + struct Types::ad_type>; + + // -------------------------- Numbers ---------------------- + + template + struct Numbers::ad_type>; + + template + struct Numbers::ad_type>; + + template + struct Numbers::ad_type>; + + template + struct Numbers::ad_type>; + + // -------------------------- TapedDrivers ---------------------- + + template + struct TapedDrivers::ad_type,number>; + + template + struct TapedDrivers::ad_type,number>; + + template + struct TapedDrivers::ad_type,number>; + + template + struct TapedDrivers::ad_type,number>; + + // -------------------------- TapelessDrivers ---------------------- + + template + struct TapelessDrivers::ad_type,number>; + + template + struct TapelessDrivers::ad_type,number>; + + template + struct TapelessDrivers::ad_type,number>; + + template + struct TapelessDrivers::ad_type,number>; + + \} + \} +} diff --git a/source/differentiation/ad/ad_helpers.cc b/source/differentiation/ad/ad_helpers.cc index 941f6c830fc2..c1a29cb1f389 100644 --- a/source/differentiation/ad/ad_helpers.cc +++ b/source/differentiation/ad/ad_helpers.cc @@ -377,7 +377,7 @@ namespace Differentiation Assert(is_registered_tape(tape_index), ExcMessage("Tape number not registered")); - TapedDrivers::print_tape_stats(tape_index, stream); + this->taped_driver.print_tape_stats(tape_index, stream); } @@ -829,8 +829,8 @@ namespace Differentiation ExcDimensionMismatch(this->independent_variable_values.size(), this->n_independent_variables())); - return TapedDrivers::value( - this->active_tape_index(), this->independent_variable_values); + return this->taped_driver.value(this->active_tape_index(), + this->independent_variable_values); } else { @@ -840,8 +840,7 @@ namespace Differentiation this->n_independent_variables(), ExcInternalError()); - return TapelessDrivers::value( - this->dependent_variables); + return this->tapeless_driver.value(this->dependent_variables); } } @@ -891,10 +890,9 @@ namespace Differentiation ExcDimensionMismatch(this->independent_variable_values.size(), this->n_independent_variables())); - TapedDrivers::gradient( - this->active_tape_index(), - this->independent_variable_values, - gradient); + this->taped_driver.gradient(this->active_tape_index(), + this->independent_variable_values, + gradient); } else { @@ -904,8 +902,9 @@ namespace Differentiation this->n_independent_variables(), ExcInternalError()); - TapelessDrivers::gradient( - this->independent_variables, this->dependent_variables, gradient); + this->tapeless_driver.gradient(this->independent_variables, + this->dependent_variables, + gradient); } } @@ -961,10 +960,9 @@ namespace Differentiation ExcDimensionMismatch(this->independent_variable_values.size(), this->n_independent_variables())); - TapedDrivers::hessian( - this->active_tape_index(), - this->independent_variable_values, - hessian); + this->taped_driver.hessian(this->active_tape_index(), + this->independent_variable_values, + hessian); } else { @@ -973,8 +971,10 @@ namespace Differentiation Assert(this->independent_variables.size() == this->n_independent_variables(), ExcInternalError()); - TapelessDrivers::hessian( - this->independent_variables, this->dependent_variables, hessian); + + this->tapeless_driver.hessian(this->independent_variables, + this->dependent_variables, + hessian); } } @@ -1048,18 +1048,16 @@ namespace Differentiation ExcDimensionMismatch(this->independent_variable_values.size(), this->n_independent_variables())); - TapedDrivers::values( - this->active_tape_index(), - this->n_dependent_variables(), - this->independent_variable_values, - values); + this->taped_driver.values(this->active_tape_index(), + this->n_dependent_variables(), + this->independent_variable_values, + values); } else { Assert(ADNumberTraits::is_tapeless == true, ExcInternalError()); - TapelessDrivers::values( - this->dependent_variables, values); + this->tapeless_driver.values(this->dependent_variables, values); } } @@ -1106,11 +1104,10 @@ namespace Differentiation ExcDimensionMismatch(this->independent_variable_values.size(), this->n_independent_variables())); - TapedDrivers::jacobian( - this->active_tape_index(), - this->n_dependent_variables(), - this->independent_variable_values, - jacobian); + this->taped_driver.jacobian(this->active_tape_index(), + this->n_dependent_variables(), + this->independent_variable_values, + jacobian); } else { @@ -1119,8 +1116,10 @@ namespace Differentiation Assert(this->independent_variables.size() == this->n_independent_variables(), ExcInternalError()); - TapelessDrivers::jacobian( - this->independent_variables, this->dependent_variables, jacobian); + + this->tapeless_driver.jacobian(this->independent_variables, + this->dependent_variables, + jacobian); } } From b8b6915b2504ecf5b2166c36d47cb0069fb33e60 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 6 Dec 2018 14:40:50 +0100 Subject: [PATCH 002/507] Expose AD driver methods via ADHelper bass class. Further features provided by the drivers are exposed through the base helper class. --- .../deal.II/differentiation/ad/ad_helpers.h | 44 +++++++++++++++++++ source/differentiation/ad/ad_helpers.cc | 38 ++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index 7aad5de7edab..4d8bcc78a325 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -478,6 +478,50 @@ namespace Differentiation activate_recorded_tape( const typename Types::tape_index tape_index); + /** + * Return a flag that, when true, indicates that the + * retaping of the dependent function is necessary for a reliable + * computation to be performed on a tape with the given @p tape_index. + * This may be necessary a sign comparison within branched operations + * yields different results to those computed at the original tape + * evaluation point. + * + * For the output of this function to be meaningful, it must be called + * after the activate_recorded_tape() is called and the new evaluation + * point for the tape (i.e. values of the independent variables) have + * been set and subsequently used (i.e. in the determination of the values + * or derivatives of the dependent variables). + */ + bool + recorded_tape_requires_retaping( + const typename Types::tape_index tape_index) const; + + /** + * Return a flag that, when true, indicates that the + * retaping of the dependent function is necessary for a reliable + * computation to be performed on the avtive tape. This may be necessary a + * sign comparison within branched operations yields different results to + * those computed at the original tape evaluation point. + * + * For the output of this function to be meaningful, it must be called + * after the activate_recorded_tape() is called and the new evaluation + * point for the tape (i.e. values of the independent variables) have + * been set and subsequently used (i.e. in the determination of the values + * or derivatives of the dependent variables). + */ + bool + active_tape_requires_retaping() const; + + /** + * Clears and removes the currently active tape. + * + * This is typically only necessary when branch switching is detected on + * the original tape at evaluation point. This state can be checked using + * the active_tape_requires_retaping() function. + */ + void + clear_active_tape(); + //@} protected: diff --git a/source/differentiation/ad/ad_helpers.cc b/source/differentiation/ad/ad_helpers.cc index c1a29cb1f389..d8a7866ba377 100644 --- a/source/differentiation/ad/ad_helpers.cc +++ b/source/differentiation/ad/ad_helpers.cc @@ -475,6 +475,44 @@ namespace Differentiation + template + bool + ADHelperBase::recorded_tape_requires_retaping( + const typename Types::tape_index tape_index) const + { + if (ADNumberTraits::is_tapeless == true) + return false; + + return taped_driver.requires_retaping(tape_index); + } + + + + template + bool + ADHelperBase::active_tape_requires_retaping() + const + { + if (ADNumberTraits::is_tapeless == true) + return false; + + return taped_driver.last_action_requires_retaping(); + } + + + + template + void + ADHelperBase::clear_active_tape() + { + if (ADNumberTraits::is_tapeless == true) + return; + + taped_driver.remove_tape(taped_driver.active_tape_index()); + } + + + template void ADHelperBase::activate_tape( From c7c946aac00869577af146fa79516f8bbcd565b0 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 6 Dec 2018 14:41:28 +0100 Subject: [PATCH 003/507] Improve some error messages in ADHelper classes. --- source/differentiation/ad/ad_helpers.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/source/differentiation/ad/ad_helpers.cc b/source/differentiation/ad/ad_helpers.cc index d8a7866ba377..e259ab6019c6 100644 --- a/source/differentiation/ad/ad_helpers.cc +++ b/source/differentiation/ad/ad_helpers.cc @@ -752,7 +752,8 @@ namespace Differentiation this->finalize_sensitive_independent_variables(); Assert(this->independent_variables.size() == this->n_independent_variables(), - ExcInternalError()); + ExcDimensionMismatch(this->independent_variables.size(), + this->n_independent_variables())); return this->independent_variables; } @@ -876,7 +877,8 @@ namespace Differentiation ExcInternalError()); Assert(this->independent_variables.size() == this->n_independent_variables(), - ExcInternalError()); + ExcDimensionMismatch(this->independent_variables.size(), + this->n_independent_variables())); return this->tapeless_driver.value(this->dependent_variables); } @@ -938,7 +940,8 @@ namespace Differentiation ExcInternalError()); Assert(this->independent_variables.size() == this->n_independent_variables(), - ExcInternalError()); + ExcDimensionMismatch(this->independent_variables.size(), + this->n_independent_variables())); this->tapeless_driver.gradient(this->independent_variables, this->dependent_variables, @@ -1008,7 +1011,8 @@ namespace Differentiation ExcInternalError()); Assert(this->independent_variables.size() == this->n_independent_variables(), - ExcInternalError()); + ExcDimensionMismatch(this->independent_variables.size(), + this->n_independent_variables())); this->tapeless_driver.hessian(this->independent_variables, this->dependent_variables, @@ -1153,7 +1157,8 @@ namespace Differentiation ExcInternalError()); Assert(this->independent_variables.size() == this->n_independent_variables(), - ExcInternalError()); + ExcDimensionMismatch(this->independent_variables.size(), + this->n_independent_variables())); this->tapeless_driver.jacobian(this->independent_variables, this->dependent_variables, From aa2b68ee540a3d8ab8223e901590601eca7e409e Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 6 Dec 2018 14:41:52 +0100 Subject: [PATCH 004/507] Improve some documentation in ADHelper classes. --- include/deal.II/differentiation/ad/ad_helpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index 4d8bcc78a325..c8bd16a31b7d 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -949,7 +949,7 @@ namespace Differentiation * Depending on the selected @p ADNumberTypeCode, this may or may not * correspond with the @p ScalarType prescribed as a template argument. * - * @note If the keep flag has been set when + * @note If the @p keep_independent_values flag has been set when * ADHelperBase::start_recording_operations() is called then the tape is * immediately usable after creation, and the values of the independent * variables set by register_dof_values() are those at which the function @@ -969,7 +969,7 @@ namespace Differentiation * which to extract the local degree of freedom values. This would * typically obtained by calling cell->get_dof_indices(). * - * @note If the keep flag has been set when + * @note If the @p keep_independent_values flag has been set when * ADHelperBase::start_recording_operations() is called then the tape is * immediately usable after creation, and the values of the independent * variables set by register_dof_values() are those at which the function From 9387ce1dca1bd41683b1f7d89cc7e096fa6a4b39 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 8 Dec 2018 12:11:03 +0100 Subject: [PATCH 005/507] Fix compiling and avoid warnings in tests --- source/differentiation/ad/ad_drivers.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/source/differentiation/ad/ad_drivers.cc b/source/differentiation/ad/ad_drivers.cc index a0447c8d7702..3d29e40a5bdd 100644 --- a/source/differentiation/ad/ad_drivers.cc +++ b/source/differentiation/ad/ad_drivers.cc @@ -893,8 +893,7 @@ namespace Differentiation double, typename std::enable_if::type_code == NumberTypes::adolc_taped>::type>:: - is_registered_tape( - const typename Types::tape_index tape_index) const + is_registered_tape(const typename Types::tape_index) const { AssertThrow(false, ExcRequiresADOLC()); return false; @@ -943,6 +942,8 @@ namespace Differentiation AssertThrow(false, ExcRequiresADOLC()); } + + template std::vector::tape_index> TapedDrivers< ADNumberType, @@ -1028,8 +1029,7 @@ namespace Differentiation double, typename std::enable_if< ADNumberTraits::type_code == - NumberTypes::adolc_taped>::type>::print(std::ostream &stream) - const + NumberTypes::adolc_taped>::type>::print(std::ostream &) const { AssertThrow(false, ExcRequiresADOLC()); } @@ -1050,7 +1050,7 @@ namespace Differentiation template - TapedDrivers< + typename TapedDrivers< ADNumberType, double, typename std::enable_if::type_code == @@ -1082,6 +1082,8 @@ namespace Differentiation AssertThrow(false, ExcRequiresADOLC()); } + + template void TapedDrivers< ADNumberType, From e2ae49cbf79e256343543906b09a2d6c1a8890a2 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Tue, 22 Jan 2019 16:17:45 +0100 Subject: [PATCH 006/507] Improve documentation in AD drivers header --- .../deal.II/differentiation/ad/ad_drivers.h | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/include/deal.II/differentiation/ad/ad_drivers.h b/include/deal.II/differentiation/ad/ad_drivers.h index 5af046665bf6..7f76fe846134 100644 --- a/include/deal.II/differentiation/ad/ad_drivers.h +++ b/include/deal.II/differentiation/ad/ad_drivers.h @@ -279,10 +279,31 @@ namespace Differentiation * Return a flag that, when true, indicates that the retaping * of the dependent function for the chosen @p tape_index is necessary for * a reliable computation to be performed. - * This may be necessary a sign comparison within branched operations + * This may be necessary if a sign comparison within branched operations * yields different results to those computed at the original tape * evaluation point. * + * This issue, known as "branch switching", can be clarified by means of + * a trivial example: + * @code + * ADNumberType func (ADNumberType x, ADNumberType y, ADNumberType z) + * { + * if (x < y) + * return y; + * else + * return x*z; + * } + * @endcode + * During taping, the conditional statement may be either true or + * false, and the result (with its sensitivities) returned by + * this function. For some other evaluation of the tape (i.e. for some + * different + * inputs @p x and @p y, the other branch of the conditional check may be + * chosen. The result of following this code path has not been recorded on + * the tape, and therefore cannot be evaluated. In such a case, it is + * therefore necessary to re-record the tape at the new evaluation point + * in order to resolve the new code branch. + * * @note The chosen tape index must be greater than * Numbers::invalid_tape_index and less than * Numbers::max_tape_index. @@ -295,9 +316,30 @@ namespace Differentiation * Return a flag that, when true, indicates that the retaping * of the dependent function is necessary for a reliable computation to be * performed on the active tape. - * This may be necessary a sign comparison within branched operations + * This may be necessary if a sign comparison within branched operations * yields different results to those computed at the original tape * evaluation point. + * + * This issue, known as "branch switching", can be clarified by means of + * a trivial example: + * @code + * ADNumberType func (ADNumberType x, ADNumberType y, ADNumberType z) + * { + * if (x < y) + * return y; + * else + * return x*z; + * } + * @endcode + * During taping, the conditional statement may be either true or + * false, and the result (with its sensitivities) returned by + * this function. For some other evaluation of the tape (i.e. for some + * different + * inputs @p x and @p y, the other branch of the conditional check may be + * chosen. The result of following this code path has not been recorded on + * the tape, and therefore cannot be evaluated. In such a case, it is + * therefore necessary to re-record the tape at the new evaluation point + * in order to resolve the new code branch. */ bool last_action_requires_retaping() const; @@ -869,6 +911,8 @@ namespace Differentiation * * When the @p status variable takes a negative value, retaping of the dependent * function is necessary for a reliable computation to be performed. + * This status can be queried through the requires_retaping() and + * last_action_requires_retaping() functions. */ mutable std::map::tape_index, int> status; From 79c6959019e0978510b49f8ef7aa6a90bbbf3ee2 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Tue, 22 Jan 2019 16:18:57 +0100 Subject: [PATCH 007/507] Remove unnecessary temporary object when copying a vector --- source/differentiation/ad/ad_drivers.cc | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/source/differentiation/ad/ad_drivers.cc b/source/differentiation/ad/ad_drivers.cc index 3d29e40a5bdd..ff0a9637cf40 100644 --- a/source/differentiation/ad/ad_drivers.cc +++ b/source/differentiation/ad/ad_drivers.cc @@ -476,17 +476,13 @@ namespace Differentiation { // We've chosen to use unsigned shorts for the tape // index type (a safety precaution) so we need to - // perform a conversion betwwen ADOL-C's native tape + // perform a conversion between ADOL-C's native tape // index type and that chosen by us. std::vector registered_tape_indices_s; cachedTraceTags(registered_tape_indices_s); - std::vector::tape_index> - registered_tape_indices(registered_tape_indices_s.size()); - std::copy(registered_tape_indices_s.begin(), - registered_tape_indices_s.end(), - registered_tape_indices.begin()); - return registered_tape_indices; + return std::vector::tape_index>( + registered_tape_indices_s.begin(), registered_tape_indices_s.end()); } @@ -537,8 +533,10 @@ namespace Differentiation // See ADOL-C manual section 1.7 and comments in last paragraph of // section 3.1 - Assert(status_tape < 4 && status_tape >= -2, - ExcIndexRange(status_tape, -2, 4)); + Assert( + status_tape < 4 && status_tape >= -2, + ExcMessage( + "The tape status is not within the range specified within the ADOL-C documentation.")); return (status_tape < 0); } From 7aceecd2706833c12f194bd2332ee9595f76a415 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Tue, 22 Jan 2019 16:19:15 +0100 Subject: [PATCH 008/507] Improve documentation to AD helpers header. --- .../deal.II/differentiation/ad/ad_helpers.h | 55 +++++++++++++++++-- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index c8bd16a31b7d..ac716dfd94c2 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -482,12 +482,33 @@ namespace Differentiation * Return a flag that, when true, indicates that the * retaping of the dependent function is necessary for a reliable * computation to be performed on a tape with the given @p tape_index. - * This may be necessary a sign comparison within branched operations + * This may be necessary if a sign comparison within branched operations * yields different results to those computed at the original tape * evaluation point. * + * This issue, known as "branch switching", can be clarified by means of + * a trivial example: + * @code + * ADNumberType func (ADNumberType x, ADNumberType y, ADNumberType z) + * { + * if (x < y) + * return y; + * else + * return x*z; + * } + * @endcode + * During taping, the conditional statement may be either true or + * false, and the result (with its sensitivities) returned by + * this function. For some other evaluation of the tape (i.e. for some + * different + * inputs @p x and @p y, the other branch of the conditional check may be + * chosen. The result of following this code path has not been recorded on + * the tape, and therefore cannot be evaluated. In such a case, it is + * therefore necessary to re-record the tape at the new evaluation point + * in order to resolve the new code branch. + * * For the output of this function to be meaningful, it must be called - * after the activate_recorded_tape() is called and the new evaluation + * after activate_recorded_tape() is called and the new evaluation * point for the tape (i.e. values of the independent variables) have * been set and subsequently used (i.e. in the determination of the values * or derivatives of the dependent variables). @@ -499,12 +520,34 @@ namespace Differentiation /** * Return a flag that, when true, indicates that the * retaping of the dependent function is necessary for a reliable - * computation to be performed on the avtive tape. This may be necessary a - * sign comparison within branched operations yields different results to - * those computed at the original tape evaluation point. + * computation to be performed on the active tape. + * This may be necessary if a sign comparison within branched operations + * yields different results to those computed at the original tape + * evaluation point. + * + * This issue, known as "branch switching", can be clarified by means of + * a trivial example: + * @code + * ADNumberType func (ADNumberType x, ADNumberType y, ADNumberType z) + * { + * if (x < y) + * return y; + * else + * return x*z; + * } + * @endcode + * During taping, the conditional statement may be either true or + * false, and the result (with its sensitivities) returned by + * this function. For some other evaluation of the tape (i.e. for some + * different + * inputs @p x and @p y, the other branch of the conditional check may be + * chosen. The result of following this code path has not been recorded on + * the tape, and therefore cannot be evaluated. In such a case, it is + * therefore necessary to re-record the tape at the new evaluation point + * in order to resolve the new code branch. * * For the output of this function to be meaningful, it must be called - * after the activate_recorded_tape() is called and the new evaluation + * after activate_recorded_tape() is called and the new evaluation * point for the tape (i.e. values of the independent variables) have * been set and subsequently used (i.e. in the determination of the values * or derivatives of the dependent variables). From 1caf7e71b5f353520772936eeb9fe4ec3bdea2e8 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Tue, 22 Jan 2019 16:20:03 +0100 Subject: [PATCH 009/507] Fix a typo in documentation for ADHelperResidualLinearization class --- include/deal.II/differentiation/ad/ad_helpers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index ac716dfd94c2..f5cb753260e4 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -1417,7 +1417,7 @@ namespace Differentiation * // must refer to one of these types. See the example for the * // ADHelperEnergyFunctional for details on how to extend * // support to taped AD numbers. - * using ADHelper = AD::ADHelperEnergyFunctional<...>; + * using ADHelper = AD::ADHelperResidualLinearization<...>; * using ADNumberType = typename ADHelper::ad_type; * * // Create and initialize an instance of the helper class. From 877fb0179735fe7c2258a3c0dbd970d9115f1fc3 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 24 Jan 2019 23:41:35 +0100 Subject: [PATCH 010/507] Parse boundary_ids in GMSH-4 format --- source/grid/grid_in.cc | 94 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/source/grid/grid_in.cc b/source/grid/grid_in.cc index c00da148814e..87fe841d9c03 100644 --- a/source/grid/grid_in.cc +++ b/source/grid/grid_in.cc @@ -1404,10 +1404,11 @@ GridIn::read_msh(std::istream &in) Assert(tria != nullptr, ExcNoTriangulationSelected()); AssertThrow(in, ExcIO()); - unsigned int n_vertices; - unsigned int n_cells; - unsigned int dummy; - std::string line; + unsigned int n_vertices; + unsigned int n_cells; + unsigned int dummy; + std::string line; + std::array, 4> tag_maps; in >> line; @@ -1451,14 +1452,73 @@ GridIn::read_msh(std::istream &in) in >> line; } - // if the next block is of kind $Entities, ignore it + // if the next block is of kind $Entities, parse it if (line == "$Entities") { - do + unsigned long numPoints, numCurves, numSurfaces, numVolumes, + numPhysicals; + int tag, physicalTag; + double boxMinX, boxMinY, boxMinZ, boxMaxX, boxMaxY, boxMaxZ; + + in >> numPoints >> numCurves >> numSurfaces >> numVolumes; + for (unsigned int i = 0; i < numPoints; ++i) { - in >> line; + // parse point ids + in >> tag >> boxMinX >> boxMinY >> boxMinZ >> boxMaxX >> + boxMaxY >> boxMaxZ >> numPhysicals; + AssertThrow(numPhysicals < 2, + ExcMessage("More than one tag is not supported!")); + for (unsigned int j = 0; j < numPhysicals; ++j) + in >> physicalTag; + tag_maps[0][tag] = (numPhysicals == 0) ? 0 : physicalTag; + } + for (unsigned int i = 0; i < numCurves; ++i) + { + // parse curve ids + in >> tag >> boxMinX >> boxMinY >> boxMinZ >> boxMaxX >> + boxMaxY >> boxMaxZ >> numPhysicals; + AssertThrow(numPhysicals < 2, + ExcMessage("More than one tag is not supported!")); + for (unsigned int j = 0; j < numPhysicals; ++j) + in >> physicalTag; + tag_maps[1][tag] = (numPhysicals == 0) ? 0 : physicalTag; + in >> numPoints; + for (unsigned int j = 0; j < numPoints; ++j) + in >> tag; + } + + for (unsigned int i = 0; i < numSurfaces; ++i) + { + // parse surface ids + in >> tag >> boxMinX >> boxMinY >> boxMinZ >> boxMaxX >> + boxMaxY >> boxMaxZ >> numPhysicals; + AssertThrow(numPhysicals < 2, + ExcMessage("More than one tag is not supported!")); + for (unsigned int j = 0; j < numPhysicals; ++j) + in >> physicalTag; + tag_maps[2][tag] = (numPhysicals == 0) ? 0 : physicalTag; + in >> numCurves; + for (unsigned int j = 0; j < numCurves; ++j) + in >> tag; + } + for (unsigned int i = 0; i < numVolumes; ++i) + { + // parse volume ids + in >> tag >> boxMinX >> boxMinY >> boxMinZ >> boxMaxX >> + boxMaxY >> boxMaxZ >> numPhysicals; + AssertThrow(numPhysicals < 2, + ExcMessage("More than one tag is not supported!")); + for (unsigned int j = 0; j < numPhysicals; ++j) + in >> physicalTag; + tag_maps[3][tag] = (numPhysicals == 0) ? 0 : physicalTag; + in >> numSurfaces; + for (unsigned int j = 0; j < numSurfaces; ++j) + in >> tag; } - while (line != "$EndEntities"); + std::cout << line << std::endl; + in >> line; + std::cout << line << std::endl; + AssertThrow(line == "$EndEntities", ExcInvalidGMSHInput(line)); in >> line; } @@ -1497,20 +1557,19 @@ GridIn::read_msh(std::istream &in) unsigned int global_vertex = 0; for (int entity_block = 0; entity_block < n_entity_blocks; ++entity_block) { - int tagEntity; - int dimEntity; int parametric; unsigned long numNodes; if (gmsh_file_format < 4) { - tagEntity = 0; - dimEntity = 0; numNodes = n_vertices; parametric = 0; } else - in >> tagEntity >> dimEntity >> parametric >> numNodes; + { + int tagEntity, dimEntity; + in >> tagEntity >> dimEntity >> parametric >> numNodes; + } for (unsigned long vertex_per_entity = 0; vertex_per_entity < numNodes; ++vertex_per_entity, ++global_vertex) { @@ -1574,20 +1633,21 @@ GridIn::read_msh(std::istream &in) for (int entity_block = 0; entity_block < n_entity_blocks; ++entity_block) { unsigned int material_id; - int dimEntity; unsigned long numElements; int cell_type; if (gmsh_file_format < 4) { material_id = 0; - dimEntity = 0; cell_type = 0; numElements = n_cells; } else - in >> material_id >> dimEntity >> cell_type >> numElements; - + { + int tagEntity, dimEntity; + in >> tagEntity >> dimEntity >> cell_type >> numElements; + material_id = tag_maps[dimEntity][tagEntity]; + } for (unsigned int cell_per_entity = 0; cell_per_entity < numElements; ++cell_per_entity, ++global_cell) { From 5d4ae1a463fef3661961903702d3a71f9f44c5cd Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 25 Jan 2019 15:20:49 +0100 Subject: [PATCH 011/507] Add GMSH-4 tests --- tests/grid/grid_in_gmsh_01_v4.cc | 136 + tests/grid/grid_in_gmsh_01_v4.output | 16 + tests/grid/grid_in_msh_02_13_v4.cc | 75 + tests/grid/grid_in_msh_02_13_v4.output | 3 + tests/grid/grid_in_msh_02_v4.cc | 70 + tests/grid/grid_in_msh_02_v4.output | 3 + tests/grid/grid_in_msh_03_v4.cc | 69 + tests/grid/grid_in_msh_03_v4.output | 569 + tests/grid/grid_in_msh_03_v4/mesh.msh | 213 + tests/grid/grid_in_msh_v4.cc | 63 + tests/grid/grid_in_msh_v4.output | 1262 ++ tests/grid/grid_in_msh_v4/mesh.msh | 501 + tests/grid/grid_in_msh_version_4.cc | 159 + tests/grid/grid_in_msh_version_4.output | 7 + tests/grid/grid_in_msh_version_4/hole81.msh | 205 + tests/grid/grid_in_msh_version_4/hole8170.msh | 16634 ++++++++++++++++ tests/grid/grids/grid_in_msh_01.2d.v4.msh | 36 + tests/grid/grids/grid_in_msh_01.2da.v4.msh | 904 + tests/grid/grids/grid_in_msh_01.3d.v4.msh | 48 + tests/grid/grids/grid_in_msh_01.3d_neg.v4.msh | 48 + tests/grid/grids/grid_in_msh_01.3da.v4.msh | 1218 ++ tests/grid/grids/grid_in_msh_02_v4.msh | 44 + 22 files changed, 22283 insertions(+) create mode 100644 tests/grid/grid_in_gmsh_01_v4.cc create mode 100644 tests/grid/grid_in_gmsh_01_v4.output create mode 100644 tests/grid/grid_in_msh_02_13_v4.cc create mode 100644 tests/grid/grid_in_msh_02_13_v4.output create mode 100644 tests/grid/grid_in_msh_02_v4.cc create mode 100644 tests/grid/grid_in_msh_02_v4.output create mode 100644 tests/grid/grid_in_msh_03_v4.cc create mode 100644 tests/grid/grid_in_msh_03_v4.output create mode 100644 tests/grid/grid_in_msh_03_v4/mesh.msh create mode 100644 tests/grid/grid_in_msh_v4.cc create mode 100644 tests/grid/grid_in_msh_v4.output create mode 100644 tests/grid/grid_in_msh_v4/mesh.msh create mode 100644 tests/grid/grid_in_msh_version_4.cc create mode 100644 tests/grid/grid_in_msh_version_4.output create mode 100644 tests/grid/grid_in_msh_version_4/hole81.msh create mode 100644 tests/grid/grid_in_msh_version_4/hole8170.msh create mode 100644 tests/grid/grids/grid_in_msh_01.2d.v4.msh create mode 100644 tests/grid/grids/grid_in_msh_01.2da.v4.msh create mode 100644 tests/grid/grids/grid_in_msh_01.3d.v4.msh create mode 100644 tests/grid/grids/grid_in_msh_01.3d_neg.v4.msh create mode 100644 tests/grid/grids/grid_in_msh_01.3da.v4.msh create mode 100644 tests/grid/grids/grid_in_msh_02_v4.msh diff --git a/tests/grid/grid_in_gmsh_01_v4.cc b/tests/grid/grid_in_gmsh_01_v4.cc new file mode 100644 index 000000000000..1caeb40fa525 --- /dev/null +++ b/tests/grid/grid_in_gmsh_01_v4.cc @@ -0,0 +1,136 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2004 - 2017 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. +// +// --------------------------------------------------------------------- + + + +// check whether we can read in with the gmsh format and obtain the same results +// for the GMSH-2 format and the GMSH-4 format + +#include +#include +#include +#include +#include + +#include "../tests.h" + + + +template +void +gmsh_grid(const char *name_v2, const char *name_v4) +{ + Triangulation tria_v2; + { + GridIn grid_in; + grid_in.attach_triangulation(tria_v2); + std::ifstream input_file(name_v2); + grid_in.read_msh(input_file); + } + + Triangulation tria_v4; + { + GridIn grid_in; + grid_in.attach_triangulation(tria_v4); + std::ifstream input_file(name_v4); + grid_in.read_msh(input_file); + } + + // The vertex index is different between the meshes parsed from the GMSH-2 and + // the GMSH-4 fil but all other information should match. + AssertThrow(tria_v2.n_active_cells() == tria_v4.n_active_cells(), + ExcInternalError()); + deallog << " " << tria_v2.n_active_cells() << " active cells" << std::endl; + + auto cell_v2 = tria_v2.begin_active(); + auto cell_v4 = tria_v4.begin_active(); + const auto end_v2 = tria_v2.end(); + for (; cell_v2 != end_v2; ++cell_v2, ++cell_v4) + { + AssertThrow(cell_v2->material_id() == cell_v4->material_id(), + ExcInternalError()); + for (unsigned int i = 0; i < GeometryInfo::vertices_per_cell; ++i) + { + AssertThrow((cell_v2->vertex(i) - cell_v4->vertex(i)).norm() < 1.e-10, + ExcInternalError()); + } + for (unsigned int i = 0; i < GeometryInfo::faces_per_cell; ++i) + { + AssertThrow(cell_v2->face(i)->boundary_id() == + cell_v4->face(i)->boundary_id(), + ExcInternalError()); + } + for (unsigned int i = 0; i < GeometryInfo::lines_per_cell; ++i) + { + AssertThrow(cell_v2->line(i)->boundary_id() == + cell_v4->line(i)->boundary_id(), + ExcInternalError()); + } + } + deallog << " OK" << std::endl; +} + + +int +main() +{ + initlog(); + + try + { + deallog << "/grid_in_msh_01.2d.v4.msh" << std::endl; + gmsh_grid<2>(SOURCE_DIR "/grids/grid_in_msh_01.2d.msh", + SOURCE_DIR "/grids/grid_in_msh_01.2d.v4.msh"); + deallog << "/grid_in_msh_01.2da.v4.msh" << std::endl; + gmsh_grid<2>(SOURCE_DIR "/grids/grid_in_msh_01.2da.msh", + SOURCE_DIR "/grids/grid_in_msh_01.2da.v4.msh"); + deallog << "/grid_in_msh_01.3d.v4.msh" << std::endl; + gmsh_grid<3>(SOURCE_DIR "/grids/grid_in_msh_01.3d.msh", + SOURCE_DIR "/grids/grid_in_msh_01.3d.v4.msh"); + deallog << "/grid_in_msh_01.3da.v4.msh" << std::endl; + gmsh_grid<3>(SOURCE_DIR "/grids/grid_in_msh_01.3da.msh", + SOURCE_DIR "/grids/grid_in_msh_01.3da.v4.msh"); + deallog << "/grid_in_msh_01.3d_neg.v4.msh" << std::endl; + gmsh_grid<3>(SOURCE_DIR "/grids/grid_in_msh_01.3d_neg.msh", + SOURCE_DIR "/grids/grid_in_msh_01.3d_neg.v4.msh"); + } + catch (std::exception &exc) + { + deallog << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + deallog << "Exception on processing: " << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + } + catch (...) + { + deallog << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + deallog << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + }; + + return 0; +} diff --git a/tests/grid/grid_in_gmsh_01_v4.output b/tests/grid/grid_in_gmsh_01_v4.output new file mode 100644 index 000000000000..861a472dcdf5 --- /dev/null +++ b/tests/grid/grid_in_gmsh_01_v4.output @@ -0,0 +1,16 @@ + +DEAL::/grid_in_msh_01.2d.v4.msh +DEAL:: 1 active cells +DEAL:: OK +DEAL::/grid_in_msh_01.2da.v4.msh +DEAL:: 360 active cells +DEAL:: OK +DEAL::/grid_in_msh_01.3d.v4.msh +DEAL:: 1 active cells +DEAL:: OK +DEAL::/grid_in_msh_01.3da.v4.msh +DEAL:: 200 active cells +DEAL:: OK +DEAL::/grid_in_msh_01.3d_neg.v4.msh +DEAL:: 1 active cells +DEAL:: OK diff --git a/tests/grid/grid_in_msh_02_13_v4.cc b/tests/grid/grid_in_msh_02_13_v4.cc new file mode 100644 index 000000000000..3c5c5c12e112 --- /dev/null +++ b/tests/grid/grid_in_msh_02_13_v4.cc @@ -0,0 +1,75 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2002 - 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. +// +// --------------------------------------------------------------------- + + +// in 1d, we have to read vertex information to set boundary +// indicators +// +// test case by Jan Strebel +// +// this is a variation of the grid_in_msh_02 testcase, but as in Jan's +// original code snippet, it uses GridIn<1,3> (which wasn't +// instantiated at the time) +// +// This is the same as grid_in_msh_02_13 but uses an input file in GMSH-4 +// format + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../tests.h" + +void +check_file() +{ + Triangulation<1, 3> tria; + GridIn<1, 3> gi; + gi.attach_triangulation(tria); + std::ifstream in(SOURCE_DIR "/../grid/grids/grid_in_msh_02_v4.msh"); + gi.read_msh(in); + + for (Triangulation<1, 3>::active_cell_iterator cell = tria.begin_active(); + cell != tria.end(); + ++cell) + { + for (unsigned int face = 0; face < 2; ++face) + { + if (cell->at_boundary(face)) + deallog << "vertex " << cell->face_index(face) + << " has boundary indicator " + << (int)cell->face(face)->boundary_id() << std::endl; + } + } +} + + +int +main() +{ + initlog(); + deallog << std::setprecision(2); + + check_file(); +} diff --git a/tests/grid/grid_in_msh_02_13_v4.output b/tests/grid/grid_in_msh_02_13_v4.output new file mode 100644 index 000000000000..2ebba38d85c8 --- /dev/null +++ b/tests/grid/grid_in_msh_02_13_v4.output @@ -0,0 +1,3 @@ + +DEAL::vertex 0 has boundary indicator 10 +DEAL::vertex 1 has boundary indicator 20 diff --git a/tests/grid/grid_in_msh_02_v4.cc b/tests/grid/grid_in_msh_02_v4.cc new file mode 100644 index 000000000000..4b75eec21fae --- /dev/null +++ b/tests/grid/grid_in_msh_02_v4.cc @@ -0,0 +1,70 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2002 - 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. +// +// --------------------------------------------------------------------- + + +// in 1d, we have to read vertex information to set boundary +// indicators +// +// test case by Jan Strebel +// +// This is the same as grid_in_msh_02 but uses an input file in GMSH-4 format + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../tests.h" + +void +check_file() +{ + Triangulation<1> tria; + GridIn<1> gi; + gi.attach_triangulation(tria); + std::ifstream in(SOURCE_DIR "/../grid/grids/grid_in_msh_02_v4.msh"); + gi.read_msh(in); + + for (Triangulation<1>::active_cell_iterator cell = tria.begin_active(); + cell != tria.end(); + ++cell) + { + for (unsigned int face = 0; face < 2; ++face) + { + if (cell->at_boundary(face)) + deallog << "vertex " << cell->face_index(face) + << " has boundary indicator " + << (int)cell->face(face)->boundary_id() << std::endl; + } + } +} + + +int +main() +{ + initlog(); + deallog << std::setprecision(2); + + check_file(); +} diff --git a/tests/grid/grid_in_msh_02_v4.output b/tests/grid/grid_in_msh_02_v4.output new file mode 100644 index 000000000000..2ebba38d85c8 --- /dev/null +++ b/tests/grid/grid_in_msh_02_v4.output @@ -0,0 +1,3 @@ + +DEAL::vertex 0 has boundary indicator 10 +DEAL::vertex 1 has boundary indicator 20 diff --git a/tests/grid/grid_in_msh_03_v4.cc b/tests/grid/grid_in_msh_03_v4.cc new file mode 100644 index 000000000000..b978ada7a9b7 --- /dev/null +++ b/tests/grid/grid_in_msh_03_v4.cc @@ -0,0 +1,69 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2002 - 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. +// +// --------------------------------------------------------------------- + + +// read a file in the MSH format used by the GMSH program. this +// particular mesh has type-15 cells (nodes) with more than one +// associated vertex. we failed to read the vertices +// +// This is the same as grid_in_msh_03 but uses an input file in GMSH-4 format + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../tests.h" + +template +void +check_file(const std::string name, typename GridIn::Format format) +{ + Triangulation tria; + GridIn gi; + gi.attach_triangulation(tria); + gi.read(name, format); + std::string source_dir(SOURCE_DIR "/"); + std::string relative_name(name.begin() + source_dir.size(), name.end()); + deallog << relative_name << '\t' << tria.n_vertices() << '\t' + << tria.n_cells() << std::endl; + + GridOut grid_out; + grid_out.write_gnuplot(tria, deallog.get_file_stream()); +} + +void +filename_resolution() +{ + check_file<2>(std::string(SOURCE_DIR "/grid_in_msh_03_v4/mesh"), + GridIn<2>::msh); +} + + +int +main() +{ + initlog(false, std::ios_base::fmtflags()); + deallog.get_file_stream() << std::setprecision(2); + + filename_resolution(); +} diff --git a/tests/grid/grid_in_msh_03_v4.output b/tests/grid/grid_in_msh_03_v4.output new file mode 100644 index 000000000000..0915ff09d954 --- /dev/null +++ b/tests/grid/grid_in_msh_03_v4.output @@ -0,0 +1,569 @@ + +DEAL::grid_in_msh_03_v4/mesh 100 81 +0 0 0 2 +2.2 0 0 2 +2.2 1.1 0 2 +0 1.1 0 2 +0 0 0 2 + + +0 1.1 0 2 +2.2 1.1 0 2 +2.2 2.2 0 2 +0 2.2 0 2 +0 1.1 0 2 + + +0 2.2 0 2 +2.2 2.2 0 2 +2.2 3.3 0 2 +0 3.3 0 2 +0 2.2 0 2 + + +0 3.3 0 2 +2.2 3.3 0 2 +2.2 4.4 0 2 +0 4.4 0 2 +0 3.3 0 2 + + +0 4.4 0 2 +2.2 4.4 0 2 +2.2 5.6 0 2 +0 5.6 0 2 +0 4.4 0 2 + + +0 5.6 0 2 +2.2 5.6 0 2 +2.2 6.7 0 2 +0 6.7 0 2 +0 5.6 0 2 + + +0 6.7 0 2 +2.2 6.7 0 2 +2.2 7.8 0 2 +0 7.8 0 2 +0 6.7 0 2 + + +0 7.8 0 2 +2.2 7.8 0 2 +2.2 8.9 0 2 +0 8.9 0 2 +0 7.8 0 2 + + +0 8.9 0 2 +2.2 8.9 0 2 +2.2 10 0 2 +0 10 0 2 +0 8.9 0 2 + + +2.2 0 0 2 +4.4 0 0 2 +4.4 1.1 0 2 +2.2 1.1 0 2 +2.2 0 0 2 + + +2.2 1.1 0 2 +4.4 1.1 0 2 +4.4 2.2 0 2 +2.2 2.2 0 2 +2.2 1.1 0 2 + + +2.2 2.2 0 2 +4.4 2.2 0 2 +4.4 3.3 0 2 +2.2 3.3 0 2 +2.2 2.2 0 2 + + +2.2 3.3 0 2 +4.4 3.3 0 2 +4.4 4.4 0 2 +2.2 4.4 0 2 +2.2 3.3 0 2 + + +2.2 4.4 0 2 +4.4 4.4 0 2 +4.4 5.6 0 2 +2.2 5.6 0 2 +2.2 4.4 0 2 + + +2.2 5.6 0 2 +4.4 5.6 0 2 +4.4 6.7 0 2 +2.2 6.7 0 2 +2.2 5.6 0 2 + + +2.2 6.7 0 2 +4.4 6.7 0 2 +4.4 7.8 0 2 +2.2 7.8 0 2 +2.2 6.7 0 2 + + +2.2 7.8 0 2 +4.4 7.8 0 2 +4.4 8.9 0 2 +2.2 8.9 0 2 +2.2 7.8 0 2 + + +2.2 8.9 0 2 +4.4 8.9 0 2 +4.4 10 0 2 +2.2 10 0 2 +2.2 8.9 0 2 + + +4.4 0 0 2 +6.7 0 0 2 +6.7 1.1 0 2 +4.4 1.1 0 2 +4.4 0 0 2 + + +4.4 1.1 0 2 +6.7 1.1 0 2 +6.7 2.2 0 2 +4.4 2.2 0 2 +4.4 1.1 0 2 + + +4.4 2.2 0 2 +6.7 2.2 0 2 +6.7 3.3 0 2 +4.4 3.3 0 2 +4.4 2.2 0 2 + + +4.4 3.3 0 2 +6.7 3.3 0 2 +6.7 4.4 0 2 +4.4 4.4 0 2 +4.4 3.3 0 2 + + +4.4 4.4 0 2 +6.7 4.4 0 2 +6.7 5.6 0 2 +4.4 5.6 0 2 +4.4 4.4 0 2 + + +4.4 5.6 0 2 +6.7 5.6 0 2 +6.7 6.7 0 2 +4.4 6.7 0 2 +4.4 5.6 0 2 + + +4.4 6.7 0 2 +6.7 6.7 0 2 +6.7 7.8 0 2 +4.4 7.8 0 2 +4.4 6.7 0 2 + + +4.4 7.8 0 2 +6.7 7.8 0 2 +6.7 8.9 0 2 +4.4 8.9 0 2 +4.4 7.8 0 2 + + +4.4 8.9 0 2 +6.7 8.9 0 2 +6.7 10 0 2 +4.4 10 0 2 +4.4 8.9 0 2 + + +6.7 0 0 2 +8.9 0 0 2 +8.9 1.1 0 2 +6.7 1.1 0 2 +6.7 0 0 2 + + +6.7 1.1 0 2 +8.9 1.1 0 2 +8.9 2.2 0 2 +6.7 2.2 0 2 +6.7 1.1 0 2 + + +6.7 2.2 0 2 +8.9 2.2 0 2 +8.9 3.3 0 2 +6.7 3.3 0 2 +6.7 2.2 0 2 + + +6.7 3.3 0 2 +8.9 3.3 0 2 +8.9 4.4 0 2 +6.7 4.4 0 2 +6.7 3.3 0 2 + + +6.7 4.4 0 2 +8.9 4.4 0 2 +8.9 5.6 0 2 +6.7 5.6 0 2 +6.7 4.4 0 2 + + +6.7 5.6 0 2 +8.9 5.6 0 2 +8.9 6.7 0 2 +6.7 6.7 0 2 +6.7 5.6 0 2 + + +6.7 6.7 0 2 +8.9 6.7 0 2 +8.9 7.8 0 2 +6.7 7.8 0 2 +6.7 6.7 0 2 + + +6.7 7.8 0 2 +8.9 7.8 0 2 +8.9 8.9 0 2 +6.7 8.9 0 2 +6.7 7.8 0 2 + + +6.7 8.9 0 2 +8.9 8.9 0 2 +8.9 10 0 2 +6.7 10 0 2 +6.7 8.9 0 2 + + +8.9 0 0 2 +11 0 0 2 +11 1.1 0 2 +8.9 1.1 0 2 +8.9 0 0 2 + + +8.9 1.1 0 2 +11 1.1 0 2 +11 2.2 0 2 +8.9 2.2 0 2 +8.9 1.1 0 2 + + +8.9 2.2 0 2 +11 2.2 0 2 +11 3.3 0 2 +8.9 3.3 0 2 +8.9 2.2 0 2 + + +8.9 3.3 0 2 +11 3.3 0 2 +11 4.4 0 2 +8.9 4.4 0 2 +8.9 3.3 0 2 + + +8.9 4.4 0 2 +11 4.4 0 2 +11 5.6 0 2 +8.9 5.6 0 2 +8.9 4.4 0 2 + + +8.9 5.6 0 2 +11 5.6 0 2 +11 6.7 0 2 +8.9 6.7 0 2 +8.9 5.6 0 2 + + +8.9 6.7 0 2 +11 6.7 0 2 +11 7.8 0 2 +8.9 7.8 0 2 +8.9 6.7 0 2 + + +8.9 7.8 0 2 +11 7.8 0 2 +11 8.9 0 2 +8.9 8.9 0 2 +8.9 7.8 0 2 + + +8.9 8.9 0 2 +11 8.9 0 2 +11 10 0 2 +8.9 10 0 2 +8.9 8.9 0 2 + + +11 0 0 2 +13 0 0 2 +13 1.1 0 2 +11 1.1 0 2 +11 0 0 2 + + +11 1.1 0 2 +13 1.1 0 2 +13 2.2 0 2 +11 2.2 0 2 +11 1.1 0 2 + + +11 2.2 0 2 +13 2.2 0 2 +13 3.3 0 2 +11 3.3 0 2 +11 2.2 0 2 + + +11 3.3 0 2 +13 3.3 0 2 +13 4.4 0 2 +11 4.4 0 2 +11 3.3 0 2 + + +11 4.4 0 2 +13 4.4 0 2 +13 5.6 0 2 +11 5.6 0 2 +11 4.4 0 2 + + +11 5.6 0 2 +13 5.6 0 2 +13 6.7 0 2 +11 6.7 0 2 +11 5.6 0 2 + + +11 6.7 0 2 +13 6.7 0 2 +13 7.8 0 2 +11 7.8 0 2 +11 6.7 0 2 + + +11 7.8 0 2 +13 7.8 0 2 +13 8.9 0 2 +11 8.9 0 2 +11 7.8 0 2 + + +11 8.9 0 2 +13 8.9 0 2 +13 10 0 2 +11 10 0 2 +11 8.9 0 2 + + +13 0 0 2 +16 0 0 2 +16 1.1 0 2 +13 1.1 0 2 +13 0 0 2 + + +13 1.1 0 2 +16 1.1 0 2 +16 2.2 0 2 +13 2.2 0 2 +13 1.1 0 2 + + +13 2.2 0 2 +16 2.2 0 2 +16 3.3 0 2 +13 3.3 0 2 +13 2.2 0 2 + + +13 3.3 0 2 +16 3.3 0 2 +16 4.4 0 2 +13 4.4 0 2 +13 3.3 0 2 + + +13 4.4 0 2 +16 4.4 0 2 +16 5.6 0 2 +13 5.6 0 2 +13 4.4 0 2 + + +13 5.6 0 2 +16 5.6 0 2 +16 6.7 0 2 +13 6.7 0 2 +13 5.6 0 2 + + +13 6.7 0 2 +16 6.7 0 2 +16 7.8 0 2 +13 7.8 0 2 +13 6.7 0 2 + + +13 7.8 0 2 +16 7.8 0 2 +16 8.9 0 2 +13 8.9 0 2 +13 7.8 0 2 + + +13 8.9 0 2 +16 8.9 0 2 +16 10 0 2 +13 10 0 2 +13 8.9 0 2 + + +16 0 0 2 +18 0 0 2 +18 1.1 0 2 +16 1.1 0 2 +16 0 0 2 + + +16 1.1 0 2 +18 1.1 0 2 +18 2.2 0 2 +16 2.2 0 2 +16 1.1 0 2 + + +16 2.2 0 2 +18 2.2 0 2 +18 3.3 0 2 +16 3.3 0 2 +16 2.2 0 2 + + +16 3.3 0 2 +18 3.3 0 2 +18 4.4 0 2 +16 4.4 0 2 +16 3.3 0 2 + + +16 4.4 0 2 +18 4.4 0 2 +18 5.6 0 2 +16 5.6 0 2 +16 4.4 0 2 + + +16 5.6 0 2 +18 5.6 0 2 +18 6.7 0 2 +16 6.7 0 2 +16 5.6 0 2 + + +16 6.7 0 2 +18 6.7 0 2 +18 7.8 0 2 +16 7.8 0 2 +16 6.7 0 2 + + +16 7.8 0 2 +18 7.8 0 2 +18 8.9 0 2 +16 8.9 0 2 +16 7.8 0 2 + + +16 8.9 0 2 +18 8.9 0 2 +18 10 0 2 +16 10 0 2 +16 8.9 0 2 + + +18 0 0 2 +20 0 0 2 +20 1.1 0 2 +18 1.1 0 2 +18 0 0 2 + + +18 1.1 0 2 +20 1.1 0 2 +20 2.2 0 2 +18 2.2 0 2 +18 1.1 0 2 + + +18 2.2 0 2 +20 2.2 0 2 +20 3.3 0 2 +18 3.3 0 2 +18 2.2 0 2 + + +18 3.3 0 2 +20 3.3 0 2 +20 4.4 0 2 +18 4.4 0 2 +18 3.3 0 2 + + +18 4.4 0 2 +20 4.4 0 2 +20 5.6 0 2 +18 5.6 0 2 +18 4.4 0 2 + + +18 5.6 0 2 +20 5.6 0 2 +20 6.7 0 2 +18 6.7 0 2 +18 5.6 0 2 + + +18 6.7 0 2 +20 6.7 0 2 +20 7.8 0 2 +18 7.8 0 2 +18 6.7 0 2 + + +18 7.8 0 2 +20 7.8 0 2 +20 8.9 0 2 +18 8.9 0 2 +18 7.8 0 2 + + +18 8.9 0 2 +20 8.9 0 2 +20 10 0 2 +18 10 0 2 +18 8.9 0 2 + + diff --git a/tests/grid/grid_in_msh_03_v4/mesh.msh b/tests/grid/grid_in_msh_03_v4/mesh.msh new file mode 100644 index 000000000000..fa7010402ad0 --- /dev/null +++ b/tests/grid/grid_in_msh_03_v4/mesh.msh @@ -0,0 +1,213 @@ +$MeshFormat +4 0 8 +$EndMeshFormat +$PhysicalNames +2 +-1 1 "1" +-1 2 "This surface" +$EndPhysicalNames +$Entities +0 1 1 0 +2 20 0 0 20 10 0 1 1 0 +1 0 0 0 20 10 0 1 2 0 +$EndEntities +$Nodes +2 100 +2 1 0 10 +2 20 0 0 +3 20 10 0 +13 20 1.111111111108906 0 +14 20 2.222222222217813 0 +15 20 3.33333333332769 0 +16 20 4.444444444437892 0 +17 20 5.555555555549327 0 +18 20 6.666666666661994 0 +19 20 7.777777777774663 0 +20 20 8.888888888887331 0 +1 2 0 90 +1 0 0 0 +4 0 10 0 +5 2.222222222217813 0 0 +6 4.444444444435626 0 0 +7 6.666666666655381 0 0 +8 8.888888888875783 0 0 +9 11.11111111109865 0 0 +10 13.33333333332399 0 0 +11 15.55555555554933 0 0 +12 17.77777777777466 0 0 +21 17.77777777777839 10 0 +22 15.55555555555679 10 0 +23 13.33333333333518 10 0 +24 11.11111111111358 10 0 +25 8.888888888891973 10 0 +26 6.666666666670369 10 0 +27 4.444444444448146 10 0 +28 2.222222222224073 10 0 +29 0 8.888888888889197 0 +30 0 7.777777777778395 0 +31 0 6.666666666667592 0 +32 0 5.555555555556789 0 +33 0 4.444444444445987 0 +34 0 3.333333333335184 0 +35 0 2.222222222224073 0 +36 0 1.111111111112036 0 +37 2.222222222218642 1.111111111111496 0 +38 2.222222222219417 2.222222222222914 0 +39 2.222222222220129 3.333333333334147 0 +40 2.222222222220792 4.444444444445237 0 +41 2.222222222221424 5.555555555556247 0 +42 2.222222222222049 6.666666666667213 0 +43 2.222222222222688 7.777777777778153 0 +44 2.222222222223361 8.888888888889079 0 +45 4.444444444437504 1.111111111111264 0 +46 4.444444444439081 2.222222222222499 0 +47 4.444444444440458 3.333333333333679 0 +48 4.444444444441706 4.444444444444804 0 +49 4.444444444442881 5.555555555555887 0 +50 4.444444444444038 6.666666666666938 0 +51 4.44444444444524 7.777777777777969 0 +52 4.444444444446567 8.888888888888987 0 +53 6.666666666657572 1.111111111111154 0 +54 6.666666666659543 2.2222222222223 0 +55 6.66666666666131 3.333333333333432 0 +56 6.666666666662916 4.444444444444548 0 +57 6.666666666664412 5.555555555555651 0 +58 6.66666666666585 6.666666666666745 0 +59 6.666666666667285 7.777777777777832 0 +60 6.666666666668773 8.888888888888916 0 +61 8.888888888878521 1.111111111111078 0 +62 8.888888888880823 2.22222222222216 0 +63 8.888888888882811 3.333333333333248 0 +64 8.888888888884571 4.444444444444345 0 +65 8.888888888886175 5.555555555555455 0 +66 8.888888888887676 6.666666666666577 0 +67 8.888888888889122 7.77777777777771 0 +68 8.888888888890547 8.888888888888852 0 +69 11.11111111110122 1.111111111110989 0 +70 11.11111111110336 2.222222222221994 0 +71 11.11111111110522 3.333333333333026 0 +72 11.11111111110686 4.444444444444096 0 +73 11.11111111110835 5.55555555555521 0 +74 11.11111111110973 6.666666666666364 0 +75 11.11111111111104 7.777777777777554 0 +76 11.11111111111232 8.88888888888877 0 +77 13.33333333332558 1.11111111111084 0 +78 13.33333333332708 2.222222222221715 0 +79 13.33333333332847 3.333333333332654 0 +80 13.33333333332975 4.444444444443679 0 +81 13.33333333333094 5.555555555554799 0 +82 13.33333333333206 6.666666666666009 0 +83 13.33333333333313 7.777777777777295 0 +84 13.33333333333417 8.888888888888633 0 +85 15.5555555555503 1.111111111110555 0 +86 15.55555555555125 2.22222222222118 0 +87 15.55555555555216 3.333333333331943 0 +88 15.55555555555302 4.444444444442883 0 +89 15.55555555555383 5.555555555554025 0 +90 15.55555555555461 6.666666666665354 0 +91 15.55555555555535 7.777777777776826 0 +92 15.55555555555608 8.88888888888839 0 +93 17.77777777777513 1.111111111109987 0 +94 17.77777777777559 2.222222222220101 0 +95 17.77777777777604 3.333333333330518 0 +96 17.77777777777647 4.444444444441285 0 +97 17.77777777777688 5.555555555552501 0 +98 17.77777777777728 6.66666666666413 0 +99 17.77777777777766 7.777777777775988 0 +100 17.77777777777803 8.888888888887967 0 +$EndNodes +$Elements +2 90 +2 1 1 9 +1 2 13 +2 13 14 +3 14 15 +4 15 16 +5 16 17 +6 17 18 +7 18 19 +8 19 20 +9 20 3 +1 2 3 81 +10 1 5 37 36 +11 36 37 38 35 +12 35 38 39 34 +13 34 39 40 33 +14 33 40 41 32 +15 32 41 42 31 +16 31 42 43 30 +17 30 43 44 29 +18 29 44 28 4 +19 5 6 45 37 +20 37 45 46 38 +21 38 46 47 39 +22 39 47 48 40 +23 40 48 49 41 +24 41 49 50 42 +25 42 50 51 43 +26 43 51 52 44 +27 44 52 27 28 +28 6 7 53 45 +29 45 53 54 46 +30 46 54 55 47 +31 47 55 56 48 +32 48 56 57 49 +33 49 57 58 50 +34 50 58 59 51 +35 51 59 60 52 +36 52 60 26 27 +37 7 8 61 53 +38 53 61 62 54 +39 54 62 63 55 +40 55 63 64 56 +41 56 64 65 57 +42 57 65 66 58 +43 58 66 67 59 +44 59 67 68 60 +45 60 68 25 26 +46 8 9 69 61 +47 61 69 70 62 +48 62 70 71 63 +49 63 71 72 64 +50 64 72 73 65 +51 65 73 74 66 +52 66 74 75 67 +53 67 75 76 68 +54 68 76 24 25 +55 9 10 77 69 +56 69 77 78 70 +57 70 78 79 71 +58 71 79 80 72 +59 72 80 81 73 +60 73 81 82 74 +61 74 82 83 75 +62 75 83 84 76 +63 76 84 23 24 +64 10 11 85 77 +65 77 85 86 78 +66 78 86 87 79 +67 79 87 88 80 +68 80 88 89 81 +69 81 89 90 82 +70 82 90 91 83 +71 83 91 92 84 +72 84 92 22 23 +73 11 12 93 85 +74 85 93 94 86 +75 86 94 95 87 +76 87 95 96 88 +77 88 96 97 89 +78 89 97 98 90 +79 90 98 99 91 +80 91 99 100 92 +81 92 100 21 22 +82 12 2 13 93 +83 93 13 14 94 +84 94 14 15 95 +85 95 15 16 96 +86 96 16 17 97 +87 97 17 18 98 +88 98 18 19 99 +89 99 19 20 100 +90 100 20 3 21 +$EndElements diff --git a/tests/grid/grid_in_msh_v4.cc b/tests/grid/grid_in_msh_v4.cc new file mode 100644 index 000000000000..a1fcb1dbedce --- /dev/null +++ b/tests/grid/grid_in_msh_v4.cc @@ -0,0 +1,63 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2002 - 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. +// +// --------------------------------------------------------------------- + + +// read a file in the MSH format used by the GMSH program +// +// This is the same as grid_in_msh but uses an input file in GMSH-4 format + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../tests.h" + +template +void +check_file(const std::string name, typename GridIn::Format format) +{ + Triangulation tria; + GridIn gi; + gi.attach_triangulation(tria); + gi.read(name, format); + deallog << '\t' << tria.n_vertices() << '\t' << tria.n_cells() << std::endl; + + GridOut grid_out; + grid_out.write_gnuplot(tria, deallog.get_file_stream()); +} + +void +filename_resolution() +{ + check_file<2>(std::string(SOURCE_DIR "/grid_in_msh_v4/mesh"), GridIn<2>::msh); +} + + +int +main() +{ + initlog(); + deallog.get_file_stream() << std::setprecision(2); + + filename_resolution(); +} diff --git a/tests/grid/grid_in_msh_v4.output b/tests/grid/grid_in_msh_v4.output new file mode 100644 index 000000000000..e6cb7dc1fc97 --- /dev/null +++ b/tests/grid/grid_in_msh_v4.output @@ -0,0 +1,1262 @@ + +DEAL: 216 180 +0.50 0.30 0 9 +0.46 0.24 0 9 +0.50 0.17 0 9 +0.54 0.24 0 9 +0.50 0.30 0 9 + + +0.41 0.18 0 9 +0.46 0.091 0 9 +0.50 0.17 0 9 +0.46 0.24 0 9 +0.41 0.18 0 9 + + +0.50 0.0 0 9 +0.54 0.090 0 9 +0.50 0.17 0 9 +0.46 0.091 0 9 +0.50 0.0 0 9 + + +0.58 0.18 0 9 +0.54 0.24 0 9 +0.50 0.17 0 9 +0.54 0.090 0 9 +0.58 0.18 0 9 + + +0.30 0.50 0 9 +0.24 0.54 0 9 +0.17 0.50 0 9 +0.24 0.46 0 9 +0.30 0.50 0 9 + + +0.18 0.58 0 9 +0.090 0.54 0 9 +0.17 0.50 0 9 +0.24 0.54 0 9 +0.18 0.58 0 9 + + +0.0 0.50 0 9 +0.091 0.46 0 9 +0.17 0.50 0 9 +0.090 0.54 0 9 +0.0 0.50 0 9 + + +0.18 0.42 0 9 +0.24 0.46 0 9 +0.17 0.50 0 9 +0.091 0.46 0 9 +0.18 0.42 0 9 + + +0.50 0.70 0 9 +0.54 0.76 0 9 +0.50 0.83 0 9 +0.46 0.76 0 9 +0.50 0.70 0 9 + + +0.58 0.82 0 9 +0.54 0.91 0 9 +0.50 0.83 0 9 +0.54 0.76 0 9 +0.58 0.82 0 9 + + +0.50 1.0 0 9 +0.46 0.91 0 9 +0.50 0.83 0 9 +0.54 0.91 0 9 +0.50 1.0 0 9 + + +0.42 0.82 0 9 +0.46 0.76 0 9 +0.50 0.83 0 9 +0.46 0.91 0 9 +0.42 0.82 0 9 + + +0.70 0.50 0 9 +0.76 0.46 0 9 +0.83 0.50 0 9 +0.76 0.54 0 9 +0.70 0.50 0 9 + + +0.82 0.41 0 9 +0.91 0.46 0 9 +0.83 0.50 0 9 +0.76 0.46 0 9 +0.82 0.41 0 9 + + +1.0 0.50 0 9 +0.91 0.54 0 9 +0.83 0.50 0 9 +0.91 0.46 0 9 +1.0 0.50 0 9 + + +0.82 0.58 0 9 +0.76 0.54 0 9 +0.83 0.50 0 9 +0.91 0.54 0 9 +0.82 0.58 0 9 + + +0.85 0.30 0 9 +0.83 0.36 0 9 +0.77 0.35 0 9 +0.79 0.29 0 9 +0.85 0.30 0 9 + + +0.82 0.41 0 9 +0.75 0.41 0 9 +0.77 0.35 0 9 +0.83 0.36 0 9 +0.82 0.41 0 9 + + +0.67 0.40 0 9 +0.70 0.34 0 9 +0.77 0.35 0 9 +0.75 0.41 0 9 +0.67 0.40 0 9 + + +0.72 0.28 0 9 +0.79 0.29 0 9 +0.77 0.35 0 9 +0.70 0.34 0 9 +0.72 0.28 0 9 + + +0.85 0.70 0 9 +0.79 0.71 0 9 +0.77 0.65 0 9 +0.83 0.64 0 9 +0.85 0.70 0 9 + + +0.72 0.72 0 9 +0.70 0.66 0 9 +0.77 0.65 0 9 +0.79 0.71 0 9 +0.72 0.72 0 9 + + +0.67 0.60 0 9 +0.75 0.59 0 9 +0.77 0.65 0 9 +0.70 0.66 0 9 +0.67 0.60 0 9 + + +0.82 0.58 0 9 +0.83 0.64 0 9 +0.77 0.65 0 9 +0.75 0.59 0 9 +0.82 0.58 0 9 + + +0.15 0.70 0 9 +0.17 0.64 0 9 +0.23 0.65 0 9 +0.21 0.71 0 9 +0.15 0.70 0 9 + + +0.18 0.58 0 9 +0.25 0.59 0 9 +0.23 0.65 0 9 +0.17 0.64 0 9 +0.18 0.58 0 9 + + +0.33 0.60 0 9 +0.30 0.66 0 9 +0.23 0.65 0 9 +0.25 0.59 0 9 +0.33 0.60 0 9 + + +0.28 0.72 0 9 +0.21 0.71 0 9 +0.23 0.65 0 9 +0.30 0.66 0 9 +0.28 0.72 0 9 + + +0.70 0.15 0 9 +0.71 0.21 0 9 +0.65 0.23 0 9 +0.64 0.17 0 9 +0.70 0.15 0 9 + + +0.72 0.28 0 9 +0.66 0.30 0 9 +0.65 0.23 0 9 +0.71 0.21 0 9 +0.72 0.28 0 9 + + +0.60 0.33 0 9 +0.59 0.25 0 9 +0.65 0.23 0 9 +0.66 0.30 0 9 +0.60 0.33 0 9 + + +0.58 0.18 0 9 +0.64 0.17 0 9 +0.65 0.23 0 9 +0.59 0.25 0 9 +0.58 0.18 0 9 + + +0.70 0.85 0 9 +0.64 0.83 0 9 +0.65 0.77 0 9 +0.71 0.79 0 9 +0.70 0.85 0 9 + + +0.58 0.82 0 9 +0.59 0.75 0 9 +0.65 0.77 0 9 +0.64 0.83 0 9 +0.58 0.82 0 9 + + +0.60 0.67 0 9 +0.66 0.70 0 9 +0.65 0.77 0 9 +0.59 0.75 0 9 +0.60 0.67 0 9 + + +0.72 0.72 0 9 +0.71 0.79 0 9 +0.65 0.77 0 9 +0.66 0.70 0 9 +0.72 0.72 0 9 + + +0.30 0.15 0 9 +0.36 0.17 0 9 +0.35 0.23 0 9 +0.29 0.21 0 9 +0.30 0.15 0 9 + + +0.41 0.18 0 9 +0.41 0.25 0 9 +0.35 0.23 0 9 +0.36 0.17 0 9 +0.41 0.18 0 9 + + +0.40 0.33 0 9 +0.34 0.30 0 9 +0.35 0.23 0 9 +0.41 0.25 0 9 +0.40 0.33 0 9 + + +0.28 0.28 0 9 +0.29 0.21 0 9 +0.35 0.23 0 9 +0.34 0.30 0 9 +0.28 0.28 0 9 + + +0.15 0.30 0 9 +0.21 0.29 0 9 +0.23 0.35 0 9 +0.17 0.36 0 9 +0.15 0.30 0 9 + + +0.28 0.28 0 9 +0.30 0.34 0 9 +0.23 0.35 0 9 +0.21 0.29 0 9 +0.28 0.28 0 9 + + +0.33 0.40 0 9 +0.25 0.41 0 9 +0.23 0.35 0 9 +0.30 0.34 0 9 +0.33 0.40 0 9 + + +0.18 0.42 0 9 +0.17 0.36 0 9 +0.23 0.35 0 9 +0.25 0.41 0 9 +0.18 0.42 0 9 + + +0.30 0.85 0 9 +0.29 0.79 0 9 +0.35 0.77 0 9 +0.36 0.83 0 9 +0.30 0.85 0 9 + + +0.28 0.72 0 9 +0.34 0.70 0 9 +0.35 0.77 0 9 +0.29 0.79 0 9 +0.28 0.72 0 9 + + +0.40 0.67 0 9 +0.41 0.75 0 9 +0.35 0.77 0 9 +0.34 0.70 0 9 +0.40 0.67 0 9 + + +0.42 0.82 0 9 +0.36 0.83 0 9 +0.35 0.77 0 9 +0.41 0.75 0 9 +0.42 0.82 0 9 + + +1.0 0.83 0 9 +1.0 0.92 0 9 +0.92 0.92 0 9 +0.92 0.84 0 9 +1.0 0.83 0 9 + + +1.0 1.0 0 9 +0.92 1.0 0 9 +0.92 0.92 0 9 +1.0 0.92 0 9 +1.0 1.0 0 9 + + +0.83 1.0 0 9 +0.84 0.92 0 9 +0.92 0.92 0 9 +0.92 1.0 0 9 +0.83 1.0 0 9 + + +0.85 0.85 0 9 +0.92 0.84 0 9 +0.92 0.92 0 9 +0.84 0.92 0 9 +0.85 0.85 0 9 + + +0.17 1.0 0 9 +0.083 1.0 0 9 +0.079 0.92 0 9 +0.16 0.92 0 9 +0.17 1.0 0 9 + + +0.0 1.0 0 9 +0.0 0.92 0 9 +0.079 0.92 0 9 +0.083 1.0 0 9 +0.0 1.0 0 9 + + +0.0 0.83 0 9 +0.075 0.84 0 9 +0.079 0.92 0 9 +0.0 0.92 0 9 +0.0 0.83 0 9 + + +0.15 0.85 0 9 +0.16 0.92 0 9 +0.079 0.92 0 9 +0.075 0.84 0 9 +0.15 0.85 0 9 + + +1.0 0.17 0 9 +0.92 0.16 0 9 +0.92 0.079 0 9 +1.0 0.083 0 9 +1.0 0.17 0 9 + + +0.85 0.15 0 9 +0.84 0.075 0 9 +0.92 0.079 0 9 +0.92 0.16 0 9 +0.85 0.15 0 9 + + +0.83 0.0 0 9 +0.92 0.0 0 9 +0.92 0.079 0 9 +0.84 0.075 0 9 +0.83 0.0 0 9 + + +1.0 0.0 0 9 +1.0 0.083 0 9 +0.92 0.079 0 9 +0.92 0.0 0 9 +1.0 0.0 0 9 + + +0.30 0.85 0 9 +0.36 0.83 0 9 +0.39 0.92 0 9 +0.32 0.92 0 9 +0.30 0.85 0 9 + + +0.42 0.82 0 9 +0.46 0.91 0 9 +0.39 0.92 0 9 +0.36 0.83 0 9 +0.42 0.82 0 9 + + +0.50 1.0 0 9 +0.42 1.0 0 9 +0.39 0.92 0 9 +0.46 0.91 0 9 +0.50 1.0 0 9 + + +0.33 1.0 0 9 +0.32 0.92 0 9 +0.39 0.92 0 9 +0.42 1.0 0 9 +0.33 1.0 0 9 + + +0.85 0.30 0 9 +0.92 0.31 0 9 +0.92 0.39 0 9 +0.83 0.36 0 9 +0.85 0.30 0 9 + + +1.0 0.33 0 9 +1.0 0.42 0 9 +0.92 0.39 0 9 +0.92 0.31 0 9 +1.0 0.33 0 9 + + +1.0 0.50 0 9 +0.91 0.46 0 9 +0.92 0.39 0 9 +1.0 0.42 0 9 +1.0 0.50 0 9 + + +0.82 0.41 0 9 +0.83 0.36 0 9 +0.92 0.39 0 9 +0.91 0.46 0 9 +0.82 0.41 0 9 + + +0.85 0.70 0 9 +0.83 0.64 0 9 +0.92 0.61 0 9 +0.92 0.68 0 9 +0.85 0.70 0 9 + + +0.82 0.58 0 9 +0.91 0.54 0 9 +0.92 0.61 0 9 +0.83 0.64 0 9 +0.82 0.58 0 9 + + +1.0 0.50 0 9 +1.0 0.58 0 9 +0.92 0.61 0 9 +0.91 0.54 0 9 +1.0 0.50 0 9 + + +1.0 0.67 0 9 +0.92 0.68 0 9 +0.92 0.61 0 9 +1.0 0.58 0 9 +1.0 0.67 0 9 + + +0.70 0.15 0 9 +0.64 0.17 0 9 +0.61 0.083 0 9 +0.68 0.077 0 9 +0.70 0.15 0 9 + + +0.58 0.18 0 9 +0.54 0.090 0 9 +0.61 0.083 0 9 +0.64 0.17 0 9 +0.58 0.18 0 9 + + +0.50 0.0 0 9 +0.58 0.0 0 9 +0.61 0.083 0 9 +0.54 0.090 0 9 +0.50 0.0 0 9 + + +0.67 0.0 0 9 +0.68 0.077 0 9 +0.61 0.083 0 9 +0.58 0.0 0 9 +0.67 0.0 0 9 + + +0.70 0.85 0 9 +0.68 0.92 0 9 +0.61 0.92 0 9 +0.64 0.83 0 9 +0.70 0.85 0 9 + + +0.67 1.0 0 9 +0.58 1.0 0 9 +0.61 0.92 0 9 +0.68 0.92 0 9 +0.67 1.0 0 9 + + +0.50 1.0 0 9 +0.54 0.91 0 9 +0.61 0.92 0 9 +0.58 1.0 0 9 +0.50 1.0 0 9 + + +0.58 0.82 0 9 +0.64 0.83 0 9 +0.61 0.92 0 9 +0.54 0.91 0 9 +0.58 0.82 0 9 + + +0.15 0.30 0 9 +0.17 0.36 0 9 +0.084 0.39 0 9 +0.077 0.32 0 9 +0.15 0.30 0 9 + + +0.18 0.42 0 9 +0.091 0.46 0 9 +0.084 0.39 0 9 +0.17 0.36 0 9 +0.18 0.42 0 9 + + +0.0 0.50 0 9 +0.0 0.42 0 9 +0.084 0.39 0 9 +0.091 0.46 0 9 +0.0 0.50 0 9 + + +0.0 0.33 0 9 +0.077 0.32 0 9 +0.084 0.39 0 9 +0.0 0.42 0 9 +0.0 0.33 0 9 + + +0.17 0.0 0 9 +0.16 0.075 0 9 +0.079 0.079 0 9 +0.083 0.0 0 9 +0.17 0.0 0 9 + + +0.15 0.15 0 9 +0.075 0.16 0 9 +0.079 0.079 0 9 +0.16 0.075 0 9 +0.15 0.15 0 9 + + +0.0 0.17 0 9 +0.0 0.083 0 9 +0.079 0.079 0 9 +0.075 0.16 0 9 +0.0 0.17 0 9 + + +0.0 0.0 0 9 +0.083 0.0 0 9 +0.079 0.079 0 9 +0.0 0.083 0 9 +0.0 0.0 0 9 + + +0.15 0.70 0 9 +0.076 0.68 0 9 +0.083 0.61 0 9 +0.17 0.64 0 9 +0.15 0.70 0 9 + + +0.0 0.67 0 9 +0.0 0.58 0 9 +0.083 0.61 0 9 +0.076 0.68 0 9 +0.0 0.67 0 9 + + +0.0 0.50 0 9 +0.090 0.54 0 9 +0.083 0.61 0 9 +0.0 0.58 0 9 +0.0 0.50 0 9 + + +0.18 0.58 0 9 +0.17 0.64 0 9 +0.083 0.61 0 9 +0.090 0.54 0 9 +0.18 0.58 0 9 + + +0.30 0.15 0 9 +0.31 0.076 0 9 +0.39 0.083 0 9 +0.36 0.17 0 9 +0.30 0.15 0 9 + + +0.33 0.0 0 9 +0.42 0.0 0 9 +0.39 0.083 0 9 +0.31 0.076 0 9 +0.33 0.0 0 9 + + +0.50 0.0 0 9 +0.46 0.091 0 9 +0.39 0.083 0 9 +0.42 0.0 0 9 +0.50 0.0 0 9 + + +0.41 0.18 0 9 +0.36 0.17 0 9 +0.39 0.083 0 9 +0.46 0.091 0 9 +0.41 0.18 0 9 + + +0.85 0.15 0 9 +0.92 0.16 0 9 +0.92 0.24 0 9 +0.85 0.22 0 9 +0.85 0.15 0 9 + + +1.0 0.17 0 9 +1.0 0.25 0 9 +0.92 0.24 0 9 +0.92 0.16 0 9 +1.0 0.17 0 9 + + +1.0 0.33 0 9 +0.92 0.31 0 9 +0.92 0.24 0 9 +1.0 0.25 0 9 +1.0 0.33 0 9 + + +0.85 0.30 0 9 +0.85 0.22 0 9 +0.92 0.24 0 9 +0.92 0.31 0 9 +0.85 0.30 0 9 + + +0.85 0.85 0 9 +0.85 0.78 0 9 +0.92 0.76 0 9 +0.92 0.84 0 9 +0.85 0.85 0 9 + + +0.85 0.70 0 9 +0.92 0.68 0 9 +0.92 0.76 0 9 +0.85 0.78 0 9 +0.85 0.70 0 9 + + +1.0 0.67 0 9 +1.0 0.75 0 9 +0.92 0.76 0 9 +0.92 0.68 0 9 +1.0 0.67 0 9 + + +1.0 0.83 0 9 +0.92 0.84 0 9 +0.92 0.76 0 9 +1.0 0.75 0 9 +1.0 0.83 0 9 + + +0.15 0.85 0 9 +0.075 0.84 0 9 +0.076 0.76 0 9 +0.15 0.78 0 9 +0.15 0.85 0 9 + + +0.0 0.83 0 9 +0.0 0.75 0 9 +0.076 0.76 0 9 +0.075 0.84 0 9 +0.0 0.83 0 9 + + +0.0 0.67 0 9 +0.076 0.68 0 9 +0.076 0.76 0 9 +0.0 0.75 0 9 +0.0 0.67 0 9 + + +0.15 0.70 0 9 +0.15 0.78 0 9 +0.076 0.76 0 9 +0.076 0.68 0 9 +0.15 0.70 0 9 + + +0.15 0.15 0 9 +0.16 0.075 0 9 +0.24 0.076 0 9 +0.22 0.15 0 9 +0.15 0.15 0 9 + + +0.17 0.0 0 9 +0.25 0.0 0 9 +0.24 0.076 0 9 +0.16 0.075 0 9 +0.17 0.0 0 9 + + +0.33 0.0 0 9 +0.31 0.076 0 9 +0.24 0.076 0 9 +0.25 0.0 0 9 +0.33 0.0 0 9 + + +0.30 0.15 0 9 +0.22 0.15 0 9 +0.24 0.076 0 9 +0.31 0.076 0 9 +0.30 0.15 0 9 + + +0.85 0.85 0 9 +0.84 0.92 0 9 +0.76 0.92 0 9 +0.78 0.85 0 9 +0.85 0.85 0 9 + + +0.83 1.0 0 9 +0.75 1.0 0 9 +0.76 0.92 0 9 +0.84 0.92 0 9 +0.83 1.0 0 9 + + +0.67 1.0 0 9 +0.68 0.92 0 9 +0.76 0.92 0 9 +0.75 1.0 0 9 +0.67 1.0 0 9 + + +0.70 0.85 0 9 +0.78 0.85 0 9 +0.76 0.92 0 9 +0.68 0.92 0 9 +0.70 0.85 0 9 + + +0.70 0.85 0 9 +0.71 0.79 0 9 +0.78 0.78 0 9 +0.78 0.85 0 9 +0.70 0.85 0 9 + + +0.72 0.72 0 9 +0.79 0.71 0 9 +0.78 0.78 0 9 +0.71 0.79 0 9 +0.72 0.72 0 9 + + +0.85 0.70 0 9 +0.85 0.78 0 9 +0.78 0.78 0 9 +0.79 0.71 0 9 +0.85 0.70 0 9 + + +0.85 0.85 0 9 +0.78 0.85 0 9 +0.78 0.78 0 9 +0.85 0.78 0 9 +0.85 0.85 0 9 + + +0.85 0.15 0 9 +0.78 0.15 0 9 +0.76 0.076 0 9 +0.84 0.075 0 9 +0.85 0.15 0 9 + + +0.70 0.15 0 9 +0.68 0.077 0 9 +0.76 0.076 0 9 +0.78 0.15 0 9 +0.70 0.15 0 9 + + +0.67 0.0 0 9 +0.75 0.0 0 9 +0.76 0.076 0 9 +0.68 0.077 0 9 +0.67 0.0 0 9 + + +0.83 0.0 0 9 +0.84 0.075 0 9 +0.76 0.076 0 9 +0.75 0.0 0 9 +0.83 0.0 0 9 + + +0.70 0.15 0 9 +0.78 0.15 0 9 +0.78 0.22 0 9 +0.71 0.21 0 9 +0.70 0.15 0 9 + + +0.85 0.15 0 9 +0.85 0.22 0 9 +0.78 0.22 0 9 +0.78 0.15 0 9 +0.85 0.15 0 9 + + +0.85 0.30 0 9 +0.79 0.29 0 9 +0.78 0.22 0 9 +0.85 0.22 0 9 +0.85 0.30 0 9 + + +0.72 0.28 0 9 +0.71 0.21 0 9 +0.78 0.22 0 9 +0.79 0.29 0 9 +0.72 0.28 0 9 + + +0.15 0.85 0 9 +0.22 0.85 0 9 +0.24 0.92 0 9 +0.16 0.92 0 9 +0.15 0.85 0 9 + + +0.30 0.85 0 9 +0.32 0.92 0 9 +0.24 0.92 0 9 +0.22 0.85 0 9 +0.30 0.85 0 9 + + +0.33 1.0 0 9 +0.25 1.0 0 9 +0.24 0.92 0 9 +0.32 0.92 0 9 +0.33 1.0 0 9 + + +0.17 1.0 0 9 +0.16 0.92 0 9 +0.24 0.92 0 9 +0.25 1.0 0 9 +0.17 1.0 0 9 + + +0.30 0.85 0 9 +0.22 0.85 0 9 +0.22 0.78 0 9 +0.29 0.79 0 9 +0.30 0.85 0 9 + + +0.15 0.85 0 9 +0.15 0.78 0 9 +0.22 0.78 0 9 +0.22 0.85 0 9 +0.15 0.85 0 9 + + +0.15 0.70 0 9 +0.21 0.71 0 9 +0.22 0.78 0 9 +0.15 0.78 0 9 +0.15 0.70 0 9 + + +0.28 0.72 0 9 +0.29 0.79 0 9 +0.22 0.78 0 9 +0.21 0.71 0 9 +0.28 0.72 0 9 + + +0.15 0.30 0 9 +0.15 0.22 0 9 +0.22 0.22 0 9 +0.21 0.29 0 9 +0.15 0.30 0 9 + + +0.15 0.15 0 9 +0.22 0.15 0 9 +0.22 0.22 0 9 +0.15 0.22 0 9 +0.15 0.15 0 9 + + +0.30 0.15 0 9 +0.29 0.21 0 9 +0.22 0.22 0 9 +0.22 0.15 0 9 +0.30 0.15 0 9 + + +0.28 0.28 0 9 +0.21 0.29 0 9 +0.22 0.22 0 9 +0.29 0.21 0 9 +0.28 0.28 0 9 + + +0.15 0.15 0 9 +0.15 0.22 0 9 +0.076 0.24 0 9 +0.075 0.16 0 9 +0.15 0.15 0 9 + + +0.15 0.30 0 9 +0.077 0.32 0 9 +0.076 0.24 0 9 +0.15 0.22 0 9 +0.15 0.30 0 9 + + +0.0 0.33 0 9 +0.0 0.25 0 9 +0.076 0.24 0 9 +0.077 0.32 0 9 +0.0 0.33 0 9 + + +0.0 0.17 0 9 +0.075 0.16 0 9 +0.076 0.24 0 9 +0.0 0.25 0 9 +0.0 0.17 0 9 + + +0.60 0.33 0 9 +0.66 0.30 0 9 +0.67 0.33 0 9 +0.64 0.36 0 9 +0.60 0.33 0 9 + + +0.72 0.28 0 9 +0.70 0.34 0 9 +0.67 0.33 0 9 +0.66 0.30 0 9 +0.72 0.28 0 9 + + +0.67 0.40 0 9 +0.64 0.36 0 9 +0.67 0.33 0 9 +0.70 0.34 0 9 +0.67 0.40 0 9 + + +0.40 0.67 0 9 +0.34 0.70 0 9 +0.33 0.67 0 9 +0.36 0.64 0 9 +0.40 0.67 0 9 + + +0.28 0.72 0 9 +0.30 0.66 0 9 +0.33 0.67 0 9 +0.34 0.70 0 9 +0.28 0.72 0 9 + + +0.33 0.60 0 9 +0.36 0.64 0 9 +0.33 0.67 0 9 +0.30 0.66 0 9 +0.33 0.60 0 9 + + +0.67 0.60 0 9 +0.70 0.66 0 9 +0.67 0.67 0 9 +0.64 0.64 0 9 +0.67 0.60 0 9 + + +0.72 0.72 0 9 +0.66 0.70 0 9 +0.67 0.67 0 9 +0.70 0.66 0 9 +0.72 0.72 0 9 + + +0.60 0.67 0 9 +0.64 0.64 0 9 +0.67 0.67 0 9 +0.66 0.70 0 9 +0.60 0.67 0 9 + + +0.33 0.40 0 9 +0.30 0.34 0 9 +0.33 0.33 0 9 +0.36 0.36 0 9 +0.33 0.40 0 9 + + +0.28 0.28 0 9 +0.34 0.30 0 9 +0.33 0.33 0 9 +0.30 0.34 0 9 +0.28 0.28 0 9 + + +0.40 0.33 0 9 +0.36 0.36 0 9 +0.33 0.33 0 9 +0.34 0.30 0 9 +0.40 0.33 0 9 + + +0.67 0.40 0 9 +0.75 0.41 0 9 +0.73 0.44 0 9 +0.69 0.45 0 9 +0.67 0.40 0 9 + + +0.82 0.41 0 9 +0.76 0.46 0 9 +0.73 0.44 0 9 +0.75 0.41 0 9 +0.82 0.41 0 9 + + +0.70 0.50 0 9 +0.69 0.45 0 9 +0.73 0.44 0 9 +0.76 0.46 0 9 +0.70 0.50 0 9 + + +0.70 0.50 0 9 +0.76 0.54 0 9 +0.73 0.56 0 9 +0.69 0.55 0 9 +0.70 0.50 0 9 + + +0.82 0.58 0 9 +0.75 0.59 0 9 +0.73 0.56 0 9 +0.76 0.54 0 9 +0.82 0.58 0 9 + + +0.67 0.60 0 9 +0.69 0.55 0 9 +0.73 0.56 0 9 +0.75 0.59 0 9 +0.67 0.60 0 9 + + +0.60 0.67 0 9 +0.59 0.75 0 9 +0.56 0.73 0 9 +0.55 0.69 0 9 +0.60 0.67 0 9 + + +0.58 0.82 0 9 +0.54 0.76 0 9 +0.56 0.73 0 9 +0.59 0.75 0 9 +0.58 0.82 0 9 + + +0.50 0.70 0 9 +0.55 0.69 0 9 +0.56 0.73 0 9 +0.54 0.76 0 9 +0.50 0.70 0 9 + + +0.50 0.70 0 9 +0.46 0.76 0 9 +0.44 0.73 0 9 +0.45 0.69 0 9 +0.50 0.70 0 9 + + +0.42 0.82 0 9 +0.41 0.75 0 9 +0.44 0.73 0 9 +0.46 0.76 0 9 +0.42 0.82 0 9 + + +0.40 0.67 0 9 +0.45 0.69 0 9 +0.44 0.73 0 9 +0.41 0.75 0 9 +0.40 0.67 0 9 + + +0.50 0.30 0 9 +0.54 0.24 0 9 +0.56 0.27 0 9 +0.55 0.31 0 9 +0.50 0.30 0 9 + + +0.58 0.18 0 9 +0.59 0.25 0 9 +0.56 0.27 0 9 +0.54 0.24 0 9 +0.58 0.18 0 9 + + +0.60 0.33 0 9 +0.55 0.31 0 9 +0.56 0.27 0 9 +0.59 0.25 0 9 +0.60 0.33 0 9 + + +0.33 0.60 0 9 +0.25 0.59 0 9 +0.27 0.56 0 9 +0.31 0.55 0 9 +0.33 0.60 0 9 + + +0.18 0.58 0 9 +0.24 0.54 0 9 +0.27 0.56 0 9 +0.25 0.59 0 9 +0.18 0.58 0 9 + + +0.30 0.50 0 9 +0.31 0.55 0 9 +0.27 0.56 0 9 +0.24 0.54 0 9 +0.30 0.50 0 9 + + +0.40 0.33 0 9 +0.41 0.25 0 9 +0.44 0.27 0 9 +0.45 0.31 0 9 +0.40 0.33 0 9 + + +0.41 0.18 0 9 +0.46 0.24 0 9 +0.44 0.27 0 9 +0.41 0.25 0 9 +0.41 0.18 0 9 + + +0.50 0.30 0 9 +0.45 0.31 0 9 +0.44 0.27 0 9 +0.46 0.24 0 9 +0.50 0.30 0 9 + + +0.30 0.50 0 9 +0.24 0.46 0 9 +0.27 0.44 0 9 +0.31 0.45 0 9 +0.30 0.50 0 9 + + +0.18 0.42 0 9 +0.25 0.41 0 9 +0.27 0.44 0 9 +0.24 0.46 0 9 +0.18 0.42 0 9 + + +0.33 0.40 0 9 +0.31 0.45 0 9 +0.27 0.44 0 9 +0.25 0.41 0 9 +0.33 0.40 0 9 + + diff --git a/tests/grid/grid_in_msh_v4/mesh.msh b/tests/grid/grid_in_msh_v4/mesh.msh new file mode 100644 index 000000000000..5010393a1909 --- /dev/null +++ b/tests/grid/grid_in_msh_v4/mesh.msh @@ -0,0 +1,501 @@ +$MeshFormat +4 0 8 +$EndMeshFormat +$Entities +0 6 1 0 +1 0 0 0 1 0 0 1 1 0 +2 1 0 0 1 1 0 1 2 0 +3 0 1 0 1 1 0 1 3 0 +4 0 0 0 0 1 0 1 4 0 +5 0.3 0.5 0 0.7 0.7 0 1 5 0 +6 0.3 0.3 0 0.7 0.5 0 1 6 0 +9 0 0.07524209221935962 0 0.9242325516454492 1 0 1 9 0 +$EndEntities +$Nodes +7 216 +1 1 0 13 +3 0 0 0 +6 1 0 0 +1647 0.1666666666666644 0 0 +1648 0.3333333333333288 0 0 +1649 0.4999999999999931 0 0 +1650 0.6666666666666574 0 0 +1651 0.8333333333333264 0 0 +1701 0.7499999999999919 0 0 +1702 0.9166666666666632 0 0 +1703 0.5833333333333253 0 0 +1704 0.416666666666661 0 0 +1705 0.2499999999999966 0 0 +1706 0.08333333333333219 0 0 +2 1 0 12 +5 1 1 0 +1652 1 0.1666666666666644 0 +1653 1 0.3333333333333288 0 +1654 1 0.4999999999999931 0 +1655 1 0.6666666666666574 0 +1656 1 0.8333333333333264 0 +1707 1 0.7499999999999919 0 +1708 1 0.9166666666666632 0 +1709 1 0.5833333333333253 0 +1710 1 0.416666666666661 0 +1711 1 0.2499999999999966 0 +1712 1 0.08333333333333219 0 +3 1 0 12 +4 0 1 0 +1657 0.8333333333333357 1 0 +1658 0.6666666666666713 1 0 +1659 0.5000000000000069 1 0 +1660 0.3333333333333426 1 0 +1661 0.1666666666666736 1 0 +1713 0.2500000000000081 1 0 +1714 0.08333333333333681 1 0 +1715 0.4166666666666747 1 0 +1716 0.5833333333333391 1 0 +1717 0.7500000000000034 1 0 +1718 0.9166666666666679 1 0 +4 1 0 11 +1662 0 0.8333333333333357 0 +1663 0 0.6666666666666713 0 +1664 0 0.5000000000000069 0 +1665 0 0.3333333333333426 0 +1666 0 0.1666666666666736 0 +1719 0 0.2500000000000081 0 +1720 0 0.08333333333333681 0 +1721 0 0.4166666666666747 0 +1722 0 0.5833333333333391 0 +1723 0 0.7500000000000034 0 +1724 0 0.9166666666666679 0 +5 1 0 13 +8 0.7 0.5 0 +9 0.3 0.5 0 +1667 0.6732050807568924 0.5999999999999918 0 +1668 0.6000000000000144 0.6732050807568793 0 +1669 0.5000000000000216 0.7 0 +1670 0.4000000000000145 0.6732050807568961 0 +1671 0.326794919243117 0.6000000000000082 0 +1725 0.3585786437626998 0.6414213562373188 0 +1726 0.3068148347421876 0.5517638090205087 0 +1727 0.4482361909795144 0.6931851652578186 0 +1728 0.5517638090205227 0.6931851652578087 0 +1729 0.6414213562373188 0.6414213562373001 0 +1730 0.6931851652578148 0.5517638090204995 0 +6 1 0 11 +1672 0.3267949192431128 0.399999999999999 0 +1673 0.3999999999999999 0.3267949192431123 0 +1674 0.4999999999999965 0.3 0 +1675 0.599999999999994 0.3267949192431088 0 +1676 0.6732050807568848 0.399999999999995 0 +1731 0.641421356237305 0.358578643762686 0 +1732 0.6931851652578129 0.4482361909794931 0 +1733 0.5517638090204992 0.306814834742185 0 +1734 0.4482361909794941 0.3068148347421868 0 +1735 0.3585786437626909 0.3585786437626901 0 +1736 0.3068148347421865 0.4482361909794953 0 +9 2 0 144 +1677 0.7246353489967157 0.7245892577490813 0 +1678 0.7244621443611338 0.2752454212829553 0 +1679 0.2754177298380878 0.72474033474392 0 +1680 0.2753835008990979 0.2755224974477131 0 +1681 0.8197037354848493 0.5842560513488779 0 +1682 0.8187725973058626 0.4149949959538635 0 +1683 0.4164160340057139 0.8191819138769635 0 +1684 0.5835772498442651 0.1808243805001786 0 +1685 0.5843928751208912 0.8182007189218857 0 +1686 0.1803074591893125 0.58427252900566 0 +1687 0.4149455084795177 0.1812809013185867 0 +1688 0.1817524392062167 0.4156905646242381 0 +1689 0.84957097469123 0.8496479176619097 0 +1690 0.8495173459120137 0.1503030736528348 0 +1691 0.150448830362328 0.8496984824700053 0 +1692 0.1503460591214605 0.1504841844387193 0 +1693 0.8474128606697829 0.2966023031909282 0 +1694 0.1524092117129105 0.7032759240162333 0 +1695 0.847610582286066 0.7032222006405694 0 +1696 0.2966401238900284 0.152592000932758 0 +1697 0.7026229705475365 0.8467752558386001 0 +1698 0.2975256444548792 0.8469768722462424 0 +1699 0.7024327506309364 0.1530119144421645 0 +1700 0.1531999201322243 0.297443318940622 0 +1737 0.1517729896268424 0.2239637516896706 0 +1738 0.1674761796692205 0.35656694178243 0 +1739 0.2142917105156611 0.2864829081941676 0 +1740 0.07659996006611214 0.3153883261369823 0 +1741 0.775975048271475 0.1516574940474996 0 +1742 0.6430050002376007 0.1669181474711716 0 +1743 0.7134474474960351 0.2141286678625599 0 +1744 0.6845497086487968 0.07650595722108226 0 +1745 0.2239872374086036 0.8483376773581239 0 +1746 0.3569708392302965 0.8330793930616029 0 +1747 0.2864716871464835 0.7858586034950812 0 +1748 0.3154294888941109 0.9234884361231213 0 +1749 0.7760969726193833 0.8482115867502549 0 +1750 0.6435079228342139 0.8324879873802429 0 +1751 0.713629159772126 0.7856822567938407 0 +1752 0.6846448186071039 0.9233876279193001 0 +1753 0.2234930915057444 0.1515380926857386 0 +1754 0.355792816184773 0.1669364511256724 0 +1755 0.2860118123945631 0.2140572491902356 0 +1756 0.3149867286116785 0.07629600046637901 0 +1757 0.8485907784886479 0.7764350591512396 0 +1758 0.8336571588854577 0.6437391259947236 0 +1759 0.7861229656413908 0.7139057291948254 0 +1760 0.923805291143033 0.6849444336536135 0 +1761 0.1514290210376192 0.7764872032431194 0 +1762 0.1663583354511115 0.6437742265109466 0 +1763 0.2139134707754992 0.7140081293800766 0 +1764 0.07620460585645525 0.6849712953414523 0 +1765 0.8484651032908983 0.2234526884218815 0 +1766 0.8330927289878227 0.3557986495723958 0 +1767 0.7859375025154584 0.2859238622369417 0 +1768 0.9237064303348914 0.3149678182621285 0 +1769 0.07517302956073026 0.1585754255526965 0 +1770 0.1585063628940624 0.07524209221935965 0 +1771 0.07522441518116399 0.8415159079016705 0 +1772 0.1585577485145008 0.9248492412350027 0 +1773 0.9247586729560069 0.1584848701597496 0 +1774 0.8414253396226701 0.07515153682641738 0 +1775 0.8414521540122828 0.9248239588309548 0 +1776 0.9247854873456149 0.841490625497618 0 +1777 0.2542736792246648 0.4078452823121186 0 +1778 0.09087621960310835 0.4578452823121225 0 +1779 0.2408762196031083 0.4578452823121191 0 +1780 0.4574727542397571 0.2406404506592933 0 +1781 0.4074727542397588 0.2540379102808495 0 +1782 0.4574727542397554 0.09064045065929337 0 +1783 0.2535511892162148 0.5921362645028341 0 +1784 0.09015372959465623 0.5421362645028334 0 +1785 0.2401537295946562 0.54213626450283 0 +1786 0.5421964375604564 0.7591003594609429 0 +1787 0.5921964375604528 0.7457028998393825 0 +1788 0.5421964375604491 0.9091003594609428 0 +1789 0.5917886249221296 0.2538096498716437 0 +1790 0.5417886249221308 0.2404121902500893 0 +1791 0.5417886249221291 0.0904121902500893 0 +1792 0.4082080170028642 0.7461934973169297 0 +1793 0.4582080170028678 0.7595909569384818 0 +1794 0.4582080170028604 0.9095909569384817 0 +1795 0.7459888390313737 0.4074974979769292 0 +1796 0.9093862986529313 0.4574974979769283 0 +1797 0.7593862986529313 0.4574974979769317 0 +1798 0.7464544081208708 0.5921280256744348 0 +1799 0.9098518677424247 0.5421280256744355 0 +1800 0.7598518677424246 0.542128025674439 0 +1801 0.3376917504495489 0.3011587083454127 0 +1802 0.3010892100711053 0.337761248723856 0 +1803 0.3011063245406024 0.6623701673719641 0 +1804 0.3377088649190512 0.698972707750408 0 +1805 0.6988336125590093 0.3376227106414751 0 +1806 0.6622310721805639 0.301020170263032 0 +1807 0.662317674498365 0.6988971692529804 0 +1808 0.6989202148768041 0.6622946288745366 0 +1809 0.07925318144703122 0.07928771277634823 0 +1810 0.0792788742572504 0.9207579539508353 0 +1811 0.9207260770061414 0.920745312748809 0 +1812 0.920712669811335 0.07924243507987479 0 +1813 0.834619083197678 0.4998127618256836 0 +1814 0.1655149745988823 0.4999907734074762 0 +1815 0.2367465457528705 0.07576904634286932 0 +1816 0.386229741425717 0.08346822556283619 0 +1817 0.613169166785463 0.08345907373558578 0 +1818 0.4996306895809431 0.1655263204546913 0 +1819 0.7629875241357335 0.07582874702374982 0 +1820 0.9242325516454492 0.236726344210939 0 +1821 0.9165463644939114 0.3862326581195284 0 +1822 0.9168285794427289 0.6135362296640244 0 +1823 0.924295389244324 0.7632175295756157 0 +1824 0.7630484863096934 0.9241057933751274 0 +1825 0.6134206280837765 0.9162439936901214 0 +1826 0.3868187529484857 0.9165396965308015 0 +1827 0.5002022272816584 0.8343456581997123 0 +1828 0.2369936187043059 0.924168838679062 0 +1829 0.07571451051880962 0.7632436016215614 0 +1830 0.08317916772555574 0.6135537799221429 0 +1831 0.08373808983461024 0.3866168042245524 0 +1832 0.07588649481342119 0.2369818758448394 0 +1833 0.7662886868811308 0.6530168774346301 0 +1834 0.6529127986662895 0.7656925783166116 0 +1835 0.3473398520746739 0.7660260504060055 0 +1836 0.233732329995857 0.6530721969414554 0 +1837 0.2342826948701629 0.3471640952531431 0 +1838 0.3467422833171609 0.2340475797355425 0 +1839 0.6526180362090823 0.2339691588671018 0 +1840 0.765963170773416 0.3467106801069355 0 +1841 0.7811099691303871 0.7810586579725401 0 +1842 0.7809562753934667 0.2187906781422207 0 +1843 0.2189503540920514 0.7811729033691003 0 +1844 0.2188924010107028 0.2190105004399531 0 +1845 0.6658890750393375 0.3340134468420197 0 +1846 0.3340708830270731 0.6659818051669414 0 +1847 0.6659468099178741 0.6659314461686509 0 +1848 0.3340594733807369 0.3341058055636081 0 +1849 0.7306592260209158 0.4383316653179528 0 +1850 0.7309696054139139 0.5614186837829566 0 +1851 0.5614642917069758 0.7304685998929217 0 +1852 0.4388053446685833 0.7307956648779532 0 +1853 0.5611924166147518 0.2692064332477624 0 +1854 0.2690341261441432 0.5614241763352227 0 +1855 0.4383151694931713 0.2693586068538997 0 +1856 0.2695157861497765 0.4385635215414124 0 +$EndNodes +$Elements +7 252 +1 1 1 12 +1 3 1706 +2 1706 1647 +3 1647 1705 +4 1705 1648 +5 1648 1704 +6 1704 1649 +7 1649 1703 +8 1703 1650 +9 1650 1701 +10 1701 1651 +11 1651 1702 +12 1702 6 +2 1 1 12 +13 6 1712 +14 1712 1652 +15 1652 1711 +16 1711 1653 +17 1653 1710 +18 1710 1654 +19 1654 1709 +20 1709 1655 +21 1655 1707 +22 1707 1656 +23 1656 1708 +24 1708 5 +3 1 1 12 +25 5 1718 +26 1718 1657 +27 1657 1717 +28 1717 1658 +29 1658 1716 +30 1716 1659 +31 1659 1715 +32 1715 1660 +33 1660 1713 +34 1713 1661 +35 1661 1714 +36 1714 4 +4 1 1 12 +37 4 1724 +38 1724 1662 +39 1662 1723 +40 1723 1663 +41 1663 1722 +42 1722 1664 +43 1664 1721 +44 1721 1665 +45 1665 1719 +46 1719 1666 +47 1666 1720 +48 1720 3 +5 1 1 12 +49 8 1730 +50 1730 1667 +51 1667 1729 +52 1729 1668 +53 1668 1728 +54 1728 1669 +55 1669 1727 +56 1727 1670 +57 1670 1725 +58 1725 1671 +59 1671 1726 +60 1726 9 +6 1 1 12 +61 9 1736 +62 1736 1672 +63 1672 1735 +64 1735 1673 +65 1673 1734 +66 1734 1674 +67 1674 1733 +68 1733 1675 +69 1675 1731 +70 1731 1676 +71 1676 1732 +72 1732 8 +9 2 3 180 +73 1674 1780 1818 1790 +74 1687 1782 1818 1780 +75 1649 1791 1818 1782 +76 1684 1790 1818 1791 +77 9 1785 1814 1779 +78 1686 1784 1814 1785 +79 1664 1778 1814 1784 +80 1688 1779 1814 1778 +81 1669 1786 1827 1793 +82 1685 1788 1827 1786 +83 1659 1794 1827 1788 +84 1683 1793 1827 1794 +85 8 1797 1813 1800 +86 1682 1796 1813 1797 +87 1654 1799 1813 1796 +88 1681 1800 1813 1799 +89 1693 1766 1840 1767 +90 1682 1795 1840 1766 +91 1676 1805 1840 1795 +92 1678 1767 1840 1805 +93 1695 1759 1833 1758 +94 1677 1808 1833 1759 +95 1667 1798 1833 1808 +96 1681 1758 1833 1798 +97 1694 1762 1836 1763 +98 1686 1783 1836 1762 +99 1671 1803 1836 1783 +100 1679 1763 1836 1803 +101 1699 1743 1839 1742 +102 1678 1806 1839 1743 +103 1675 1789 1839 1806 +104 1684 1742 1839 1789 +105 1697 1750 1834 1751 +106 1685 1787 1834 1750 +107 1668 1807 1834 1787 +108 1677 1751 1834 1807 +109 1696 1754 1838 1755 +110 1687 1781 1838 1754 +111 1673 1801 1838 1781 +112 1680 1755 1838 1801 +113 1700 1739 1837 1738 +114 1680 1802 1837 1739 +115 1672 1777 1837 1802 +116 1688 1738 1837 1777 +117 1698 1747 1835 1746 +118 1679 1804 1835 1747 +119 1670 1792 1835 1804 +120 1683 1746 1835 1792 +121 1656 1708 1811 1776 +122 5 1718 1811 1708 +123 1657 1775 1811 1718 +124 1689 1776 1811 1775 +125 1661 1714 1810 1772 +126 4 1724 1810 1714 +127 1662 1771 1810 1724 +128 1691 1772 1810 1771 +129 1652 1773 1812 1712 +130 1690 1774 1812 1773 +131 1651 1702 1812 1774 +132 6 1712 1812 1702 +133 1698 1746 1826 1748 +134 1683 1794 1826 1746 +135 1659 1715 1826 1794 +136 1660 1748 1826 1715 +137 1693 1768 1821 1766 +138 1653 1710 1821 1768 +139 1654 1796 1821 1710 +140 1682 1766 1821 1796 +141 1695 1758 1822 1760 +142 1681 1799 1822 1758 +143 1654 1709 1822 1799 +144 1655 1760 1822 1709 +145 1699 1742 1817 1744 +146 1684 1791 1817 1742 +147 1649 1703 1817 1791 +148 1650 1744 1817 1703 +149 1697 1752 1825 1750 +150 1658 1716 1825 1752 +151 1659 1788 1825 1716 +152 1685 1750 1825 1788 +153 1700 1738 1831 1740 +154 1688 1778 1831 1738 +155 1664 1721 1831 1778 +156 1665 1740 1831 1721 +157 1647 1770 1809 1706 +158 1692 1769 1809 1770 +159 1666 1720 1809 1769 +160 3 1706 1809 1720 +161 1694 1764 1830 1762 +162 1663 1722 1830 1764 +163 1664 1784 1830 1722 +164 1686 1762 1830 1784 +165 1696 1756 1816 1754 +166 1648 1704 1816 1756 +167 1649 1782 1816 1704 +168 1687 1754 1816 1782 +169 1690 1773 1820 1765 +170 1652 1711 1820 1773 +171 1653 1768 1820 1711 +172 1693 1765 1820 1768 +173 1689 1757 1823 1776 +174 1695 1760 1823 1757 +175 1655 1707 1823 1760 +176 1656 1776 1823 1707 +177 1691 1771 1829 1761 +178 1662 1723 1829 1771 +179 1663 1764 1829 1723 +180 1694 1761 1829 1764 +181 1692 1770 1815 1753 +182 1647 1705 1815 1770 +183 1648 1756 1815 1705 +184 1696 1753 1815 1756 +185 1689 1775 1824 1749 +186 1657 1717 1824 1775 +187 1658 1752 1824 1717 +188 1697 1749 1824 1752 +189 1697 1751 1841 1749 +190 1677 1759 1841 1751 +191 1695 1757 1841 1759 +192 1689 1749 1841 1757 +193 1690 1741 1819 1774 +194 1699 1744 1819 1741 +195 1650 1701 1819 1744 +196 1651 1774 1819 1701 +197 1699 1741 1842 1743 +198 1690 1765 1842 1741 +199 1693 1767 1842 1765 +200 1678 1743 1842 1767 +201 1691 1745 1828 1772 +202 1698 1748 1828 1745 +203 1660 1713 1828 1748 +204 1661 1772 1828 1713 +205 1698 1745 1843 1747 +206 1691 1761 1843 1745 +207 1694 1763 1843 1761 +208 1679 1747 1843 1763 +209 1700 1737 1844 1739 +210 1692 1753 1844 1737 +211 1696 1755 1844 1753 +212 1680 1739 1844 1755 +213 1692 1737 1832 1769 +214 1700 1740 1832 1737 +215 1665 1719 1832 1740 +216 1666 1769 1832 1719 +217 1675 1806 1845 1731 +218 1678 1805 1845 1806 +219 1676 1731 1845 1805 +220 1670 1804 1846 1725 +221 1679 1803 1846 1804 +222 1671 1725 1846 1803 +223 1667 1808 1847 1729 +224 1677 1807 1847 1808 +225 1668 1729 1847 1807 +226 1672 1802 1848 1735 +227 1680 1801 1848 1802 +228 1673 1735 1848 1801 +229 1676 1795 1849 1732 +230 1682 1797 1849 1795 +231 8 1732 1849 1797 +232 8 1800 1850 1730 +233 1681 1798 1850 1800 +234 1667 1730 1850 1798 +235 1668 1787 1851 1728 +236 1685 1786 1851 1787 +237 1669 1728 1851 1786 +238 1669 1793 1852 1727 +239 1683 1792 1852 1793 +240 1670 1727 1852 1792 +241 1674 1790 1853 1733 +242 1684 1789 1853 1790 +243 1675 1733 1853 1789 +244 1671 1783 1854 1726 +245 1686 1785 1854 1783 +246 9 1726 1854 1785 +247 1673 1781 1855 1734 +248 1687 1780 1855 1781 +249 1674 1734 1855 1780 +250 9 1779 1856 1736 +251 1688 1777 1856 1779 +252 1672 1736 1856 1777 +$EndElements diff --git a/tests/grid/grid_in_msh_version_4.cc b/tests/grid/grid_in_msh_version_4.cc new file mode 100644 index 000000000000..1cab217aaa83 --- /dev/null +++ b/tests/grid/grid_in_msh_version_4.cc @@ -0,0 +1,159 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2002 - 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. +// +// --------------------------------------------------------------------- + + +// read a file in the MSH format used by the GMSH program. +// and test that files in GMSH-2 format and in GMSH-4 format produce the same +// result. + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../tests.h" + +template +struct PointComparator +{ + bool + operator()(const Point &lhs, const Point &rhs) const + { + double downstream_size = 0; + double weight = 1.; + for (unsigned int d = 0; d < dim; ++d) + { + downstream_size += (rhs[d] - lhs[d]) * weight; + weight *= 1e-5; + } + if (downstream_size < 0) + return false; + else if (downstream_size > 0) + return true; + else + { + for (unsigned int d = 0; d < dim; ++d) + { + if (lhs[d] == rhs[d]) + continue; + return lhs[d] < rhs[d]; + } + return false; + } + } +}; + + +template +void +gmsh_grid(const char *name_v2, const char *name_v4) +{ + Triangulation tria_v2; + { + GridIn grid_in; + grid_in.attach_triangulation(tria_v2); + std::ifstream input_file(name_v2); + grid_in.read_msh(input_file); + } + + Triangulation tria_v4; + { + GridIn grid_in; + grid_in.attach_triangulation(tria_v4); + std::ifstream input_file(name_v4); + grid_in.read_msh(input_file); + } + + AssertThrow(tria_v2.n_active_cells() == tria_v4.n_active_cells(), + ExcInternalError()); + deallog << " " << tria_v2.n_active_cells() << " active cells" << std::endl; + + // The cells and faces in the two files are in reversed order + // but the vertex index is the same. + auto cell_v2 = tria_v2.begin_active(); + auto cell_v4 = + std::next(tria_v4.begin_active(), tria_v4.n_active_cells() - 1); + const auto end_v2 = tria_v2.end(); + for (; cell_v2 != end_v2; ++cell_v2, --cell_v4) + { + AssertThrow(cell_v2->material_id() == cell_v4->material_id(), + ExcInternalError()); + std::set vertices_v2; + std::set vertices_v4; + for (unsigned int i = 0; i < GeometryInfo::vertices_per_cell; ++i) + { + AssertThrow((tria_v2.get_vertices()[cell_v2->vertex_index(i)] - + tria_v4.get_vertices()[cell_v2->vertex_index(i)]) + .norm() < 1.e-10, + ExcInternalError()); + AssertThrow((tria_v2.get_vertices()[cell_v4->vertex_index(i)] - + tria_v4.get_vertices()[cell_v4->vertex_index(i)]) + .norm() < 1.e-10, + ExcInternalError()); + vertices_v2.insert(cell_v2->vertex_index(i)); + vertices_v4.insert(cell_v4->vertex_index(i)); + } + AssertThrow(vertices_v2 == vertices_v4, ExcInternalError()); + std::map, types::boundary_id, PointComparator> faces_v2; + std::map, types::boundary_id, PointComparator> faces_v4; + for (unsigned int i = 0; i < GeometryInfo::faces_per_cell; ++i) + { + faces_v2[cell_v2->face(i)->center()] = + cell_v2->face(i)->boundary_id(); + faces_v4[cell_v4->face(i)->center()] = + cell_v4->face(i)->boundary_id(); + } + AssertThrow(faces_v2 == faces_v4, ExcInternalError()); + std::map, types::boundary_id, PointComparator> lines_v2; + std::map, types::boundary_id, PointComparator> lines_v4; + for (unsigned int i = 0; i < GeometryInfo::lines_per_cell; ++i) + { + lines_v2[cell_v2->line(i)->center()] = + cell_v2->line(i)->boundary_id(); + lines_v4[cell_v4->line(i)->center()] = + cell_v4->line(i)->boundary_id(); + } + AssertThrow(lines_v2 == lines_v4, ExcInternalError()); + } + deallog << " OK" << std::endl; +} + +void +filename_resolution() +{ + deallog << "grid_in_msh_version_2/hole81" << std::endl; + gmsh_grid<2>(SOURCE_DIR "/grid_in_msh_version_2/hole81.msh", + SOURCE_DIR "/grid_in_msh_version_4/hole81.msh"); + deallog << "grid_in_msh_version_2/hole8170" << std::endl; + gmsh_grid<2>(SOURCE_DIR "/grid_in_msh_version_2/hole8170.msh", + SOURCE_DIR "/grid_in_msh_version_4/hole8170.msh"); +} + + +int +main() +{ + initlog(); + deallog.get_file_stream() << std::setprecision(5); + + filename_resolution(); +} diff --git a/tests/grid/grid_in_msh_version_4.output b/tests/grid/grid_in_msh_version_4.output new file mode 100644 index 000000000000..3dd5e3673860 --- /dev/null +++ b/tests/grid/grid_in_msh_version_4.output @@ -0,0 +1,7 @@ + +DEAL::grid_in_msh_version_2/hole81 +DEAL:: 81 active cells +DEAL:: OK +DEAL::grid_in_msh_version_2/hole8170 +DEAL:: 8170 active cells +DEAL:: OK diff --git a/tests/grid/grid_in_msh_version_4/hole81.msh b/tests/grid/grid_in_msh_version_4/hole81.msh new file mode 100644 index 000000000000..c10687073913 --- /dev/null +++ b/tests/grid/grid_in_msh_version_4/hole81.msh @@ -0,0 +1,205 @@ +$MeshFormat +4 0 8 +$EndMeshFormat +$Entities +0 0 1 0 +0 0 0 0 1 1 0 1 1 0 +$EndEntities +$Nodes +1 109 +0 2 0 109 +1 0.323223 0.323223 0 +2 0.26903 0.404329 0 +3 0.205471 0.335785 0 +4 0.261688 0.253588 0 +5 0.25 0.5 0 +6 0.168897 0.421825 0 +7 0.351915 0.201897 0 +8 0.404329 0.26903 0 +9 0.151061 0.146973 0 +10 0.267453 0.115922 0 +11 0.115602 0.257549 0 +12 0.09287869999999999 0.355903 0 +13 0.475666 0.173068 0 +14 0.5 0.25 0 +15 0 0.2 0 +16 0 0.1 0 +17 0 0.3 0 +18 0.0706253 0.44267 0 +19 0 0.4 0 +20 0.12425 0.502054 0 +21 0.170037 0.579759 0 +22 0.26903 0.595671 0 +23 0.210011 0.664612 0 +24 0.323223 0.676777 0 +25 0.273645 0.727505 0 +26 0.404329 0.73097 0 +27 0.332934 0.761889 0 +28 0.5 0.75 0 +29 0.506916 0.824562 0 +30 0.409603 0.823159 0 +31 0.595671 0.73097 0 +32 0.604938 0.811586 0 +33 0.676777 0.676777 0 +34 0.707555 0.779276 0 +35 0.0470804 0.501553 0 +36 0 0.5 0 +37 0.07092469999999999 0.561217 0 +38 0.0961342 0.6492790000000001 0 +39 0.129878 0.762537 0 +40 0.235142 0.8052550000000001 0 +41 0.322202 0.826855 0 +42 0.407261 0.910834 0 +43 0.4 1 0 +44 0.3 1 0 +45 0.309776 0.910203 0 +46 0.504887 0.910157 0 +47 0.605977 0.903532 0 +48 0.714192 0.888402 0 +49 0.5 1 0 +50 0.2 1 0 +51 0.213462 0.90127 0 +52 0.1 1 0 +53 0.109849 0.891977 0 +54 0 1 0 +55 0 0.9 0 +56 0.6 1 0 +57 0 0.8 0 +58 0 0.7 0 +59 0 0.6 0 +60 0.73097 0.595671 0 +61 0.820507 0.734392 0 +62 1 0.6 0 +63 1 0.7 0 +64 0.75 0.5 0 +65 0.851105 0.486625 0 +66 0.73097 0.404329 0 +67 0.816035 0.389041 0 +68 0.842812 0.863497 0 +69 0.909413 0.382874 0 +70 0.920173 0.4565 0 +71 1 0.8 0 +72 1 0.9 0 +73 0.9142709999999999 0.921166 0 +74 1 1 0 +75 0.9 1 0 +76 1 0.4 0 +77 1 0.5 0 +78 0.8 1 0 +79 0.7 1 0 +80 0.892629 0.287213 0 +81 1 0.3 0 +82 0.676777 0.323223 0 +83 0.595671 0.26903 0 +84 0.622453 0.20943 0 +85 0.758832 0.275022 0 +86 0.6 0 0 +87 0.7 0 0 +88 0.679002 0.0740277 0 +89 0.579569 0.0612463 0 +90 0.8 0 0 +91 0.786941 0.0865707 0 +92 0.9 0 0 +93 0.893574 0.09434090000000001 0 +94 1 0 0 +95 1 0.1 0 +96 1 0.2 0 +97 0.889796 0.189523 0 +98 0.772001 0.17509 0 +99 0.653399 0.144139 0 +100 0.540113 0.116873 0 +101 0.4 0 0 +102 0.459658 0.0723085 0 +103 0.373509 0.0963702 0 +104 0.3 0 0 +105 0.2 0 0 +106 0.5 0 0 +107 0.512671 0.0441593 0 +108 0.1 0 0 +109 0 0 0 +$EndNodes +$Elements +1 81 +0 2 3 81 +1 9 16 109 108 +2 108 105 10 9 +3 41 27 26 30 +4 45 41 30 42 +5 103 102 100 13 +6 10 103 13 7 +7 107 89 100 102 +8 101 106 107 102 +9 106 86 89 107 +10 104 103 10 105 +11 101 102 103 104 +12 80 85 98 97 +13 80 69 67 85 +14 88 99 100 89 +15 99 84 13 100 +16 98 85 84 99 +17 91 98 99 88 +18 67 66 82 85 +19 62 65 70 77 +20 68 61 63 71 +21 91 93 97 98 +22 96 81 80 97 +23 95 96 97 93 +24 92 94 95 93 +25 90 92 93 91 +26 87 90 91 88 +27 86 87 88 89 +28 83 14 13 84 +29 82 83 84 85 +30 76 69 80 81 +31 48 79 56 47 +32 78 79 48 68 +33 75 78 68 73 +34 70 69 76 77 +35 72 74 75 73 +36 71 72 73 68 +37 65 67 69 70 +38 34 61 68 48 +39 64 66 67 65 +40 60 64 65 62 +41 60 62 63 61 +42 33 60 61 34 +43 40 41 45 51 +44 51 53 39 40 +45 37 59 36 35 +46 58 59 37 38 +47 57 58 38 39 +48 55 57 39 53 +49 46 47 56 49 +50 52 54 55 53 +51 50 52 53 51 +52 44 50 51 45 +53 42 46 49 43 +54 32 34 48 47 +55 29 32 47 46 +56 30 29 46 42 +57 42 43 44 45 +58 25 27 41 40 +59 23 25 40 39 +60 21 23 39 38 +61 20 21 38 37 +62 18 20 37 35 +63 19 18 35 36 +64 31 33 34 32 +65 28 31 32 29 +66 26 28 29 30 +67 24 26 27 25 +68 22 24 25 23 +69 5 22 23 21 +70 6 5 21 20 +71 12 6 20 18 +72 17 12 18 19 +73 11 12 17 15 +74 9 11 15 16 +75 8 7 13 14 +76 3 6 12 11 +77 4 3 11 9 +78 4 9 10 7 +79 1 4 7 8 +80 2 5 6 3 +81 1 2 3 4 +$EndElements diff --git a/tests/grid/grid_in_msh_version_4/hole8170.msh b/tests/grid/grid_in_msh_version_4/hole8170.msh new file mode 100644 index 000000000000..0123fd703909 --- /dev/null +++ b/tests/grid/grid_in_msh_version_4/hole8170.msh @@ -0,0 +1,16634 @@ +$MeshFormat +4 0 8 +$EndMeshFormat +$Entities +0 0 1 0 +0 0.07000119999999999 0.0199995 0 1 0.99 0 1 1 0 +$EndEntities +$Nodes +1 8449 +0 2 0 8449 +1 0.25 0.5 0 +2 0.250198 0.509939 0 +3 0.240977 0.51045 0 +4 0.240733 0.500203 0 +5 0.25079 0.519863 0 +6 0.241584 0.5206460000000001 0 +7 0.251777 0.529755 0 +8 0.242569 0.53085 0 +9 0.253156 0.5396 0 +10 0.243923 0.540949 0 +11 0.254926 0.549382 0 +12 0.245668 0.551011 0 +13 0.257083 0.559086 0 +14 0.247854 0.560959 0 +15 0.259624 0.568697 0 +16 0.250467 0.570724 0 +17 0.262545 0.578199 0 +18 0.253532 0.580349 0 +19 0.265842 0.587578 0 +20 0.256958 0.5898409999999999 0 +21 0.269509 0.596818 0 +22 0.260714 0.599203 0 +23 0.27354 0.605905 0 +24 0.264701 0.608471 0 +25 0.277929 0.614824 0 +26 0.26894 0.61783 0 +27 0.28267 0.6235619999999999 0 +28 0.273248 0.627177 0 +29 0.287754 0.632105 0 +30 0.27818 0.637097 0 +31 0.293174 0.640439 0 +32 0.284592 0.646257 0 +33 0.298921 0.64855 0 +34 0.291024 0.65459 0 +35 0.304986 0.656427 0 +36 0.29765 0.66271 0 +37 0.311359 0.664056 0 +38 0.3044 0.670569 0 +39 0.31803 0.671426 0 +40 0.31136 0.678132 0 +41 0.324989 0.678525 0 +42 0.318498 0.685382 0 +43 0.332225 0.685342 0 +44 0.325922 0.692351 0 +45 0.339727 0.691866 0 +46 0.33355 0.698968 0 +47 0.347481 0.698086 0 +48 0.341452 0.705275 0 +49 0.355477 0.703993 0 +50 0.349574 0.711341 0 +51 0.363701 0.709577 0 +52 0.357929 0.717201 0 +53 0.372141 0.71483 0 +54 0.366556 0.723004 0 +55 0.380783 0.7197440000000001 0 +56 0.375307 0.728651 0 +57 0.389614 0.72431 0 +58 0.384852 0.734322 0 +59 0.398619 0.728521 0 +60 0.395198 0.738356 0 +61 0.407784 0.732371 0 +62 0.404998 0.741653 0 +63 0.417095 0.735853 0 +64 0.414764 0.744792 0 +65 0.426537 0.738963 0 +66 0.424451 0.747712 0 +67 0.436096 0.741695 0 +68 0.434092 0.750414 0 +69 0.445755 0.744044 0 +70 0.443749 0.752763 0 +71 0.455501 0.746008 0 +72 0.4534 0.754768 0 +73 0.465316 0.747582 0 +74 0.463133 0.756399 0 +75 0.475187 0.748766 0 +76 0.472882 0.757701 0 +77 0.485096 0.749555 0 +78 0.482727 0.758753 0 +79 0.495029 0.749951 0 +80 0.492804 0.759676 0 +81 0.5049709999999999 0.749951 0 +82 0.50322 0.7608 0 +83 0.514904 0.749555 0 +84 0.5158779999999999 0.763585 0 +85 0.524813 0.748766 0 +86 0.527818 0.759324 0 +87 0.534684 0.747582 0 +88 0.537756 0.756718 0 +89 0.544499 0.746008 0 +90 0.547447 0.754811 0 +91 0.554245 0.744044 0 +92 0.557204 0.752862 0 +93 0.563904 0.741695 0 +94 0.566902 0.750603 0 +95 0.5734629999999999 0.738963 0 +96 0.576552 0.747962 0 +97 0.582905 0.735853 0 +98 0.586116 0.744887 0 +99 0.592216 0.732371 0 +100 0.59556 0.741336 0 +101 0.6013810000000001 0.728521 0 +102 0.60484 0.737382 0 +103 0.610386 0.72431 0 +104 0.614008 0.733088 0 +105 0.619217 0.7197440000000001 0 +106 0.623126 0.728539 0 +107 0.6278589999999999 0.71483 0 +108 0.632285 0.723746 0 +109 0.6362989999999999 0.709577 0 +110 0.641373 0.718813 0 +111 0.644523 0.703993 0 +112 0.650884 0.713164 0 +113 0.652519 0.698086 0 +114 0.659245 0.70623 0 +115 0.660273 0.691866 0 +116 0.667093 0.6991849999999999 0 +117 0.667775 0.685342 0 +118 0.6746259999999999 0.692138 0 +119 0.675011 0.678525 0 +120 0.681853 0.6850619999999999 0 +121 0.68197 0.671426 0 +122 0.688824 0.67782 0 +123 0.6886409999999999 0.664056 0 +124 0.695457 0.670451 0 +125 0.695014 0.656427 0 +126 0.701802 0.662863 0 +127 0.701079 0.64855 0 +128 0.707852 0.655026 0 +129 0.706826 0.640439 0 +130 0.713737 0.64698 0 +131 0.712246 0.632105 0 +132 0.719669 0.638768 0 +133 0.71733 0.6235619999999999 0 +134 0.725928 0.630317 0 +135 0.722071 0.614824 0 +136 0.734762 0.6206739999999999 0 +137 0.72646 0.605905 0 +138 0.737039 0.608338 0 +139 0.730491 0.596818 0 +140 0.7397590000000001 0.598539 0 +141 0.734158 0.587578 0 +142 0.742981 0.589271 0 +143 0.737455 0.578199 0 +144 0.7462569999999999 0.579879 0 +145 0.740376 0.568697 0 +146 0.749324 0.570416 0 +147 0.742917 0.559086 0 +148 0.752034 0.560765 0 +149 0.745074 0.549382 0 +150 0.754318 0.550998 0 +151 0.746844 0.5396 0 +152 0.756148 0.541041 0 +153 0.748223 0.529755 0 +154 0.757584 0.531003 0 +155 0.74921 0.519863 0 +156 0.758686 0.520853 0 +157 0.749802 0.509939 0 +158 0.7595229999999999 0.510597 0 +159 0.75 0.5 0 +160 0.760114 0.500149 0 +161 0.749802 0.490061 0 +162 0.760177 0.489634 0 +163 0.74921 0.480137 0 +164 0.75925 0.479149 0 +165 0.748223 0.470245 0 +166 0.757833 0.468852 0 +167 0.746844 0.4604 0 +168 0.756121 0.458679 0 +169 0.745074 0.450618 0 +170 0.754174 0.448668 0 +171 0.742917 0.440914 0 +172 0.751919 0.438781 0 +173 0.740376 0.431303 0 +174 0.7493570000000001 0.429052 0 +175 0.737455 0.421801 0 +176 0.74647 0.419485 0 +177 0.734158 0.412422 0 +178 0.743187 0.410055 0 +179 0.730491 0.403182 0 +180 0.739584 0.400797 0 +181 0.72646 0.394095 0 +182 0.735707 0.391617 0 +183 0.722071 0.385176 0 +184 0.731649 0.38237 0 +185 0.71733 0.376438 0 +186 0.727715 0.372796 0 +187 0.712246 0.367895 0 +188 0.724908 0.360503 0 +189 0.706826 0.359561 0 +190 0.715606 0.351747 0 +191 0.701079 0.35145 0 +192 0.708368 0.344047 0 +193 0.695014 0.343573 0 +194 0.701751 0.336299 0 +195 0.6886409999999999 0.335944 0 +196 0.695095 0.328725 0 +197 0.68197 0.328574 0 +198 0.688239 0.321381 0 +199 0.675011 0.321475 0 +200 0.681149 0.314207 0 +201 0.667775 0.314658 0 +202 0.673779 0.307306 0 +203 0.660273 0.308134 0 +204 0.666187 0.300647 0 +205 0.652519 0.301914 0 +206 0.658311 0.294259 0 +207 0.644523 0.296007 0 +208 0.650196 0.288148 0 +209 0.6362989999999999 0.290423 0 +210 0.641823 0.282296 0 +211 0.6278589999999999 0.28517 0 +212 0.633177 0.276716 0 +213 0.619217 0.280256 0 +214 0.6242490000000001 0.27138 0 +215 0.610386 0.27569 0 +216 0.614978 0.266457 0 +217 0.6013810000000001 0.271479 0 +218 0.6053230000000001 0.262356 0 +219 0.592216 0.267629 0 +220 0.595599 0.258665 0 +221 0.582905 0.264147 0 +222 0.585898 0.255279 0 +223 0.5734629999999999 0.261037 0 +224 0.576174 0.252165 0 +225 0.563904 0.258305 0 +226 0.566429 0.249437 0 +227 0.554245 0.255956 0 +228 0.556689 0.247097 0 +229 0.544499 0.253992 0 +230 0.546903 0.24511 0 +231 0.534684 0.252418 0 +232 0.537119 0.243501 0 +233 0.524813 0.251234 0 +234 0.527287 0.242207 0 +235 0.514904 0.250445 0 +236 0.517379 0.24116 0 +237 0.5049709999999999 0.250049 0 +238 0.507345 0.240231 0 +239 0.495029 0.250049 0 +240 0.49701 0.239049 0 +241 0.485096 0.250445 0 +242 0.484755 0.235939 0 +243 0.475187 0.251234 0 +244 0.472502 0.239885 0 +245 0.465316 0.252418 0 +246 0.462312 0.242606 0 +247 0.455501 0.253992 0 +248 0.452324 0.24476 0 +249 0.445755 0.255956 0 +250 0.442458 0.246998 0 +251 0.436096 0.258305 0 +252 0.432714 0.249482 0 +253 0.426537 0.261037 0 +254 0.423007 0.252293 0 +255 0.417095 0.264147 0 +256 0.413391 0.255452 0 +257 0.407784 0.267629 0 +258 0.40386 0.259017 0 +259 0.398619 0.271479 0 +260 0.394481 0.263021 0 +261 0.389614 0.27569 0 +262 0.385251 0.26742 0 +263 0.380783 0.280256 0 +264 0.376185 0.272198 0 +265 0.372141 0.28517 0 +266 0.367286 0.277299 0 +267 0.363701 0.290423 0 +268 0.358615 0.282698 0 +269 0.355477 0.296007 0 +270 0.350136 0.288431 0 +271 0.347481 0.301914 0 +272 0.341914 0.294454 0 +273 0.339727 0.308134 0 +274 0.333932 0.300801 0 +275 0.332225 0.314658 0 +276 0.326229 0.307408 0 +277 0.324989 0.321475 0 +278 0.318775 0.314267 0 +279 0.31803 0.328574 0 +280 0.311664 0.321404 0 +281 0.311359 0.335944 0 +282 0.304886 0.328834 0 +283 0.304986 0.343573 0 +284 0.298439 0.336538 0 +285 0.298921 0.35145 0 +286 0.292251 0.344414 0 +287 0.293174 0.359561 0 +288 0.28623 0.352403 0 +289 0.287754 0.367895 0 +290 0.280168 0.360568 0 +291 0.28267 0.376438 0 +292 0.27369 0.368898 0 +293 0.277929 0.385176 0 +294 0.264494 0.377983 0 +295 0.27354 0.394095 0 +296 0.261854 0.39068 0 +297 0.269509 0.403182 0 +298 0.259222 0.400933 0 +299 0.265842 0.412422 0 +300 0.25606 0.410648 0 +301 0.262545 0.421801 0 +302 0.253077 0.420284 0 +303 0.259624 0.431303 0 +304 0.250344 0.429932 0 +305 0.257083 0.440914 0 +306 0.247835 0.439699 0 +307 0.254926 0.450618 0 +308 0.245666 0.449566 0 +309 0.253156 0.4604 0 +310 0.243814 0.459531 0 +311 0.251777 0.470245 0 +312 0.242409 0.469601 0 +313 0.25079 0.480137 0 +314 0.241429 0.479753 0 +315 0.250198 0.490061 0 +316 0.2409 0.48996 0 +317 0 0 0 +318 0.01 0 0 +319 0.0100003 0.0100001 0 +320 0 0.01 0 +321 0.02 0 0 +322 0.0200004 0.0100002 0 +323 0.03 0 0 +324 0.0300004 0.0100006 0 +325 0.04 0 0 +326 0.0400005 0.0100006 0 +327 0.05 0 0 +328 0.0500005 0.0100005 0 +329 0.06 0 0 +330 0.0600005 0.0100004 0 +331 0.07000000000000001 0 0 +332 0.07000049999999999 0.0100002 0 +333 0.08 0 0 +334 0.0800004 0.0100001 0 +335 0.09 0 0 +336 0.09000030000000001 0.01 0 +337 0.1 0 0 +338 0.1 0.00999999 0 +339 0.11 0 0 +340 0.11 0.009999950000000001 0 +341 0.12 0 0 +342 0.12 0.009999940000000001 0 +343 0.13 0 0 +344 0.13 0.009999950000000001 0 +345 0.14 0 0 +346 0.14 0.00999996 0 +347 0.15 0 0 +348 0.15 0.00999997 0 +349 0.16 0 0 +350 0.16 0.00999998 0 +351 0.17 0 0 +352 0.17 0.00999999 0 +353 0.18 0 0 +354 0.18 0.00999999 0 +355 0.19 0 0 +356 0.19 0.01 0 +357 0.2 0 0 +358 0.2 0.01 0 +359 0.21 0 0 +360 0.21 0.01 0 +361 0.22 0 0 +362 0.22 0.01 0 +363 0.23 0 0 +364 0.23 0.01 0 +365 0.24 0 0 +366 0.24 0.01 0 +367 0.25 0 0 +368 0.25 0.01 0 +369 0.26 0 0 +370 0.26 0.01 0 +371 0.27 0 0 +372 0.27 0.01 0 +373 0.28 0 0 +374 0.28 0.01 0 +375 0.29 0 0 +376 0.29 0.01 0 +377 0.3 0 0 +378 0.3 0.01 0 +379 0.31 0 0 +380 0.31 0.01 0 +381 0.32 0 0 +382 0.32 0.01 0 +383 0.33 0 0 +384 0.33 0.01 0 +385 0.34 0 0 +386 0.34 0.01 0 +387 0.35 0 0 +388 0.35 0.01 0 +389 0.36 0 0 +390 0.36 0.01 0 +391 0.37 0 0 +392 0.37 0.01 0 +393 0.38 0 0 +394 0.38 0.01 0 +395 0.39 0 0 +396 0.39 0.01 0 +397 0.4 0 0 +398 0.4 0.01 0 +399 0.41 0 0 +400 0.41 0.01 0 +401 0.42 0 0 +402 0.42 0.01 0 +403 0.43 0 0 +404 0.43 0.01 0 +405 0.44 0 0 +406 0.44 0.01 0 +407 0.45 0 0 +408 0.45 0.01 0 +409 0.46 0 0 +410 0.46 0.01 0 +411 0.47 0 0 +412 0.47 0.01 0 +413 0.48 0 0 +414 0.48 0.01 0 +415 0.49 0 0 +416 0.49 0.01 0 +417 0.5 0 0 +418 0.5 0.0100447 0 +419 0.51 0 0 +420 0.510001 0.0100575 0 +421 0.52 0 0 +422 0.520001 0.0100796 0 +423 0.53 0 0 +424 0.5300010000000001 0.010093 0 +425 0.54 0 0 +426 0.54 0.0100975 0 +427 0.55 0 0 +428 0.55 0.0100767 0 +429 0.5600000000000001 0 0 +430 0.5600000000000001 0.0100545 0 +431 0.57 0 0 +432 0.57 0.0100348 0 +433 0.58 0 0 +434 0.58 0.0100199 0 +435 0.59 0 0 +436 0.59 0.0100103 0 +437 0.6 0 0 +438 0.6 0.0100049 0 +439 0.61 0 0 +440 0.61 0.0100022 0 +441 0.62 0 0 +442 0.62 0.0100009 0 +443 0.63 0 0 +444 0.63 0.0100004 0 +445 0.64 0 0 +446 0.64 0.0100001 0 +447 0.65 0 0 +448 0.65 0.0100001 0 +449 0.66 0 0 +450 0.66 0.01 0 +451 0.67 0 0 +452 0.67 0.01 0 +453 0.68 0 0 +454 0.68 0.01 0 +455 0.6899999999999999 0 0 +456 0.6899999999999999 0.01 0 +457 0.7 0 0 +458 0.7 0.01 0 +459 0.71 0 0 +460 0.71 0.01 0 +461 0.72 0 0 +462 0.72 0.01 0 +463 0.73 0 0 +464 0.73 0.01 0 +465 0.74 0 0 +466 0.74 0.01 0 +467 0.75 0 0 +468 0.75 0.01 0 +469 0.76 0 0 +470 0.76 0.01 0 +471 0.77 0 0 +472 0.77 0.01 0 +473 0.78 0 0 +474 0.78 0.01 0 +475 0.79 0 0 +476 0.79 0.01 0 +477 0.8 0 0 +478 0.8 0.01 0 +479 0.8100000000000001 0 0 +480 0.8100000000000001 0.01 0 +481 0.82 0 0 +482 0.82 0.01 0 +483 0.83 0 0 +484 0.83 0.01 0 +485 0.84 0 0 +486 0.84 0.01 0 +487 0.85 0 0 +488 0.85 0.00999999 0 +489 0.86 0 0 +490 0.86 0.00999999 0 +491 0.87 0 0 +492 0.87 0.00999997 0 +493 0.88 0 0 +494 0.88 0.009999950000000001 0 +495 0.89 0 0 +496 0.89 0.009999859999999999 0 +497 0.9 0 0 +498 0.899999 0.00999973 0 +499 0.91 0 0 +500 0.9099969999999999 0.009999839999999999 0 +501 0.92 0 0 +502 0.919997 0.0100007 0 +503 0.93 0 0 +504 0.929997 0.0100017 0 +505 0.9399999999999999 0 0 +506 0.939998 0.0100014 0 +507 0.95 0 0 +508 0.949999 0.0100005 0 +509 0.96 0 0 +510 0.959997 0.0100009 0 +511 0.97 0 0 +512 0.969998 0.0100012 0 +513 0.98 0 0 +514 0.979999 0.0100003 0 +515 0.99 0 0 +516 0.989999 0.00999999 0 +517 1 0 0 +518 1 0.01 0 +519 1 1 0 +520 0.99 1 0 +521 0.99 0.99 0 +522 1 0.99 0 +523 0.98 1 0 +524 0.979999 0.989999 0 +525 0.97 1 0 +526 0.9699989999999999 0.989998 0 +527 0.96 1 0 +528 0.959999 0.989998 0 +529 0.95 1 0 +530 0.949999 0.989998 0 +531 0.9399999999999999 1 0 +532 0.939999 0.989999 0 +533 0.93 1 0 +534 0.929999 0.989999 0 +535 0.92 1 0 +536 0.919999 0.989999 0 +537 0.91 1 0 +538 0.909999 0.99 0 +539 0.9 1 0 +540 0.899999 0.99 0 +541 0.89 1 0 +542 0.889999 0.99 0 +543 0.88 1 0 +544 0.88 0.99 0 +545 0.87 1 0 +546 0.87 0.99 0 +547 0.86 1 0 +548 0.86 0.99 0 +549 0.85 1 0 +550 0.85 0.99 0 +551 0.84 1 0 +552 0.84 0.99 0 +553 0.83 1 0 +554 0.83 0.99 0 +555 0.82 1 0 +556 0.82 0.99 0 +557 0.8100000000000001 1 0 +558 0.8100000000000001 0.99 0 +559 0.8 1 0 +560 0.8 0.99 0 +561 0.79 1 0 +562 0.79 0.99 0 +563 0.78 1 0 +564 0.78 0.99 0 +565 0.77 1 0 +566 0.77 0.99 0 +567 0.76 1 0 +568 0.76 0.99 0 +569 0.75 1 0 +570 0.75 0.99 0 +571 0.74 1 0 +572 0.74 0.99 0 +573 0.73 1 0 +574 0.73 0.99 0 +575 0.72 1 0 +576 0.72 0.99 0 +577 0.71 1 0 +578 0.71 0.99 0 +579 0.7 1 0 +580 0.7 0.99 0 +581 0.6899999999999999 1 0 +582 0.6899999999999999 0.99 0 +583 0.68 1 0 +584 0.68 0.99 0 +585 0.67 1 0 +586 0.67 0.99 0 +587 0.66 1 0 +588 0.66 0.99 0 +589 0.65 1 0 +590 0.65 0.99 0 +591 0.64 1 0 +592 0.64 0.99 0 +593 0.63 1 0 +594 0.63 0.99 0 +595 0.62 1 0 +596 0.62 0.99 0 +597 0.61 1 0 +598 0.61 0.99 0 +599 0.6 1 0 +600 0.6 0.99 0 +601 0.59 1 0 +602 0.59 0.99 0 +603 0.58 1 0 +604 0.58 0.99 0 +605 0.57 1 0 +606 0.57 0.99 0 +607 0.5600000000000001 1 0 +608 0.5600000000000001 0.99 0 +609 0.55 1 0 +610 0.55 0.989963 0 +611 0.54 1 0 +612 0.54 0.98994 0 +613 0.53 1 0 +614 0.5300010000000001 0.9899 0 +615 0.52 1 0 +616 0.520004 0.989877 0 +617 0.51 1 0 +618 0.510005 0.989891 0 +619 0.5 1 0 +620 0.500006 0.989903 0 +621 0.49 1 0 +622 0.490006 0.989931 0 +623 0.48 1 0 +624 0.480005 0.989954 0 +625 0.47 1 0 +626 0.470004 0.989971 0 +627 0.46 1 0 +628 0.460003 0.9899829999999999 0 +629 0.45 1 0 +630 0.450003 0.989991 0 +631 0.44 1 0 +632 0.440002 0.989981 0 +633 0.43 1 0 +634 0.430002 0.989966 0 +635 0.42 1 0 +636 0.420001 0.989973 0 +637 0.41 1 0 +638 0.410001 0.989974 0 +639 0.4 1 0 +640 0.400001 0.989977 0 +641 0.39 1 0 +642 0.39 0.989974 0 +643 0.38 1 0 +644 0.38 0.989977 0 +645 0.37 1 0 +646 0.37 0.989975 0 +647 0.36 1 0 +648 0.36 0.989976 0 +649 0.35 1 0 +650 0.349999 0.989976 0 +651 0.34 1 0 +652 0.339999 0.989975 0 +653 0.33 1 0 +654 0.329999 0.989971 0 +655 0.32 1 0 +656 0.319999 0.989975 0 +657 0.31 1 0 +658 0.309999 0.9899829999999999 0 +659 0.3 1 0 +660 0.299999 0.98999 0 +661 0.29 1 0 +662 0.29 0.989995 0 +663 0.28 1 0 +664 0.28 0.989998 0 +665 0.27 1 0 +666 0.27 0.989999 0 +667 0.26 1 0 +668 0.26 0.99 0 +669 0.25 1 0 +670 0.25 0.99 0 +671 0.24 1 0 +672 0.24 0.99 0 +673 0.23 1 0 +674 0.23 0.99 0 +675 0.22 1 0 +676 0.22 0.99 0 +677 0.21 1 0 +678 0.21 0.99 0 +679 0.2 1 0 +680 0.2 0.99 0 +681 0.19 1 0 +682 0.19 0.99 0 +683 0.18 1 0 +684 0.18 0.99 0 +685 0.17 1 0 +686 0.17 0.99 0 +687 0.16 1 0 +688 0.16 0.99 0 +689 0.15 1 0 +690 0.15 0.99 0 +691 0.14 1 0 +692 0.14 0.99 0 +693 0.13 1 0 +694 0.13 0.99 0 +695 0.12 1 0 +696 0.12 0.99 0 +697 0.11 1 0 +698 0.11 0.99 0 +699 0.1 1 0 +700 0.1 0.99 0 +701 0.09 1 0 +702 0.0900019 0.99 0 +703 0.08 1 0 +704 0.0800028 0.99 0 +705 0.07000000000000001 1 0 +706 0.0700037 0.989999 0 +707 0.06 1 0 +708 0.0600044 0.989999 0 +709 0.05 1 0 +710 0.0500021 0.989999 0 +711 0.04 1 0 +712 0.0400019 0.989999 0 +713 0.03 1 0 +714 0.0300019 0.989999 0 +715 0.02 1 0 +716 0.0200008 0.99 0 +717 0.01 1 0 +718 0.0100002 0.99 0 +719 0 1 0 +720 0 0.99 0 +721 1 0.02 0 +722 0.989998 0.0200003 0 +723 1 0.03 0 +724 0.989998 0.0300004 0 +725 1 0.04 0 +726 0.989999 0.0400006 0 +727 1 0.05 0 +728 0.989999 0.0500006 0 +729 1 0.06 0 +730 0.989999 0.0600006 0 +731 1 0.07000000000000001 0 +732 0.989999 0.0700006 0 +733 1 0.08 0 +734 0.99 0.0800005 0 +735 1 0.09 0 +736 0.99 0.09000039999999999 0 +737 1 0.1 0 +738 0.99 0.1 0 +739 1 0.11 0 +740 0.99 0.11 0 +741 1 0.12 0 +742 0.99 0.12 0 +743 1 0.13 0 +744 0.99 0.13 0 +745 1 0.14 0 +746 0.99 0.14 0 +747 1 0.15 0 +748 0.99 0.15 0 +749 1 0.16 0 +750 0.99 0.16 0 +751 1 0.17 0 +752 0.99 0.17 0 +753 1 0.18 0 +754 0.99 0.18 0 +755 1 0.19 0 +756 0.99 0.19 0 +757 1 0.2 0 +758 0.99 0.2 0 +759 1 0.21 0 +760 0.99 0.21 0 +761 1 0.22 0 +762 0.99 0.22 0 +763 1 0.23 0 +764 0.99 0.23 0 +765 1 0.24 0 +766 0.99 0.24 0 +767 1 0.25 0 +768 0.99 0.25 0 +769 1 0.26 0 +770 0.99 0.26 0 +771 1 0.27 0 +772 0.99 0.27 0 +773 1 0.28 0 +774 0.99 0.28 0 +775 1 0.29 0 +776 0.99 0.29 0 +777 1 0.3 0 +778 0.99 0.3 0 +779 1 0.31 0 +780 0.99 0.31 0 +781 1 0.32 0 +782 0.99 0.32 0 +783 1 0.33 0 +784 0.99 0.33 0 +785 1 0.34 0 +786 0.989994 0.34 0 +787 1 0.35 0 +788 0.989993 0.35 0 +789 1 0.36 0 +790 0.98998 0.36 0 +791 1 0.37 0 +792 0.989971 0.37 0 +793 1 0.38 0 +794 0.989978 0.379999 0 +795 1 0.39 0 +796 0.989988 0.389999 0 +797 1 0.4 0 +798 0.989994 0.4 0 +799 1 0.41 0 +800 0.989998 0.41 0 +801 1 0.42 0 +802 0.989999 0.42 0 +803 1 0.43 0 +804 0.99 0.43 0 +805 1 0.44 0 +806 0.99 0.44 0 +807 1 0.45 0 +808 0.99 0.45 0 +809 1 0.46 0 +810 0.989995 0.46 0 +811 1 0.47 0 +812 0.98999 0.47 0 +813 1 0.48 0 +814 0.989986 0.48 0 +815 1 0.49 0 +816 0.989988 0.490001 0 +817 1 0.5 0 +818 0.989992 0.500001 0 +819 1 0.51 0 +820 0.989996 0.510001 0 +821 1 0.52 0 +822 0.989998 0.520001 0 +823 1 0.53 0 +824 0.989999 0.53 0 +825 1 0.54 0 +826 0.99 0.54 0 +827 1 0.55 0 +828 0.99 0.55 0 +829 1 0.5600000000000001 0 +830 0.99 0.5600000000000001 0 +831 1 0.57 0 +832 0.99 0.57 0 +833 1 0.58 0 +834 0.989996 0.58 0 +835 1 0.59 0 +836 0.989995 0.59 0 +837 1 0.6 0 +838 0.989996 0.6 0 +839 1 0.61 0 +840 0.989998 0.61 0 +841 1 0.62 0 +842 0.989999 0.62 0 +843 1 0.63 0 +844 0.99 0.63 0 +845 1 0.64 0 +846 0.99 0.64 0 +847 1 0.65 0 +848 0.99 0.65 0 +849 1 0.66 0 +850 0.99 0.66 0 +851 1 0.67 0 +852 0.99 0.67 0 +853 1 0.68 0 +854 0.99 0.68 0 +855 1 0.6899999999999999 0 +856 0.99 0.6899999999999999 0 +857 1 0.7 0 +858 0.99 0.7 0 +859 1 0.71 0 +860 0.99 0.71 0 +861 1 0.72 0 +862 0.99 0.72 0 +863 1 0.73 0 +864 0.99 0.73 0 +865 1 0.74 0 +866 0.99 0.74 0 +867 1 0.75 0 +868 0.99 0.75 0 +869 1 0.76 0 +870 0.99 0.76 0 +871 1 0.77 0 +872 0.99 0.77 0 +873 1 0.78 0 +874 0.99 0.78 0 +875 1 0.79 0 +876 0.99 0.79 0 +877 1 0.8 0 +878 0.99 0.8 0 +879 1 0.8100000000000001 0 +880 0.99 0.8100000000000001 0 +881 1 0.82 0 +882 0.99 0.82 0 +883 1 0.83 0 +884 0.99 0.83 0 +885 1 0.84 0 +886 0.99 0.84 0 +887 1 0.85 0 +888 0.99 0.85 0 +889 1 0.86 0 +890 0.99 0.86 0 +891 1 0.87 0 +892 0.99 0.87 0 +893 1 0.88 0 +894 0.99 0.88 0 +895 1 0.89 0 +896 0.99 0.89 0 +897 1 0.9 0 +898 0.99 0.9 0 +899 1 0.91 0 +900 0.99 0.909998 0 +901 1 0.92 0 +902 0.99 0.919996 0 +903 1 0.93 0 +904 0.989998 0.929994 0 +905 1 0.9399999999999999 0 +906 0.989998 0.939992 0 +907 1 0.95 0 +908 0.989997 0.949995 0 +909 1 0.96 0 +910 0.989999 0.959997 0 +911 1 0.97 0 +912 0.989999 0.969998 0 +913 1 0.98 0 +914 0.989999 0.979999 0 +915 0 0.98 0 +916 0.0100011 0.979999 0 +917 0 0.97 0 +918 0.0100011 0.9699989999999999 0 +919 0 0.96 0 +920 0.010001 0.959999 0 +921 0 0.95 0 +922 0.0100009 0.949999 0 +923 0 0.9399999999999999 0 +924 0.0100008 0.939999 0 +925 0 0.93 0 +926 0.0100005 0.929999 0 +927 0 0.92 0 +928 0.0100003 0.92 0 +929 0 0.91 0 +930 0.0100002 0.91 0 +931 0 0.9 0 +932 0.0100001 0.9 0 +933 0 0.89 0 +934 0.01 0.89 0 +935 0 0.88 0 +936 0.00999997 0.88 0 +937 0 0.87 0 +938 0.009999950000000001 0.87 0 +939 0 0.86 0 +940 0.009999950000000001 0.86 0 +941 0 0.85 0 +942 0.00999996 0.85 0 +943 0 0.84 0 +944 0.00999997 0.84 0 +945 0 0.83 0 +946 0.00999998 0.83 0 +947 0 0.82 0 +948 0.00999999 0.82 0 +949 0 0.8100000000000001 0 +950 0.00999999 0.8100000000000001 0 +951 0 0.8 0 +952 0.01 0.8 0 +953 0 0.79 0 +954 0.01 0.79 0 +955 0 0.78 0 +956 0.01 0.78 0 +957 0 0.77 0 +958 0.01 0.77 0 +959 0 0.76 0 +960 0.01 0.76 0 +961 0 0.75 0 +962 0.01 0.75 0 +963 0 0.74 0 +964 0.01 0.74 0 +965 0 0.73 0 +966 0.01 0.73 0 +967 0 0.72 0 +968 0.01 0.72 0 +969 0 0.71 0 +970 0.01 0.71 0 +971 0 0.7 0 +972 0.01 0.7 0 +973 0 0.6899999999999999 0 +974 0.01 0.6899999999999999 0 +975 0 0.68 0 +976 0.01 0.68 0 +977 0 0.67 0 +978 0.01 0.67 0 +979 0 0.66 0 +980 0.01 0.66 0 +981 0 0.65 0 +982 0.01 0.65 0 +983 0 0.64 0 +984 0.01 0.64 0 +985 0 0.63 0 +986 0.01 0.63 0 +987 0 0.62 0 +988 0.01 0.62 0 +989 0 0.61 0 +990 0.01 0.61 0 +991 0 0.6 0 +992 0.01 0.6 0 +993 0 0.59 0 +994 0.0100263 0.59 0 +995 0 0.58 0 +996 0.0100522 0.58 0 +997 0 0.57 0 +998 0.0100634 0.570001 0 +999 0 0.5600000000000001 0 +1000 0.0100824 0.560001 0 +1001 0 0.55 0 +1002 0.0100943 0.550002 0 +1003 0 0.54 0 +1004 0.0100761 0.540002 0 +1005 0 0.53 0 +1006 0.0100541 0.530002 0 +1007 0 0.52 0 +1008 0.0100342 0.520002 0 +1009 0 0.51 0 +1010 0.0100194 0.510002 0 +1011 0 0.5 0 +1012 0.0100204 0.500001 0 +1013 0 0.49 0 +1014 0.0100253 0.49 0 +1015 0 0.48 0 +1016 0.0100188 0.48 0 +1017 0 0.47 0 +1018 0.0100157 0.469999 0 +1019 0 0.46 0 +1020 0.0100114 0.459999 0 +1021 0 0.45 0 +1022 0.0100069 0.449999 0 +1023 0 0.44 0 +1024 0.0100036 0.44 0 +1025 0 0.43 0 +1026 0.0100017 0.43 0 +1027 0 0.42 0 +1028 0.0100129 0.419999 0 +1029 0 0.41 0 +1030 0.0100273 0.409999 0 +1031 0 0.4 0 +1032 0.0100508 0.399999 0 +1033 0 0.39 0 +1034 0.0100729 0.389998 0 +1035 0 0.38 0 +1036 0.0100993 0.379997 0 +1037 0 0.37 0 +1038 0.0100942 0.369997 0 +1039 0 0.36 0 +1040 0.0100967 0.359997 0 +1041 0 0.35 0 +1042 0.0100748 0.349997 0 +1043 0 0.34 0 +1044 0.0100539 0.339998 0 +1045 0 0.33 0 +1046 0.0100354 0.329998 0 +1047 0 0.32 0 +1048 0.0100209 0.319998 0 +1049 0 0.31 0 +1050 0.0100111 0.309999 0 +1051 0 0.3 0 +1052 0.0100054 0.299999 0 +1053 0 0.29 0 +1054 0.0100025 0.289999 0 +1055 0 0.28 0 +1056 0.0100011 0.28 0 +1057 0 0.27 0 +1058 0.0100004 0.27 0 +1059 0 0.26 0 +1060 0.0100002 0.26 0 +1061 0 0.25 0 +1062 0.0100001 0.25 0 +1063 0 0.24 0 +1064 0.01 0.24 0 +1065 0 0.23 0 +1066 0.01 0.23 0 +1067 0 0.22 0 +1068 0.01 0.22 0 +1069 0 0.21 0 +1070 0.01 0.21 0 +1071 0 0.2 0 +1072 0.01 0.2 0 +1073 0 0.19 0 +1074 0.01 0.19 0 +1075 0 0.18 0 +1076 0.01 0.18 0 +1077 0 0.17 0 +1078 0.01 0.17 0 +1079 0 0.16 0 +1080 0.01 0.16 0 +1081 0 0.15 0 +1082 0.00999999 0.15 0 +1083 0 0.14 0 +1084 0.00999999 0.14 0 +1085 0 0.13 0 +1086 0.00999997 0.13 0 +1087 0 0.12 0 +1088 0.00999996 0.12 0 +1089 0 0.11 0 +1090 0.009999940000000001 0.11 0 +1091 0 0.1 0 +1092 0.009999910000000001 0.100001 0 +1093 0 0.09 0 +1094 0.009999940000000001 0.0900006 0 +1095 0 0.08 0 +1096 0.0100006 0.0800025 0 +1097 0 0.07000000000000001 0 +1098 0.010001 0.0700025 0 +1099 0 0.06 0 +1100 0.0100012 0.060002 0 +1101 0 0.05 0 +1102 0.0100009 0.0500014 0 +1103 0 0.04 0 +1104 0.0100007 0.0400001 0 +1105 0 0.03 0 +1106 0.0100006 0.03 0 +1107 0 0.02 0 +1108 0.0100004 0.0200002 0 +1109 0.232201 0.521468 0 +1110 0.231561 0.510945 0 +1111 0.233161 0.531917 0 +1112 0.234473 0.542333 0 +1113 0.23618 0.552677 0 +1114 0.23837 0.562863 0 +1115 0.241077 0.572807 0 +1116 0.244285 0.582539 0 +1117 0.247874 0.592086 0 +1118 0.251694 0.601454 0 +1119 0.255726 0.610762 0 +1120 0.259661 0.620003 0 +1121 0.263416 0.629968 0 +1122 0.266456 0.642687 0 +1123 0.283429 0.661433 0 +1124 0.275967 0.652857 0 +1125 0.290426 0.669467 0 +1126 0.297451 0.677392 0 +1127 0.304577 0.685059 0 +1128 0.311903 0.692461 0 +1129 0.319413 0.699512 0 +1130 0.327205 0.706205 0 +1131 0.335221 0.712596 0 +1132 0.343434 0.718736 0 +1133 0.35184 0.724787 0 +1134 0.360238 0.73082 0 +1135 0.369037 0.737443 0 +1136 0.379214 0.746364 0 +1137 0.392462 0.748829 0 +1138 0.403149 0.751347 0 +1139 0.412936 0.753925 0 +1140 0.422638 0.756664 0 +1141 0.432217 0.759281 0 +1142 0.44176 0.761668 0 +1143 0.45131 0.763678 0 +1144 0.460862 0.765357 0 +1145 0.470433 0.766717 0 +1146 0.480081 0.767877 0 +1147 0.489814 0.769082 0 +1148 0.499443 0.771129 0 +1149 0.509203 0.774613 0 +1150 0.541347 0.765666 0 +1151 0.532534 0.768471 0 +1152 0.550523 0.763682 0 +1153 0.560126 0.761911 0 +1154 0.569844 0.75985 0 +1155 0.579596 0.757337 0 +1156 0.5893119999999999 0.754297 0 +1157 0.598855 0.750628 0 +1158 0.608224 0.746565 0 +1159 0.6175079999999999 0.742173 0 +1160 0.62678 0.737625 0 +1161 0.635991 0.7331800000000001 0 +1162 0.645884 0.7287130000000001 0 +1163 0.658353 0.724631 0 +1164 0.666889 0.714104 0 +1165 0.674534 0.706158 0 +1166 0.68189 0.698788 0 +1167 0.689021 0.691538 0 +1168 0.695892 0.68429 0 +1169 0.702471 0.676919 0 +1170 0.70871 0.669372 0 +1171 0.714668 0.661621 0 +1172 0.720504 0.653774 0 +1173 0.726491 0.645895 0 +1174 0.733156 0.638513 0 +1175 0.741135 0.63171 0 +1176 0.749032 0.599643 0 +1177 0.747155 0.608584 0 +1178 0.751877 0.590809 0 +1179 0.7552140000000001 0.581716 0 +1180 0.758444 0.572344 0 +1181 0.761341 0.562715 0 +1182 0.763779 0.552818 0 +1183 0.765671 0.542734 0 +1184 0.767135 0.532487 0 +1185 0.768355 0.522103 0 +1186 0.769477 0.5114300000000001 0 +1187 0.770451 0.500731 0 +1188 0.771025 0.489183 0 +1189 0.769466 0.477714 0 +1190 0.76755 0.467163 0 +1191 0.765513 0.456707 0 +1192 0.763388 0.446503 0 +1193 0.76109 0.436492 0 +1194 0.758548 0.426654 0 +1195 0.755659 0.41701 0 +1196 0.752404 0.407598 0 +1197 0.748806 0.398389 0 +1198 0.745065 0.389333 0 +1199 0.7413149999999999 0.380367 0 +1200 0.738966 0.371146 0 +1201 0.738104 0.361418 0 +1202 0.715242 0.335925 0 +1203 0.722428 0.342888 0 +1204 0.708402 0.328695 0 +1205 0.7016019999999999 0.321321 0 +1206 0.6946329999999999 0.313994 0 +1207 0.687434 0.3068 0 +1208 0.679993 0.299783 0 +1209 0.6722860000000001 0.293003 0 +1210 0.664323 0.286456 0 +1211 0.656107 0.28015 0 +1212 0.6475959999999999 0.274086 0 +1213 0.638768 0.268155 0 +1214 0.629628 0.262446 0 +1215 0.6196970000000001 0.256791 0 +1216 0.608853 0.252854 0 +1217 0.59854 0.24943 0 +1218 0.588728 0.246186 0 +1219 0.578838 0.243126 0 +1220 0.568999 0.240402 0 +1221 0.559148 0.238044 0 +1222 0.549389 0.236068 0 +1223 0.539638 0.234424 0 +1224 0.529881 0.233068 0 +1225 0.520174 0.231924 0 +1226 0.510516 0.230742 0 +1227 0.501183 0.228436 0 +1228 0.491898 0.225 0 +1229 0.45839 0.232908 0 +1230 0.467909 0.229786 0 +1231 0.448796 0.235519 0 +1232 0.439036 0.237905 0 +1233 0.429234 0.240492 0 +1234 0.419412 0.24333 0 +1235 0.409593 0.246526 0 +1236 0.399842 0.25014 0 +1237 0.390242 0.254322 0 +1238 0.380778 0.258954 0 +1239 0.371451 0.263912 0 +1240 0.362331 0.269191 0 +1241 0.353392 0.27476 0 +1242 0.344704 0.280614 0 +1243 0.336234 0.286791 0 +1244 0.328018 0.293259 0 +1245 0.320046 0.299899 0 +1246 0.312364 0.306821 0 +1247 0.305059 0.314018 0 +1248 0.298225 0.321583 0 +1249 0.291744 0.32934 0 +1250 0.285538 0.337129 0 +1251 0.279442 0.344902 0 +1252 0.273246 0.352626 0 +1253 0.266176 0.35958 0 +1254 0.258178 0.365979 0 +1255 0.248394 0.399678 0 +1256 0.250292 0.389778 0 +1257 0.24608 0.409251 0 +1258 0.243427 0.418899 0 +1259 0.240852 0.428643 0 +1260 0.238437 0.438502 0 +1261 0.236201 0.4485 0 +1262 0.234279 0.458628 0 +1263 0.232793 0.468925 0 +1264 0.231849 0.47935 0 +1265 0.231374 0.489871 0 +1266 0.231298 0.500418 0 +1267 0.250229 0.379369 0 +1268 0.247444 0.369309 0 +1269 0.477065 0.225244 0 +1270 0.484306 0.218214 0 +1271 0.730918 0.348677 0 +1272 0.740252 0.351979 0 +1273 0.7475270000000001 0.618127 0 +1274 0.750881 0.62735 0 +1275 0.524248 0.773517 0 +1276 0.517602 0.780991 0 +1277 0.979997 0.0200009 0 +1278 0.979997 0.030001 0 +1279 0.979998 0.0400011 0 +1280 0.979998 0.0500012 0 +1281 0.979998 0.0600012 0 +1282 0.979999 0.0700011 0 +1283 0.979999 0.080001 0 +1284 0.979999 0.09000080000000001 0 +1285 0.98 0.100001 0 +1286 0.98 0.110001 0 +1287 0.98 0.12 0 +1288 0.98 0.13 0 +1289 0.98 0.14 0 +1290 0.98 0.15 0 +1291 0.98 0.16 0 +1292 0.98 0.17 0 +1293 0.98 0.18 0 +1294 0.98 0.19 0 +1295 0.98 0.2 0 +1296 0.98 0.21 0 +1297 0.98 0.22 0 +1298 0.98 0.23 0 +1299 0.98 0.24 0 +1300 0.98 0.25 0 +1301 0.98 0.26 0 +1302 0.98 0.27 0 +1303 0.98 0.28 0 +1304 0.98 0.29 0 +1305 0.98 0.3 0 +1306 0.98 0.31 0 +1307 0.9799949999999999 0.32 0 +1308 0.979965 0.329999 0 +1309 0.979961 0.339998 0 +1310 0.979914 0.349997 0 +1311 0.979893 0.359996 0 +1312 0.979904 0.369995 0 +1313 0.979915 0.379996 0 +1314 0.9799290000000001 0.389996 0 +1315 0.979958 0.399996 0 +1316 0.97998 0.409997 0 +1317 0.9799909999999999 0.419998 0 +1318 0.979997 0.429999 0 +1319 0.979993 0.439999 0 +1320 0.979967 0.450001 0 +1321 0.979945 0.460002 0 +1322 0.979927 0.470004 0 +1323 0.979934 0.480005 0 +1324 0.979951 0.490005 0 +1325 0.979961 0.500005 0 +1326 0.979965 0.510006 0 +1327 0.979978 0.520006 0 +1328 0.9799949999999999 0.530007 0 +1329 0.980001 0.540007 0 +1330 0.980002 0.550006 0 +1331 0.980001 0.560005 0 +1332 0.979985 0.570003 0 +1333 0.97998 0.580002 0 +1334 0.979976 0.590002 0 +1335 0.97998 0.600001 0 +1336 0.9799870000000001 0.610001 0 +1337 0.979993 0.620001 0 +1338 0.979996 0.63 0 +1339 0.979998 0.64 0 +1340 0.979999 0.65 0 +1341 0.98 0.66 0 +1342 0.98 0.67 0 +1343 0.98 0.68 0 +1344 0.98 0.6899999999999999 0 +1345 0.98 0.7 0 +1346 0.98 0.71 0 +1347 0.98 0.72 0 +1348 0.98 0.73 0 +1349 0.98 0.74 0 +1350 0.98 0.75 0 +1351 0.98 0.76 0 +1352 0.98 0.77 0 +1353 0.98 0.78 0 +1354 0.98 0.79 0 +1355 0.98 0.8 0 +1356 0.98 0.8100000000000001 0 +1357 0.98 0.82 0 +1358 0.98 0.83 0 +1359 0.98 0.84 0 +1360 0.98 0.85 0 +1361 0.98 0.86 0 +1362 0.98 0.87 0 +1363 0.98 0.88 0 +1364 0.98 0.89 0 +1365 0.98 0.899999 0 +1366 0.98 0.909996 0 +1367 0.979998 0.919992 0 +1368 0.979997 0.929989 0 +1369 0.979996 0.939991 0 +1370 0.979997 0.949993 0 +1371 0.979998 0.959995 0 +1372 0.979998 0.969997 0 +1373 0.979999 0.979998 0 +1374 0.969998 0.979997 0 +1375 0.959998 0.979997 0 +1376 0.949998 0.979997 0 +1377 0.939998 0.979998 0 +1378 0.929998 0.979998 0 +1379 0.919998 0.979999 0 +1380 0.909998 0.979999 0 +1381 0.899999 0.98 0 +1382 0.889999 0.98 0 +1383 0.879999 0.98 0 +1384 0.869999 0.98 0 +1385 0.86 0.98 0 +1386 0.85 0.98 0 +1387 0.84 0.98 0 +1388 0.83 0.98 0 +1389 0.82 0.98 0 +1390 0.8100000000000001 0.98 0 +1391 0.8 0.98 0 +1392 0.79 0.98 0 +1393 0.78 0.98 0 +1394 0.77 0.98 0 +1395 0.76 0.98 0 +1396 0.75 0.98 0 +1397 0.74 0.98 0 +1398 0.73 0.98 0 +1399 0.72 0.98 0 +1400 0.71 0.98 0 +1401 0.7 0.98 0 +1402 0.6899999999999999 0.98 0 +1403 0.68 0.98 0 +1404 0.67 0.98 0 +1405 0.66 0.98 0 +1406 0.65 0.98 0 +1407 0.64 0.98 0 +1408 0.63 0.98 0 +1409 0.62 0.98 0 +1410 0.61 0.98 0 +1411 0.6 0.98 0 +1412 0.59 0.979989 0 +1413 0.58 0.979981 0 +1414 0.570001 0.979969 0 +1415 0.560001 0.979942 0 +1416 0.550003 0.979884 0 +1417 0.540007 0.979812 0 +1418 0.530013 0.979748 0 +1419 0.520015 0.979729 0 +1420 0.510018 0.979764 0 +1421 0.500017 0.979818 0 +1422 0.490015 0.979871 0 +1423 0.480012 0.9799099999999999 0 +1424 0.47001 0.979932 0 +1425 0.460008 0.979931 0 +1426 0.450008 0.9799020000000001 0 +1427 0.440008 0.979867 0 +1428 0.430007 0.9798829999999999 0 +1429 0.420006 0.97988 0 +1430 0.410004 0.979897 0 +1431 0.400002 0.979884 0 +1432 0.390001 0.979897 0 +1433 0.379999 0.979887 0 +1434 0.369997 0.979898 0 +1435 0.359996 0.9799020000000001 0 +1436 0.349996 0.979908 0 +1437 0.339994 0.979898 0 +1438 0.329994 0.979907 0 +1439 0.319995 0.979926 0 +1440 0.309995 0.979943 0 +1441 0.299996 0.979957 0 +1442 0.289997 0.979971 0 +1443 0.279997 0.979984 0 +1444 0.269998 0.979992 0 +1445 0.259999 0.979996 0 +1446 0.249999 0.979998 0 +1447 0.239999 0.979999 0 +1448 0.229999 0.98 0 +1449 0.22 0.98 0 +1450 0.21 0.98 0 +1451 0.2 0.98 0 +1452 0.19 0.98 0 +1453 0.18 0.98 0 +1454 0.17 0.98 0 +1455 0.16 0.98 0 +1456 0.15 0.98 0 +1457 0.14 0.98 0 +1458 0.13 0.98 0 +1459 0.12 0.98 0 +1460 0.11 0.98 0 +1461 0.100001 0.98 0 +1462 0.09000329999999999 0.98 0 +1463 0.0800051 0.979999 0 +1464 0.07000580000000001 0.979998 0 +1465 0.0600061 0.979998 0 +1466 0.0500033 0.979998 0 +1467 0.0400028 0.979998 0 +1468 0.0300025 0.979999 0 +1469 0.0200018 0.979999 0 +1470 0.0200007 0.0200004 0 +1471 0.0300008 0.0200008 0 +1472 0.0400009 0.0200011 0 +1473 0.050001 0.0200009 0 +1474 0.0600009 0.0200007 0 +1475 0.0700008 0.0200005 0 +1476 0.08000069999999999 0.0200003 0 +1477 0.0900006 0.0200001 0 +1478 0.100001 0.02 0 +1479 0.11 0.0199999 0 +1480 0.12 0.0199999 0 +1481 0.13 0.0199999 0 +1482 0.14 0.0199999 0 +1483 0.15 0.0199999 0 +1484 0.16 0.02 0 +1485 0.17 0.02 0 +1486 0.18 0.02 0 +1487 0.19 0.02 0 +1488 0.2 0.02 0 +1489 0.21 0.02 0 +1490 0.22 0.02 0 +1491 0.23 0.02 0 +1492 0.24 0.02 0 +1493 0.25 0.02 0 +1494 0.26 0.02 0 +1495 0.27 0.02 0 +1496 0.28 0.02 0 +1497 0.29 0.02 0 +1498 0.3 0.02 0 +1499 0.31 0.0200043 0 +1500 0.32 0.0200109 0 +1501 0.33 0.0200109 0 +1502 0.34 0.0200075 0 +1503 0.35 0.0200042 0 +1504 0.36 0.0200156 0 +1505 0.370001 0.0200244 0 +1506 0.380001 0.0200187 0 +1507 0.390001 0.0200297 0 +1508 0.400001 0.0200286 0 +1509 0.410001 0.0200185 0 +1510 0.420001 0.0200096 0 +1511 0.43 0.0200043 0 +1512 0.44 0.0200018 0 +1513 0.45 0.0200007 0 +1514 0.46 0.0200002 0 +1515 0.47 0.0200001 0 +1516 0.48 0.02 0 +1517 0.490002 0.0200552 0 +1518 0.500003 0.0200978 0 +1519 0.510003 0.0201416 0 +1520 0.520003 0.0201808 0 +1521 0.530002 0.0202074 0 +1522 0.540002 0.0201946 0 +1523 0.550001 0.0201785 0 +1524 0.5600000000000001 0.020147 0 +1525 0.57 0.0201158 0 +1526 0.58 0.0200794 0 +1527 0.59 0.020055 0 +1528 0.6 0.0200371 0 +1529 0.61 0.0200223 0 +1530 0.620001 0.0200208 0 +1531 0.630001 0.0200201 0 +1532 0.640001 0.0200213 0 +1533 0.6500010000000001 0.0200223 0 +1534 0.6600009999999999 0.0200174 0 +1535 0.670001 0.0200107 0 +1536 0.680001 0.0200056 0 +1537 0.690001 0.02 0 +1538 0.7 0.0199985 0 +1539 0.71 0.019997 0 +1540 0.7199989999999999 0.0199971 0 +1541 0.729999 0.019998 0 +1542 0.739999 0.0199989 0 +1543 0.749999 0.0199995 0 +1544 0.759999 0.0199998 0 +1545 0.77 0.0199999 0 +1546 0.78 0.02 0 +1547 0.79 0.02 0 +1548 0.8 0.02 0 +1549 0.8100000000000001 0.02 0 +1550 0.82 0.02 0 +1551 0.83 0.02 0 +1552 0.84 0.02 0 +1553 0.85 0.02 0 +1554 0.86 0.02 0 +1555 0.87 0.0199999 0 +1556 0.88 0.0199998 0 +1557 0.889999 0.0199997 0 +1558 0.899997 0.0199996 0 +1559 0.909996 0.0200003 0 +1560 0.919995 0.0200016 0 +1561 0.929994 0.0200027 0 +1562 0.9399960000000001 0.020002 0 +1563 0.949997 0.0200012 0 +1564 0.959997 0.0200015 0 +1565 0.969997 0.0200013 0 +1566 0.0200021 0.9699989999999999 0 +1567 0.020002 0.959999 0 +1568 0.0200018 0.949999 0 +1569 0.0200014 0.939999 0 +1570 0.0200011 0.929999 0 +1571 0.0200007 0.919999 0 +1572 0.0200004 0.909999 0 +1573 0.0200002 0.899999 0 +1574 0.0200001 0.89 0 +1575 0.02 0.88 0 +1576 0.0199999 0.87 0 +1577 0.0199999 0.86 0 +1578 0.0199999 0.85 0 +1579 0.0199999 0.84 0 +1580 0.02 0.83 0 +1581 0.02 0.82 0 +1582 0.02 0.8100000000000001 0 +1583 0.02 0.8 0 +1584 0.02 0.79 0 +1585 0.02 0.78 0 +1586 0.02 0.77 0 +1587 0.02 0.76 0 +1588 0.02 0.75 0 +1589 0.02 0.74 0 +1590 0.02 0.73 0 +1591 0.02 0.72 0 +1592 0.02 0.71 0 +1593 0.02 0.7 0 +1594 0.02 0.6899999999999999 0 +1595 0.02 0.68 0 +1596 0.02 0.67 0 +1597 0.02 0.66 0 +1598 0.02 0.65 0 +1599 0.02 0.64 0 +1600 0.02 0.63 0 +1601 0.02 0.62 0 +1602 0.02 0.61 0 +1603 0.020041 0.600001 0 +1604 0.0200818 0.590001 0 +1605 0.0201138 0.580003 0 +1606 0.0201644 0.570006 0 +1607 0.0202108 0.560008 0 +1608 0.0202021 0.550009 0 +1609 0.0201669 0.540009 0 +1610 0.0201257 0.530008 0 +1611 0.0200884 0.520006 0 +1612 0.02009 0.51 0 +1613 0.0200932 0.499995 0 +1614 0.0200713 0.489992 0 +1615 0.020076 0.47999 0 +1616 0.0200623 0.469989 0 +1617 0.0200504 0.459989 0 +1618 0.020033 0.44999 0 +1619 0.0200201 0.439991 0 +1620 0.02005 0.42999 0 +1621 0.020083 0.419988 0 +1622 0.0201255 0.409987 0 +1623 0.0201738 0.399986 0 +1624 0.0202009 0.389984 0 +1625 0.02023 0.379984 0 +1626 0.0202546 0.369984 0 +1627 0.0202179 0.359986 0 +1628 0.0201709 0.349988 0 +1629 0.0201311 0.33999 0 +1630 0.0200935 0.329992 0 +1631 0.0200596 0.319994 0 +1632 0.020034 0.309995 0 +1633 0.0200177 0.299996 0 +1634 0.0200085 0.289997 0 +1635 0.0200039 0.279998 0 +1636 0.0200017 0.269999 0 +1637 0.0200007 0.259999 0 +1638 0.0200003 0.249999 0 +1639 0.0200001 0.24 0 +1640 0.02 0.23 0 +1641 0.02 0.22 0 +1642 0.02 0.21 0 +1643 0.02 0.2 0 +1644 0.02 0.19 0 +1645 0.02 0.18 0 +1646 0.02 0.17 0 +1647 0.02 0.16 0 +1648 0.02 0.15 0 +1649 0.02 0.14 0 +1650 0.0199999 0.13 0 +1651 0.0199999 0.12 0 +1652 0.0199999 0.11 0 +1653 0.0199999 0.100001 0 +1654 0.0200004 0.0900019 0 +1655 0.0200013 0.08000400000000001 0 +1656 0.0200017 0.0700032 0 +1657 0.0200018 0.0600023 0 +1658 0.0200013 0.0500017 0 +1659 0.0200011 0.0400009 0 +1660 0.0200009 0.0300006 0 +1661 0.26055 0.65378 0 +1662 0.268832 0.661053 0 +1663 0.969997 0.0300015 0 +1664 0.969997 0.0400016 0 +1665 0.969997 0.0500017 0 +1666 0.969998 0.0600016 0 +1667 0.969998 0.07000149999999999 0 +1668 0.9699989999999999 0.0800014 0 +1669 0.9699989999999999 0.0900012 0 +1670 0.97 0.100001 0 +1671 0.97 0.110001 0 +1672 0.97 0.120001 0 +1673 0.97 0.13 0 +1674 0.97 0.14 0 +1675 0.97 0.15 0 +1676 0.97 0.16 0 +1677 0.97 0.17 0 +1678 0.97 0.18 0 +1679 0.97 0.19 0 +1680 0.97 0.2 0 +1681 0.97 0.21 0 +1682 0.97 0.22 0 +1683 0.97 0.23 0 +1684 0.97 0.24 0 +1685 0.97 0.25 0 +1686 0.97 0.26 0 +1687 0.97 0.27 0 +1688 0.97 0.28 0 +1689 0.97 0.29 0 +1690 0.97 0.3 0 +1691 0.969975 0.309998 0 +1692 0.969915 0.319993 0 +1693 0.969901 0.329989 0 +1694 0.96982 0.339983 0 +1695 0.969777 0.34998 0 +1696 0.969759 0.35998 0 +1697 0.969758 0.36998 0 +1698 0.9697750000000001 0.379982 0 +1699 0.9698369999999999 0.389985 0 +1700 0.969895 0.399988 0 +1701 0.969942 0.40999 0 +1702 0.969971 0.419993 0 +1703 0.969966 0.429996 0 +1704 0.9699140000000001 0.440003 0 +1705 0.969868 0.450008 0 +1706 0.969825 0.460013 0 +1707 0.969823 0.470015 0 +1708 0.9698329999999999 0.480019 0 +1709 0.969847 0.490024 0 +1710 0.969866 0.5000289999999999 0 +1711 0.969921 0.510035 0 +1712 0.969979 0.520041 0 +1713 0.970005 0.530039 0 +1714 0.9700220000000001 0.540035 0 +1715 0.970027 0.550031 0 +1716 0.969992 0.560026 0 +1717 0.969958 0.570021 0 +1718 0.969929 0.580017 0 +1719 0.969935 0.590012 0 +1720 0.969949 0.600009 0 +1721 0.969966 0.610006 0 +1722 0.969979 0.620004 0 +1723 0.969989 0.630003 0 +1724 0.9699950000000001 0.640002 0 +1725 0.969998 0.6500010000000001 0 +1726 0.9699989999999999 0.6600009999999999 0 +1727 0.97 0.670001 0 +1728 0.97 0.68 0 +1729 0.97 0.6899999999999999 0 +1730 0.97 0.7 0 +1731 0.97 0.71 0 +1732 0.97 0.72 0 +1733 0.97 0.73 0 +1734 0.97 0.74 0 +1735 0.97 0.75 0 +1736 0.97 0.76 0 +1737 0.97 0.77 0 +1738 0.97 0.78 0 +1739 0.97 0.79 0 +1740 0.97 0.8 0 +1741 0.97 0.8100000000000001 0 +1742 0.97 0.82 0 +1743 0.97 0.83 0 +1744 0.97 0.84 0 +1745 0.97 0.85 0 +1746 0.97 0.86 0 +1747 0.97 0.87 0 +1748 0.97 0.88 0 +1749 0.97 0.889999 0 +1750 0.97 0.899997 0 +1751 0.9699989999999999 0.909994 0 +1752 0.969997 0.919991 0 +1753 0.969996 0.929989 0 +1754 0.969996 0.939991 0 +1755 0.969996 0.949993 0 +1756 0.969997 0.959995 0 +1757 0.969997 0.969996 0 +1758 0.276264 0.668721 0 +1759 0.283398 0.676643 0 +1760 0.290517 0.684508 0 +1761 0.297744 0.692235 0 +1762 0.305128 0.699709 0 +1763 0.312761 0.706874 0 +1764 0.32069 0.713608 0 +1765 0.328811 0.719985 0 +1766 0.337069 0.726114 0 +1767 0.345371 0.7320990000000001 0 +1768 0.353617 0.738093 0 +1769 0.361254 0.744568 0 +1770 0.36786 0.752491 0 +1771 0.402071 0.76088 0 +1772 0.392215 0.7596309999999999 0 +1773 0.411728 0.763108 0 +1774 0.421151 0.76567 0 +1775 0.430506 0.7682870000000001 0 +1776 0.439858 0.770676 0 +1777 0.449234 0.772732 0 +1778 0.458618 0.77442 0 +1779 0.468003 0.775779 0 +1780 0.477378 0.776918 0 +1781 0.486693 0.778125 0 +1782 0.495645 0.780281 0 +1783 0.50429 0.783538 0 +1784 0.512009 0.788596 0 +1785 0.524914 0.787301 0 +1786 0.519274 0.7942630000000001 0 +1787 0.530682 0.780837 0 +1788 0.536865 0.776 0 +1789 0.544401 0.7738699999999999 0 +1790 0.553211 0.772668 0 +1791 0.562654 0.771311 0 +1792 0.572483 0.76944 0 +1793 0.5824549999999999 0.7670979999999999 0 +1794 0.592421 0.764063 0 +1795 0.602096 0.76027 0 +1796 0.6115620000000001 0.755979 0 +1797 0.620865 0.751464 0 +1798 0.63001 0.7469519999999999 0 +1799 0.639086 0.742567 0 +1800 0.6482 0.739447 0 +1801 0.657872 0.737704 0 +1802 0.682527 0.712411 0 +1803 0.676025 0.720379 0 +1804 0.689503 0.705108 0 +1805 0.696425 0.697942 0 +1806 0.703192 0.690731 0 +1807 0.709658 0.683404 0 +1808 0.71577 0.67588 0 +1809 0.721562 0.668215 0 +1810 0.72722 0.660532 0 +1811 0.732935 0.65304 0 +1812 0.739352 0.6461980000000001 0 +1813 0.74659 0.640188 0 +1814 0.754923 0.635756 0 +1815 0.75993 0.623825 0 +1816 0.7636269999999999 0.631983 0 +1817 0.756908 0.615897 0 +1818 0.755602 0.608332 0 +1819 0.757339 0.600863 0 +1820 0.760579 0.592718 0 +1821 0.764173 0.58402 0 +1822 0.767652 0.574754 0 +1823 0.7708429999999999 0.565068 0 +1824 0.773485 0.555033 0 +1825 0.7753949999999999 0.5447340000000001 0 +1826 0.776848 0.534312 0 +1827 0.7781090000000001 0.523746 0 +1828 0.779425 0.513235 0 +1829 0.781103 0.502109 0 +1830 0.784084 0.488688 0 +1831 0.779955 0.475429 0 +1832 0.777134 0.464455 0 +1833 0.774803 0.454198 0 +1834 0.772589 0.443994 0 +1835 0.7703449999999999 0.433931 0 +1836 0.7678739999999999 0.424023 0 +1837 0.765046 0.414318 0 +1838 0.761718 0.404893 0 +1839 0.75813 0.39577 0 +1840 0.754352 0.386952 0 +1841 0.7509400000000001 0.378367 0 +1842 0.748403 0.369999 0 +1843 0.747712 0.361677 0 +1844 0.748968 0.35362 0 +1845 0.743461 0.343854 0 +1846 0.751173 0.346073 0 +1847 0.735729 0.340148 0 +1848 0.728668 0.334616 0 +1849 0.721751 0.328194 0 +1850 0.715097 0.321093 0 +1851 0.708249 0.313853 0 +1852 0.70118 0.306569 0 +1853 0.693919 0.299301 0 +1854 0.686414 0.292158 0 +1855 0.678608 0.285241 0 +1856 0.6705759999999999 0.278533 0 +1857 0.662297 0.272075 0 +1858 0.653755 0.265835 0 +1859 0.644965 0.25987 0 +1860 0.635758 0.253532 0 +1861 0.625038 0.245157 0 +1862 0.611658 0.242878 0 +1863 0.601044 0.240062 0 +1864 0.591101 0.236962 0 +1865 0.581342 0.233901 0 +1866 0.571481 0.231179 0 +1867 0.561627 0.228839 0 +1868 0.551823 0.226863 0 +1869 0.542066 0.22521 0 +1870 0.532427 0.22387 0 +1871 0.522967 0.222747 0 +1872 0.513802 0.221337 0 +1873 0.505035 0.219239 0 +1874 0.49692 0.21576 0 +1875 0.489787 0.211015 0 +1876 0.478308 0.21149 0 +1877 0.483571 0.205252 0 +1878 0.471558 0.216719 0 +1879 0.463448 0.220555 0 +1880 0.454649 0.223788 0 +1881 0.445264 0.226246 0 +1882 0.435622 0.228708 0 +1883 0.425802 0.231308 0 +1884 0.415849 0.234164 0 +1885 0.405794 0.237263 0 +1886 0.395778 0.240935 0 +1887 0.385905 0.245328 0 +1888 0.376197 0.250204 0 +1889 0.366647 0.255411 0 +1890 0.357282 0.260859 0 +1891 0.348119 0.266574 0 +1892 0.339165 0.272587 0 +1893 0.330459 0.278921 0 +1894 0.321996 0.285467 0 +1895 0.313701 0.292207 0 +1896 0.305718 0.299158 0 +1897 0.298196 0.306488 0 +1898 0.291294 0.314216 0 +1899 0.284863 0.322077 0 +1900 0.278708 0.329825 0 +1901 0.272679 0.337411 0 +1902 0.266407 0.344564 0 +1903 0.259774 0.35114 0 +1904 0.25197 0.356507 0 +1905 0.243562 0.360485 0 +1906 0.237914 0.371374 0 +1907 0.235193 0.363189 0 +1908 0.239441 0.380272 0 +1909 0.239274 0.389501 0 +1910 0.237983 0.398744 0 +1911 0.236074 0.408032 0 +1912 0.233705 0.417587 0 +1913 0.231324 0.427336 0 +1914 0.228934 0.437256 0 +1915 0.226637 0.447333 0 +1916 0.224531 0.457652 0 +1917 0.222915 0.468194 0 +1918 0.222009 0.478948 0 +1919 0.221646 0.489793 0 +1920 0.221672 0.500641 0 +1921 0.222021 0.511474 0 +1922 0.222665 0.52224 0 +1923 0.223585 0.532998 0 +1924 0.224822 0.543733 0 +1925 0.226445 0.554391 0 +1926 0.228547 0.564859 0 +1927 0.231419 0.575023 0 +1928 0.234867 0.58486 0 +1929 0.238652 0.59441 0 +1930 0.24266 0.603675 0 +1931 0.24671 0.61272 0 +1932 0.250471 0.62152 0 +1933 0.25323 0.63046 0 +1934 0.25417 0.639903 0 +1935 0.251157 0.648797 0 +1936 0.254518 0.662191 0 +1937 0.246638 0.656574 0 +1938 0.262163 0.668851 0 +1939 0.381533 0.759647 0 +1940 0.37136 0.762103 0 +1941 0.670269 0.729421 0 +1942 0.667418 0.739615 0 +1943 0.0300026 0.969998 0 +1944 0.0300026 0.959998 0 +1945 0.0300024 0.949998 0 +1946 0.030002 0.939998 0 +1947 0.0300015 0.929999 0 +1948 0.0300011 0.919999 0 +1949 0.0300007 0.909999 0 +1950 0.0300004 0.899999 0 +1951 0.0300001 0.889999 0 +1952 0.03 0.88 0 +1953 0.0299999 0.87 0 +1954 0.0299999 0.86 0 +1955 0.0299999 0.85 0 +1956 0.0299999 0.84 0 +1957 0.0299999 0.83 0 +1958 0.03 0.82 0 +1959 0.03 0.8100000000000001 0 +1960 0.03 0.8 0 +1961 0.03 0.79 0 +1962 0.03 0.78 0 +1963 0.03 0.77 0 +1964 0.03 0.76 0 +1965 0.03 0.75 0 +1966 0.03 0.74 0 +1967 0.03 0.73 0 +1968 0.0300057 0.72 0 +1969 0.0300112 0.71 0 +1970 0.030016 0.7 0 +1971 0.030014 0.6899999999999999 0 +1972 0.030009 0.68 0 +1973 0.0300049 0.67 0 +1974 0.0300023 0.66 0 +1975 0.030001 0.65 0 +1976 0.0300004 0.64 0 +1977 0.0300002 0.63 0 +1978 0.0299868 0.62 0 +1979 0.0300103 0.610002 0 +1980 0.0300603 0.600004 0 +1981 0.0301222 0.590011 0 +1982 0.0302138 0.580018 0 +1983 0.0303294 0.570022 0 +1984 0.0303577 0.560023 0 +1985 0.0303102 0.550021 0 +1986 0.0302633 0.540017 0 +1987 0.0302017 0.530006 0 +1988 0.0301795 0.519985 0 +1989 0.0301733 0.509972 0 +1990 0.0301531 0.499964 0 +1991 0.0301661 0.489956 0 +1992 0.0301442 0.479949 0 +1993 0.0301306 0.46995 0 +1994 0.03009 0.459951 0 +1995 0.0300631 0.449956 0 +1996 0.0300825 0.43995 0 +1997 0.0301183 0.429949 0 +1998 0.0301862 0.419947 0 +1999 0.0302701 0.409944 0 +2000 0.0303272 0.399944 0 +2001 0.0304122 0.389946 0 +2002 0.0304913 0.379945 0 +2003 0.030471 0.36995 0 +2004 0.0304215 0.359955 0 +2005 0.0303609 0.349961 0 +2006 0.0302704 0.339967 0 +2007 0.0301883 0.329974 0 +2008 0.0301254 0.319979 0 +2009 0.0300816 0.309983 0 +2010 0.0300477 0.299987 0 +2011 0.0300251 0.28999 0 +2012 0.0300121 0.279993 0 +2013 0.0300055 0.269995 0 +2014 0.0300023 0.259996 0 +2015 0.030001 0.249997 0 +2016 0.0300004 0.239998 0 +2017 0.0300001 0.229999 0 +2018 0.0300001 0.219999 0 +2019 0.03 0.21 0 +2020 0.03 0.2 0 +2021 0.03 0.19 0 +2022 0.03 0.18 0 +2023 0.03 0.17 0 +2024 0.03 0.16 0 +2025 0.03 0.15 0 +2026 0.0299999 0.14 0 +2027 0.0299999 0.13 0 +2028 0.0299998 0.12 0 +2029 0.0299998 0.110001 0 +2030 0.0300003 0.100001 0 +2031 0.0300008 0.0900026 0 +2032 0.0300016 0.0800042 0 +2033 0.030002 0.07000290000000001 0 +2034 0.0300019 0.0600022 0 +2035 0.0300016 0.0500018 0 +2036 0.0300015 0.0400014 0 +2037 0.0300012 0.0300012 0 +2038 0.959997 0.969996 0 +2039 0.949997 0.969996 0 +2040 0.939997 0.969997 0 +2041 0.929997 0.969998 0 +2042 0.919998 0.9699989999999999 0 +2043 0.909998 0.9699989999999999 0 +2044 0.899998 0.97 0 +2045 0.889999 0.97 0 +2046 0.879999 0.97 0 +2047 0.869999 0.97 0 +2048 0.859999 0.97 0 +2049 0.8499989999999999 0.97 0 +2050 0.84 0.97 0 +2051 0.83 0.97 0 +2052 0.82 0.97 0 +2053 0.8100000000000001 0.97 0 +2054 0.8 0.97 0 +2055 0.79 0.97 0 +2056 0.78 0.97 0 +2057 0.77 0.97 0 +2058 0.76 0.97 0 +2059 0.75 0.97 0 +2060 0.74 0.97 0 +2061 0.73 0.97 0 +2062 0.72 0.97 0 +2063 0.71 0.97 0 +2064 0.7 0.97 0 +2065 0.6899999999999999 0.97 0 +2066 0.68 0.97 0 +2067 0.67 0.97 0 +2068 0.66 0.97 0 +2069 0.65 0.97 0 +2070 0.64 0.9699950000000001 0 +2071 0.63 0.969993 0 +2072 0.62 0.96999 0 +2073 0.61 0.969991 0 +2074 0.600001 0.969953 0 +2075 0.5900030000000001 0.969932 0 +2076 0.5800070000000001 0.969896 0 +2077 0.570008 0.969885 0 +2078 0.560014 0.969782 0 +2079 0.550022 0.969687 0 +2080 0.540031 0.969587 0 +2081 0.530036 0.969522 0 +2082 0.5200399999999999 0.969554 0 +2083 0.510037 0.96962 0 +2084 0.500031 0.9697170000000001 0 +2085 0.490023 0.969789 0 +2086 0.480019 0.969828 0 +2087 0.47002 0.9698099999999999 0 +2088 0.460021 0.96978 0 +2089 0.450025 0.9697210000000001 0 +2090 0.440023 0.969716 0 +2091 0.43002 0.969712 0 +2092 0.420017 0.969718 0 +2093 0.410011 0.969701 0 +2094 0.400006 0.969731 0 +2095 0.389999 0.9697249999999999 0 +2096 0.379994 0.9697519999999999 0 +2097 0.36999 0.969771 0 +2098 0.359986 0.969787 0 +2099 0.349981 0.96977 0 +2100 0.33998 0.969782 0 +2101 0.32998 0.969807 0 +2102 0.319981 0.969832 0 +2103 0.309982 0.969858 0 +2104 0.299984 0.969897 0 +2105 0.289986 0.969929 0 +2106 0.279988 0.969956 0 +2107 0.269991 0.969975 0 +2108 0.259993 0.969987 0 +2109 0.249995 0.969994 0 +2110 0.239996 0.969997 0 +2111 0.229997 0.9699989999999999 0 +2112 0.219998 0.97 0 +2113 0.209999 0.97 0 +2114 0.199999 0.97 0 +2115 0.189999 0.97 0 +2116 0.18 0.97 0 +2117 0.17 0.97 0 +2118 0.16 0.97 0 +2119 0.15 0.97 0 +2120 0.14 0.97 0 +2121 0.13 0.97 0 +2122 0.12 0.97 0 +2123 0.110001 0.97 0 +2124 0.100002 0.97 0 +2125 0.0900044 0.97 0 +2126 0.0800059 0.9699989999999999 0 +2127 0.0700061 0.969998 0 +2128 0.0600057 0.969998 0 +2129 0.050004 0.969998 0 +2130 0.0400032 0.969998 0 +2131 0.0400013 0.0300013 0 +2132 0.0500013 0.0300012 0 +2133 0.0600013 0.030001 0 +2134 0.0700012 0.0300007 0 +2135 0.080001 0.0300004 0 +2136 0.09000089999999999 0.0300002 0 +2137 0.100001 0.03 0 +2138 0.110001 0.0299999 0 +2139 0.12 0.0299999 0 +2140 0.13 0.0299999 0 +2141 0.14 0.0299999 0 +2142 0.15 0.0299999 0 +2143 0.16 0.0299999 0 +2144 0.17 0.0299999 0 +2145 0.18 0.03 0 +2146 0.19 0.03 0 +2147 0.2 0.03 0 +2148 0.21 0.03 0 +2149 0.22 0.03 0 +2150 0.23 0.03 0 +2151 0.24 0.03 0 +2152 0.25 0.03 0 +2153 0.26 0.03 0 +2154 0.27 0.0300064 0 +2155 0.28 0.0300161 0 +2156 0.290001 0.0300283 0 +2157 0.300001 0.0300418 0 +2158 0.310002 0.0300558 0 +2159 0.320002 0.0300492 0 +2160 0.330002 0.030044 0 +2161 0.340002 0.0300406 0 +2162 0.350004 0.0300796 0 +2163 0.360006 0.0300968 0 +2164 0.370006 0.0300858 0 +2165 0.380009 0.0301186 0 +2166 0.390008 0.0301147 0 +2167 0.400007 0.0300917 0 +2168 0.410007 0.0300756 0 +2169 0.420006 0.0300619 0 +2170 0.430005 0.0300468 0 +2171 0.440005 0.0300414 0 +2172 0.450005 0.0300388 0 +2173 0.460004 0.0300261 0 +2174 0.470004 0.030014 0 +2175 0.480007 0.0300472 0 +2176 0.490008 0.0301056 0 +2177 0.500008 0.0301646 0 +2178 0.510007 0.030242 0 +2179 0.5200050000000001 0.0303131 0 +2180 0.530003 0.0303516 0 +2181 0.540002 0.0303797 0 +2182 0.550001 0.0303539 0 +2183 0.560002 0.0303243 0 +2184 0.570003 0.0302595 0 +2185 0.580005 0.0302111 0 +2186 0.590006 0.0301547 0 +2187 0.600006 0.0301041 0 +2188 0.610008 0.0300948 0 +2189 0.620008 0.0300837 0 +2190 0.630009 0.0300874 0 +2191 0.6400090000000001 0.0300912 0 +2192 0.6500089999999999 0.0300731 0 +2193 0.660009 0.0300545 0 +2194 0.670007 0.0300361 0 +2195 0.680005 0.0300076 0 +2196 0.690002 0.0299953 0 +2197 0.699999 0.0299835 0 +2198 0.709997 0.0299858 0 +2199 0.719997 0.0299889 0 +2200 0.729996 0.0299923 0 +2201 0.739997 0.0299953 0 +2202 0.749997 0.0299975 0 +2203 0.759998 0.0299988 0 +2204 0.769998 0.0299994 0 +2205 0.779999 0.0299998 0 +2206 0.789999 0.0299999 0 +2207 0.799999 0.03 0 +2208 0.8100000000000001 0.03 0 +2209 0.82 0.03 0 +2210 0.83 0.03 0 +2211 0.84 0.03 0 +2212 0.85 0.0299999 0 +2213 0.86 0.0299999 0 +2214 0.87 0.0299998 0 +2215 0.879999 0.0299997 0 +2216 0.889998 0.0299996 0 +2217 0.899996 0.0300001 0 +2218 0.909995 0.0300009 0 +2219 0.919994 0.0300023 0 +2220 0.929994 0.030003 0 +2221 0.939995 0.0300023 0 +2222 0.949997 0.0300018 0 +2223 0.959997 0.0300017 0 +2224 0.269341 0.676273 0 +2225 0.276396 0.683989 0 +2226 0.283506 0.691785 0 +2227 0.29075 0.6995400000000001 0 +2228 0.298174 0.707168 0 +2229 0.305927 0.714435 0 +2230 0.314023 0.721171 0 +2231 0.322348 0.727526 0 +2232 0.330688 0.73359 0 +2233 0.338954 0.739418 0 +2234 0.346981 0.745077 0 +2235 0.354089 0.7509479999999999 0 +2236 0.35972 0.757132 0 +2237 0.362252 0.765078 0 +2238 0.373689 0.771858 0 +2239 0.364273 0.773989 0 +2240 0.383139 0.770083 0 +2241 0.392699 0.7696769999999999 0 +2242 0.401834 0.770221 0 +2243 0.410905 0.772116 0 +2244 0.419865 0.774635 0 +2245 0.428868 0.777345 0 +2246 0.437999 0.779821 0 +2247 0.447227 0.781928 0 +2248 0.456506 0.783625 0 +2249 0.465772 0.78493 0 +2250 0.474913 0.78595 0 +2251 0.483821 0.786911 0 +2252 0.492179 0.788706 0 +2253 0.499935 0.791453 0 +2254 0.506781 0.795973 0 +2255 0.513497 0.801324 0 +2256 0.526554 0.80025 0 +2257 0.5201750000000001 0.807265 0 +2258 0.53207 0.7930469999999999 0 +2259 0.536619 0.786315 0 +2260 0.539839 0.781274 0 +2261 0.5459039999999999 0.781648 0 +2262 0.554387 0.781755 0 +2263 0.5643629999999999 0.781071 0 +2264 0.574582 0.779474 0 +2265 0.585057 0.777336 0 +2266 0.595383 0.774187 0 +2267 0.605424 0.770189 0 +2268 0.615019 0.765555 0 +2269 0.6242799999999999 0.76085 0 +2270 0.633258 0.756258 0 +2271 0.641913 0.752093 0 +2272 0.650087 0.74875 0 +2273 0.657842 0.747037 0 +2274 0.665513 0.748653 0 +2275 0.676044 0.74261 0 +2276 0.673505 0.75143 0 +2277 0.679426 0.73384 0 +2278 0.684561 0.725841 0 +2279 0.6905520000000001 0.718345 0 +2280 0.697203 0.711313 0 +2281 0.703975 0.704301 0 +2282 0.71066 0.697176 0 +2283 0.717064 0.689848 0 +2284 0.723051 0.682303 0 +2285 0.72867 0.674661 0 +2286 0.734011 0.667089 0 +2287 0.739259 0.659702 0 +2288 0.7450639999999999 0.653157 0 +2289 0.751393 0.647634 0 +2290 0.758819 0.643662 0 +2291 0.767055 0.6401829999999999 0 +2292 0.772302 0.628085 0 +2293 0.775799 0.636816 0 +2294 0.768193 0.62004 0 +2295 0.764329 0.613167 0 +2296 0.761455 0.608189 0 +2297 0.764523 0.603138 0 +2298 0.768798 0.595816 0 +2299 0.772932 0.587259 0 +2300 0.776864 0.5779260000000001 0 +2301 0.780511 0.567995 0 +2302 0.783509 0.557655 0 +2303 0.785366 0.547013 0 +2304 0.786664 0.536407 0 +2305 0.787811 0.525884 0 +2306 0.789042 0.515524 0 +2307 0.791049 0.505562 0 +2308 0.79481 0.495949 0 +2309 0.786272 0.461198 0 +2310 0.78956 0.470928 0 +2311 0.783843 0.451188 0 +2312 0.781738 0.441166 0 +2313 0.779648 0.431148 0 +2314 0.777398 0.421139 0 +2315 0.774617 0.411315 0 +2316 0.771197 0.4018 0 +2317 0.7674029999999999 0.392716 0 +2318 0.763472 0.384056 0 +2319 0.75972 0.375874 0 +2320 0.756793 0.36843 0 +2321 0.755364 0.361574 0 +2322 0.756619 0.3548 0 +2323 0.759081 0.347714 0 +2324 0.753432 0.338906 0 +2325 0.761213 0.340151 0 +2326 0.746592 0.337156 0 +2327 0.740608 0.33313 0 +2328 0.734804 0.327387 0 +2329 0.728638 0.320716 0 +2330 0.7220800000000001 0.313692 0 +2331 0.715135 0.306511 0 +2332 0.707978 0.299193 0 +2333 0.700661 0.291778 0 +2334 0.693078 0.28444 0 +2335 0.685172 0.27734 0 +2336 0.677032 0.27048 0 +2337 0.668749 0.263851 0 +2338 0.660238 0.257627 0 +2339 0.651512 0.251915 0 +2340 0.643232 0.246043 0 +2341 0.635972 0.238785 0 +2342 0.6026359999999999 0.230707 0 +2343 0.612094 0.232857 0 +2344 0.593338 0.227702 0 +2345 0.583779 0.224516 0 +2346 0.573929 0.221751 0 +2347 0.56399 0.219423 0 +2348 0.55408 0.217454 0 +2349 0.544278 0.215836 0 +2350 0.534687 0.214562 0 +2351 0.525398 0.21356 0 +2352 0.51652 0.212365 0 +2353 0.508277 0.210697 0 +2354 0.500875 0.207768 0 +2355 0.494272 0.203639 0 +2356 0.488183 0.198499 0 +2357 0.477915 0.200101 0 +2358 0.481991 0.193522 0 +2359 0.473536 0.205567 0 +2360 0.46742 0.209253 0 +2361 0.459813 0.211973 0 +2362 0.451258 0.214537 0 +2363 0.442053 0.216883 0 +2364 0.432487 0.21933 0 +2365 0.422624 0.221946 0 +2366 0.412492 0.224669 0 +2367 0.402147 0.227635 0 +2368 0.391702 0.231203 0 +2369 0.381533 0.235941 0 +2370 0.371549 0.241196 0 +2371 0.361772 0.246674 0 +2372 0.352164 0.252312 0 +2373 0.342737 0.258164 0 +2374 0.333527 0.264296 0 +2375 0.324599 0.270798 0 +2376 0.31584 0.277429 0 +2377 0.307225 0.284271 0 +2378 0.298808 0.291305 0 +2379 0.290983 0.298901 0 +2380 0.283987 0.30687 0 +2381 0.277673 0.314966 0 +2382 0.271642 0.322767 0 +2383 0.265751 0.330226 0 +2384 0.259639 0.337145 0 +2385 0.253252 0.343367 0 +2386 0.246389 0.348612 0 +2387 0.239336 0.352799 0 +2388 0.232121 0.355846 0 +2389 0.227101 0.365022 0 +2390 0.224594 0.358019 0 +2391 0.228761 0.372655 0 +2392 0.229781 0.380744 0 +2393 0.229415 0.389115 0 +2394 0.228018 0.397689 0 +2395 0.226131 0.406676 0 +2396 0.224034 0.416155 0 +2397 0.221822 0.425881 0 +2398 0.219478 0.435809 0 +2399 0.216988 0.446013 0 +2400 0.214563 0.456481 0 +2401 0.212653 0.467351 0 +2402 0.211914 0.478511 0 +2403 0.211748 0.489729 0 +2404 0.21193 0.500882 0 +2405 0.212358 0.5119590000000001 0 +2406 0.212987 0.522987 0 +2407 0.213867 0.534031 0 +2408 0.214993 0.545081 0 +2409 0.216351 0.556157 0 +2410 0.21833 0.567082 0 +2411 0.22154 0.577562 0 +2412 0.22538 0.587552 0 +2413 0.229491 0.59712 0 +2414 0.2337 0.606237 0 +2415 0.237889 0.61495 0 +2416 0.241927 0.623193 0 +2417 0.244687 0.631054 0 +2418 0.24571 0.638344 0 +2419 0.243134 0.645153 0 +2420 0.239058 0.6517579999999999 0 +2421 0.241279 0.663521 0 +2422 0.234203 0.658098 0 +2423 0.248355 0.669564 0 +2424 0.255371 0.676334 0 +2425 0.794473 0.480631 0 +2426 0.801438 0.488404 0 +2427 0.622198 0.232738 0 +2428 0.63173 0.229886 0 +2429 0.959997 0.0400019 0 +2430 0.959997 0.0500019 0 +2431 0.959997 0.0600019 0 +2432 0.959998 0.0700018 0 +2433 0.959999 0.08000160000000001 0 +2434 0.959999 0.0900014 0 +2435 0.959999 0.100001 0 +2436 0.96 0.110001 0 +2437 0.96 0.120001 0 +2438 0.96 0.130001 0 +2439 0.96 0.14 0 +2440 0.96 0.15 0 +2441 0.96 0.16 0 +2442 0.96 0.17 0 +2443 0.96 0.18 0 +2444 0.96 0.19 0 +2445 0.96 0.2 0 +2446 0.96 0.21 0 +2447 0.96 0.22 0 +2448 0.96 0.23 0 +2449 0.96 0.24 0 +2450 0.96 0.25 0 +2451 0.96 0.26 0 +2452 0.96 0.27 0 +2453 0.96 0.28 0 +2454 0.960004 0.289997 0 +2455 0.959966 0.299989 0 +2456 0.959897 0.309974 0 +2457 0.959846 0.319961 0 +2458 0.959744 0.329947 0 +2459 0.959657 0.339941 0 +2460 0.959579 0.349939 0 +2461 0.95955 0.359942 0 +2462 0.959546 0.369946 0 +2463 0.959608 0.379956 0 +2464 0.959708 0.389963 0 +2465 0.959798 0.39997 0 +2466 0.959875 0.409976 0 +2467 0.959893 0.419985 0 +2468 0.959848 0.43 0 +2469 0.95978 0.440009 0 +2470 0.9597059999999999 0.450021 0 +2471 0.959656 0.460028 0 +2472 0.959626 0.470047 0 +2473 0.9596479999999999 0.480065 0 +2474 0.959687 0.490088 0 +2475 0.959784 0.500109 0 +2476 0.9598950000000001 0.510132 0 +2477 0.959982 0.520128 0 +2478 0.960052 0.530125 0 +2479 0.960082 0.540115 0 +2480 0.960047 0.5501 0 +2481 0.959977 0.560083 0 +2482 0.959912 0.570068 0 +2483 0.959893 0.580054 0 +2484 0.9598989999999999 0.590042 0 +2485 0.959919 0.600032 0 +2486 0.959945 0.610024 0 +2487 0.959961 0.620018 0 +2488 0.959969 0.630014 0 +2489 0.959972 0.64001 0 +2490 0.959981 0.650008 0 +2491 0.959989 0.660006 0 +2492 0.959995 0.670004 0 +2493 0.959998 0.680003 0 +2494 0.959999 0.690002 0 +2495 0.96 0.700001 0 +2496 0.96 0.710001 0 +2497 0.96 0.720001 0 +2498 0.96 0.73 0 +2499 0.96 0.74 0 +2500 0.96 0.75 0 +2501 0.96 0.76 0 +2502 0.96 0.77 0 +2503 0.96 0.78 0 +2504 0.96 0.79 0 +2505 0.96 0.8 0 +2506 0.96 0.8100000000000001 0 +2507 0.96 0.82 0 +2508 0.96 0.83 0 +2509 0.96 0.84 0 +2510 0.96 0.85 0 +2511 0.96 0.86 0 +2512 0.96 0.87 0 +2513 0.96 0.879999 0 +2514 0.96 0.889998 0 +2515 0.959999 0.899996 0 +2516 0.959998 0.9099930000000001 0 +2517 0.959996 0.919991 0 +2518 0.959996 0.929991 0 +2519 0.959996 0.939992 0 +2520 0.959996 0.949994 0 +2521 0.959997 0.959995 0 +2522 0.949996 0.959995 0 +2523 0.939997 0.959996 0 +2524 0.929997 0.959997 0 +2525 0.919997 0.959998 0 +2526 0.9099969999999999 0.959999 0 +2527 0.899998 0.96 0 +2528 0.889998 0.96 0 +2529 0.879999 0.96 0 +2530 0.869999 0.96 0 +2531 0.859999 0.96 0 +2532 0.8499989999999999 0.96 0 +2533 0.84 0.96 0 +2534 0.83 0.96 0 +2535 0.82 0.96 0 +2536 0.8100000000000001 0.96 0 +2537 0.8 0.96 0 +2538 0.79 0.96 0 +2539 0.78 0.96 0 +2540 0.77 0.96 0 +2541 0.76 0.96 0 +2542 0.75 0.96 0 +2543 0.74 0.96 0 +2544 0.73 0.96 0 +2545 0.72 0.96 0 +2546 0.71 0.96 0 +2547 0.7 0.96 0 +2548 0.6899999999999999 0.96 0 +2549 0.68 0.96 0 +2550 0.67 0.959991 0 +2551 0.66 0.959991 0 +2552 0.65 0.959982 0 +2553 0.64 0.959981 0 +2554 0.63 0.959959 0 +2555 0.62 0.9599569999999999 0 +2556 0.610005 0.959889 0 +2557 0.60001 0.959856 0 +2558 0.590021 0.959803 0 +2559 0.580026 0.959779 0 +2560 0.570042 0.959656 0 +2561 0.560053 0.959531 0 +2562 0.5500660000000001 0.959406 0 +2563 0.5400740000000001 0.959267 0 +2564 0.530073 0.959238 0 +2565 0.520072 0.959302 0 +2566 0.510053 0.959437 0 +2567 0.50004 0.95958 0 +2568 0.490035 0.959681 0 +2569 0.480044 0.959691 0 +2570 0.470047 0.959666 0 +2571 0.460057 0.959573 0 +2572 0.450061 0.959506 0 +2573 0.440057 0.959473 0 +2574 0.430053 0.959431 0 +2575 0.420041 0.959427 0 +2576 0.410029 0.959449 0 +2577 0.400011 0.959463 0 +2578 0.389998 0.959494 0 +2579 0.379986 0.959537 0 +2580 0.369973 0.959566 0 +2581 0.359958 0.95955 0 +2582 0.34995 0.959569 0 +2583 0.339946 0.959591 0 +2584 0.329943 0.959636 0 +2585 0.319941 0.959684 0 +2586 0.309944 0.959739 0 +2587 0.29995 0.959793 0 +2588 0.289956 0.959844 0 +2589 0.279963 0.9598989999999999 0 +2590 0.269971 0.959936 0 +2591 0.259977 0.959964 0 +2592 0.249983 0.959982 0 +2593 0.239987 0.959991 0 +2594 0.229991 0.959996 0 +2595 0.219994 0.959998 0 +2596 0.209996 0.959999 0 +2597 0.199997 0.96 0 +2598 0.189998 0.96 0 +2599 0.179999 0.96 0 +2600 0.169999 0.96 0 +2601 0.159999 0.96 0 +2602 0.15 0.96 0 +2603 0.14 0.96 0 +2604 0.13 0.96 0 +2605 0.120001 0.96 0 +2606 0.110001 0.96 0 +2607 0.100003 0.96 0 +2608 0.09000470000000001 0.96 0 +2609 0.0800054 0.959998 0 +2610 0.0700054 0.959998 0 +2611 0.0600048 0.959998 0 +2612 0.0500039 0.959998 0 +2613 0.0400032 0.959998 0 +2614 0.0400016 0.0400015 0 +2615 0.0500016 0.0400014 0 +2616 0.0600015 0.0400012 0 +2617 0.07000140000000001 0.0400008 0 +2618 0.08000119999999999 0.0400005 0 +2619 0.0900011 0.0400003 0 +2620 0.100001 0.0400001 0 +2621 0.110001 0.04 0 +2622 0.120001 0.0399999 0 +2623 0.13 0.0399998 0 +2624 0.14 0.0399998 0 +2625 0.15 0.0399999 0 +2626 0.16 0.0399999 0 +2627 0.17 0.0399999 0 +2628 0.18 0.0399999 0 +2629 0.19 0.04 0 +2630 0.2 0.04 0 +2631 0.21 0.04 0 +2632 0.22 0.04 0 +2633 0.23 0.04 0 +2634 0.24 0.04 0 +2635 0.25 0.0400044 0 +2636 0.260001 0.0400372 0 +2637 0.270003 0.0400725 0 +2638 0.280006 0.0401099 0 +2639 0.290008 0.0401336 0 +2640 0.300011 0.0401624 0 +2641 0.310012 0.0401517 0 +2642 0.320012 0.0401453 0 +2643 0.330011 0.0401369 0 +2644 0.340019 0.0401884 0 +2645 0.350024 0.0402139 0 +2646 0.360027 0.0402186 0 +2647 0.370034 0.0402487 0 +2648 0.380033 0.0402634 0 +2649 0.390031 0.0402467 0 +2650 0.40003 0.0402414 0 +2651 0.410029 0.0402281 0 +2652 0.420031 0.0402044 0 +2653 0.430035 0.040188 0 +2654 0.440036 0.0401737 0 +2655 0.450035 0.0401398 0 +2656 0.460033 0.0400946 0 +2657 0.470036 0.0400586 0 +2658 0.480035 0.0400865 0 +2659 0.490028 0.0401542 0 +2660 0.500021 0.040257 0 +2661 0.510014 0.0403774 0 +2662 0.5200050000000001 0.0404805 0 +2663 0.5300010000000001 0.0405855 0 +2664 0.540001 0.0406117 0 +2665 0.550009 0.0406242 0 +2666 0.560014 0.0405613 0 +2667 0.570024 0.0404906 0 +2668 0.580028 0.0403864 0 +2669 0.590032 0.0403059 0 +2670 0.600039 0.0402647 0 +2671 0.610042 0.0402331 0 +2672 0.620044 0.0402212 0 +2673 0.630046 0.0402177 0 +2674 0.640043 0.0401864 0 +2675 0.650039 0.0401578 0 +2676 0.660034 0.0401139 0 +2677 0.670023 0.0400442 0 +2678 0.680013 0.0400023 0 +2679 0.690002 0.0399671 0 +2680 0.699995 0.0399668 0 +2681 0.709991 0.039968 0 +2682 0.719989 0.0399684 0 +2683 0.729988 0.0399736 0 +2684 0.739989 0.0399776 0 +2685 0.74999 0.039984 0 +2686 0.759992 0.0399904 0 +2687 0.769994 0.039995 0 +2688 0.779995 0.0399976 0 +2689 0.789996 0.039999 0 +2690 0.799997 0.0399996 0 +2691 0.809998 0.0399998 0 +2692 0.819999 0.0399999 0 +2693 0.829999 0.0399999 0 +2694 0.8399990000000001 0.0399999 0 +2695 0.85 0.0399999 0 +2696 0.86 0.0399998 0 +2697 0.869999 0.0399996 0 +2698 0.879999 0.0399996 0 +2699 0.889997 0.04 0 +2700 0.899996 0.0400006 0 +2701 0.909995 0.0400015 0 +2702 0.919995 0.0400026 0 +2703 0.929995 0.0400029 0 +2704 0.9399960000000001 0.0400024 0 +2705 0.949996 0.0400021 0 +2706 0.0400029 0.949998 0 +2707 0.0400024 0.939998 0 +2708 0.0400019 0.929998 0 +2709 0.0400013 0.919999 0 +2710 0.0400009 0.909999 0 +2711 0.0400005 0.899999 0 +2712 0.0400003 0.889999 0 +2713 0.0400001 0.879999 0 +2714 0.04 0.87 0 +2715 0.0399999 0.86 0 +2716 0.0399999 0.85 0 +2717 0.0399999 0.84 0 +2718 0.0399999 0.83 0 +2719 0.0399999 0.82 0 +2720 0.04 0.8100000000000001 0 +2721 0.04 0.8 0 +2722 0.04 0.79 0 +2723 0.04 0.78 0 +2724 0.04 0.77 0 +2725 0.04 0.76 0 +2726 0.0400043 0.75 0 +2727 0.0400169 0.74 0 +2728 0.0400489 0.729999 0 +2729 0.0400665 0.719998 0 +2730 0.0400845 0.709997 0 +2731 0.0400736 0.699997 0 +2732 0.0400586 0.689997 0 +2733 0.0400401 0.679997 0 +2734 0.0400237 0.669997 0 +2735 0.0400124 0.659998 0 +2736 0.0400059 0.649998 0 +2737 0.0400026 0.639999 0 +2738 0.0399537 0.63 0 +2739 0.0399381 0.620004 0 +2740 0.0399724 0.610009 0 +2741 0.0400402 0.600025 0 +2742 0.0401744 0.590035 0 +2743 0.0403466 0.580039 0 +2744 0.0404377 0.570039 0 +2745 0.0404207 0.5600309999999999 0 +2746 0.0403932 0.550023 0 +2747 0.0403156 0.539991 0 +2748 0.040254 0.529952 0 +2749 0.0402429 0.51993 0 +2750 0.0402399 0.5099050000000001 0 +2751 0.0402466 0.499888 0 +2752 0.0402392 0.48987 0 +2753 0.0402238 0.479874 0 +2754 0.0401771 0.469869 0 +2755 0.0401356 0.459876 0 +2756 0.0401057 0.449863 0 +2757 0.0401332 0.439864 0 +2758 0.0402171 0.429859 0 +2759 0.0403284 0.419858 0 +2760 0.0404483 0.409864 0 +2761 0.0405853 0.399867 0 +2762 0.0407355 0.389865 0 +2763 0.0407893 0.379875 0 +2764 0.0407924 0.36988 0 +2765 0.0407289 0.35989 0 +2766 0.0406112 0.349905 0 +2767 0.0404759 0.339921 0 +2768 0.0403465 0.329933 0 +2769 0.040248 0.319942 0 +2770 0.040161 0.309952 0 +2771 0.0401021 0.299961 0 +2772 0.0400631 0.289968 0 +2773 0.04004 0.279975 0 +2774 0.0400238 0.26998 0 +2775 0.0400127 0.259985 0 +2776 0.0400062 0.249989 0 +2777 0.0400028 0.239992 0 +2778 0.0400012 0.229994 0 +2779 0.0400005 0.219996 0 +2780 0.0400002 0.209997 0 +2781 0.0400001 0.199998 0 +2782 0.04 0.189999 0 +2783 0.04 0.179999 0 +2784 0.04 0.17 0 +2785 0.04 0.16 0 +2786 0.0399999 0.15 0 +2787 0.0399998 0.14 0 +2788 0.0399998 0.13 0 +2789 0.0399998 0.120001 0 +2790 0.0400001 0.110001 0 +2791 0.0400006 0.100002 0 +2792 0.0400011 0.0900024 0 +2793 0.0400018 0.0800034 0 +2794 0.040002 0.0700026 0 +2795 0.0400019 0.060002 0 +2796 0.0400017 0.0500018 0 +2797 0.262271 0.683643 0 +2798 0.2692 0.691254 0 +2799 0.276278 0.699018 0 +2800 0.283493 0.706885 0 +2801 0.290946 0.71472 0 +2802 0.298776 0.7222460000000001 0 +2803 0.307287 0.729009 0 +2804 0.315944 0.735317 0 +2805 0.324539 0.741304 0 +2806 0.332959 0.747028 0 +2807 0.341033 0.75247 0 +2808 0.348447 0.7571639999999999 0 +2809 0.35401 0.760409 0 +2810 0.353937 0.766804 0 +2811 0.354561 0.77579 0 +2812 0.366795 0.783374 0 +2813 0.35743 0.7856109999999999 0 +2814 0.375962 0.781266 0 +2815 0.384956 0.779712 0 +2816 0.393669 0.778931 0 +2817 0.402029 0.779166 0 +2818 0.410184 0.7807500000000001 0 +2819 0.418524 0.78348 0 +2820 0.427126 0.7864409999999999 0 +2821 0.436075 0.789093 0 +2822 0.4453 0.791279 0 +2823 0.454643 0.793011 0 +2824 0.463912 0.794283 0 +2825 0.472974 0.795084 0 +2826 0.481591 0.795561 0 +2827 0.489431 0.7964639999999999 0 +2828 0.496139 0.798295 0 +2829 0.501599 0.80253 0 +2830 0.507162 0.807899 0 +2831 0.5132060000000001 0.81393 0 +2832 0.52725 0.8132819999999999 0 +2833 0.519822 0.820133 0 +2834 0.534009 0.806102 0 +2835 0.540455 0.798244 0 +2836 0.544245 0.789548 0 +2837 0.553987 0.791707 0 +2838 0.564956 0.7912979999999999 0 +2839 0.576064 0.789974 0 +2840 0.587127 0.788019 0 +2841 0.598583 0.785223 0 +2842 0.609194 0.780201 0 +2843 0.61882 0.775134 0 +2844 0.628109 0.770147 0 +2845 0.6370209999999999 0.765342 0 +2846 0.645383 0.76078 0 +2847 0.652657 0.756544 0 +2848 0.657884 0.753314 0 +2849 0.663169 0.756403 0 +2850 0.670655 0.760298 0 +2851 0.681741 0.754122 0 +2852 0.67958 0.762714 0 +2853 0.684291 0.745884 0 +2854 0.6874980000000001 0.738061 0 +2855 0.692388 0.7310680000000001 0 +2856 0.698224 0.724248 0 +2857 0.704777 0.717606 0 +2858 0.711531 0.7107599999999999 0 +2859 0.718267 0.703643 0 +2860 0.724735 0.696255 0 +2861 0.730693 0.688553 0 +2862 0.73617 0.680762 0 +2863 0.741119 0.672996 0 +2864 0.745885 0.665462 0 +2865 0.750529 0.659063 0 +2866 0.75547 0.65403 0 +2867 0.761889 0.651136 0 +2868 0.769571 0.648632 0 +2869 0.777915 0.646057 0 +2870 0.784725 0.633382 0 +2871 0.786824 0.643299 0 +2872 0.78156 0.623204 0 +2873 0.776176 0.6146779999999999 0 +2874 0.770388 0.607975 0 +2875 0.7761479999999999 0.600684 0 +2876 0.7814179999999999 0.59173 0 +2877 0.785989 0.58194 0 +2878 0.790193 0.571788 0 +2879 0.794057 0.560632 0 +2880 0.795639 0.548949 0 +2881 0.796633 0.537976 0 +2882 0.797481 0.5278 0 +2883 0.798442 0.517833 0 +2884 0.800073 0.508603 0 +2885 0.802718 0.500703 0 +2886 0.808306 0.494693 0 +2887 0.808697 0.482124 0 +2888 0.814968 0.488825 0 +2889 0.8027300000000001 0.474793 0 +2890 0.79817 0.466394 0 +2891 0.794871 0.457528 0 +2892 0.79265 0.44806 0 +2893 0.790811 0.438326 0 +2894 0.789112 0.428326 0 +2895 0.787158 0.418158 0 +2896 0.78434 0.408076 0 +2897 0.780758 0.398274 0 +2898 0.7765649999999999 0.388984 0 +2899 0.77228 0.380274 0 +2900 0.767692 0.372484 0 +2901 0.763695 0.365976 0 +2902 0.760818 0.36138 0 +2903 0.7635189999999999 0.356671 0 +2904 0.766709 0.350165 0 +2905 0.769838 0.342107 0 +2906 0.762239 0.332096 0 +2907 0.771184 0.333204 0 +2908 0.754521 0.331992 0 +2909 0.7489980000000001 0.332288 0 +2910 0.745964 0.327682 0 +2911 0.741585 0.321132 0 +2912 0.736098 0.314103 0 +2913 0.729566 0.306674 0 +2914 0.722392 0.299425 0 +2915 0.715065 0.291991 0 +2916 0.707694 0.284303 0 +2917 0.700068 0.276606 0 +2918 0.691893 0.269325 0 +2919 0.683582 0.262227 0 +2920 0.675222 0.255319 0 +2921 0.666444 0.24919 0 +2922 0.657602 0.243933 0 +2923 0.649775 0.239101 0 +2924 0.6434800000000001 0.233724 0 +2925 0.640036 0.226371 0 +2926 0.62864 0.220923 0 +2927 0.637201 0.218027 0 +2928 0.620204 0.223421 0 +2929 0.612117 0.224232 0 +2930 0.604337 0.222062 0 +2931 0.595933 0.218712 0 +2932 0.586471 0.214954 0 +2933 0.576454 0.212104 0 +2934 0.566226 0.209767 0 +2935 0.55605 0.207833 0 +2936 0.546061 0.206242 0 +2937 0.536362 0.205026 0 +2938 0.527106 0.204255 0 +2939 0.518471 0.203806 0 +2940 0.510602 0.202817 0 +2941 0.503996 0.201092 0 +2942 0.498549 0.197024 0 +2943 0.4929 0.191758 0 +2944 0.486733 0.186479 0 +2945 0.475098 0.189218 0 +2946 0.479377 0.181212 0 +2947 0.472103 0.196142 0 +2948 0.470188 0.201312 0 +2949 0.464782 0.202116 0 +2950 0.457392 0.203421 0 +2951 0.448677 0.205119 0 +2952 0.439481 0.20731 0 +2953 0.429867 0.209746 0 +2954 0.419927 0.212327 0 +2955 0.409638 0.214889 0 +2956 0.39916 0.217423 0 +2957 0.387747 0.220712 0 +2958 0.376847 0.226316 0 +2959 0.366777 0.232034 0 +2960 0.356747 0.237804 0 +2961 0.346906 0.243591 0 +2962 0.337224 0.249452 0 +2963 0.327791 0.255702 0 +2964 0.318697 0.26233 0 +2965 0.309712 0.269184 0 +2966 0.300709 0.276093 0 +2967 0.291798 0.283115 0 +2968 0.282933 0.290901 0 +2969 0.275977 0.299969 0 +2970 0.269798 0.308531 0 +2971 0.264155 0.316259 0 +2972 0.258399 0.323593 0 +2973 0.252852 0.330446 0 +2974 0.246937 0.336624 0 +2975 0.24113 0.341954 0 +2976 0.234996 0.346136 0 +2977 0.22858 0.349179 0 +2978 0.221511 0.351548 0 +2979 0.217706 0.359859 0 +2980 0.214481 0.354011 0 +2981 0.219312 0.366271 0 +2982 0.220454 0.373451 0 +2983 0.22099 0.380927 0 +2984 0.220749 0.388404 0 +2985 0.218323 0.396056 0 +2986 0.216311 0.405004 0 +2987 0.21447 0.414475 0 +2988 0.212486 0.424189 0 +2989 0.210164 0.434135 0 +2990 0.2074 0.444302 0 +2991 0.204552 0.454686 0 +2992 0.201897 0.466265 0 +2993 0.201558 0.478447 0 +2994 0.201738 0.489819 0 +2995 0.202101 0.501225 0 +2996 0.202594 0.512472 0 +2997 0.203238 0.5236769999999999 0 +2998 0.204066 0.534903 0 +2999 0.204971 0.546287 0 +3000 0.206009 0.557621 0 +3001 0.207609 0.569681 0 +3002 0.211695 0.58103 0 +3003 0.216195 0.591283 0 +3004 0.220538 0.600553 0 +3005 0.225008 0.6095739999999999 0 +3006 0.229465 0.618046 0 +3007 0.233938 0.625926 0 +3008 0.237744 0.632586 0 +3009 0.240091 0.637554 0 +3010 0.236819 0.6417310000000001 0 +3011 0.232182 0.647158 0 +3012 0.227378 0.653147 0 +3013 0.228776 0.664088 0 +3014 0.222839 0.659146 0 +3015 0.235122 0.669978 0 +3016 0.241636 0.676383 0 +3017 0.248203 0.68332 0 +3018 0.0500018 0.0500016 0 +3019 0.0600017 0.0500013 0 +3020 0.07000149999999999 0.050001 0 +3021 0.0800014 0.0500006 0 +3022 0.0900012 0.0500004 0 +3023 0.100001 0.0500002 0 +3024 0.110001 0.05 0 +3025 0.120001 0.0499999 0 +3026 0.130001 0.0499998 0 +3027 0.14 0.0499998 0 +3028 0.15 0.0499998 0 +3029 0.16 0.0499999 0 +3030 0.17 0.0499999 0 +3031 0.18 0.0499999 0 +3032 0.19 0.05 0 +3033 0.2 0.05 0 +3034 0.21 0.05 0 +3035 0.22 0.05 0 +3036 0.23 0.05 0 +3037 0.24 0.0500267 0 +3038 0.250005 0.0501062 0 +3039 0.260012 0.0501765 0 +3040 0.270022 0.0502469 0 +3041 0.280029 0.0502971 0 +3042 0.290037 0.0503498 0 +3043 0.30004 0.0503452 0 +3044 0.310041 0.0503386 0 +3045 0.320039 0.0503243 0 +3046 0.330058 0.0503526 0 +3047 0.340068 0.0503809 0 +3048 0.35008 0.0504017 0 +3049 0.360089 0.050414 0 +3050 0.370091 0.0504537 0 +3051 0.380086 0.0504687 0 +3052 0.390089 0.0504865 0 +3053 0.400092 0.0504939 0 +3054 0.41011 0.050481 0 +3055 0.420121 0.050438 0 +3056 0.430129 0.0504096 0 +3057 0.440131 0.0503747 0 +3058 0.450136 0.0502966 0 +3059 0.460136 0.0501683 0 +3060 0.470128 0.0500891 0 +3061 0.480099 0.0501102 0 +3062 0.490073 0.0502056 0 +3063 0.500046 0.0503486 0 +3064 0.510016 0.0505046 0 +3065 0.520003 0.0507054 0 +3066 0.53 0.0508456 0 +3067 0.5400199999999999 0.0509516 0 +3068 0.5500350000000001 0.0509489 0 +3069 0.560064 0.0508927 0 +3070 0.57008 0.0507622 0 +3071 0.5800999999999999 0.0506554 0 +3072 0.590118 0.0505553 0 +3073 0.600125 0.0505026 0 +3074 0.610129 0.0504476 0 +3075 0.620131 0.0504194 0 +3076 0.630123 0.0503806 0 +3077 0.640114 0.0503393 0 +3078 0.650099 0.0502648 0 +3079 0.660073 0.0501519 0 +3080 0.6700469999999999 0.0500581 0 +3081 0.680021 0.049977 0 +3082 0.689999 0.0499431 0 +3083 0.6999840000000001 0.0499332 0 +3084 0.709975 0.0499188 0 +3085 0.71997 0.0499254 0 +3086 0.729969 0.0499226 0 +3087 0.739971 0.0499365 0 +3088 0.749974 0.0499514 0 +3089 0.759979 0.0499673 0 +3090 0.769983 0.0499808 0 +3091 0.779987 0.0499899 0 +3092 0.78999 0.0499952 0 +3093 0.799993 0.0499979 0 +3094 0.809995 0.0499991 0 +3095 0.8199959999999999 0.0499996 0 +3096 0.829998 0.0499998 0 +3097 0.839998 0.0499998 0 +3098 0.8499989999999999 0.0499998 0 +3099 0.859999 0.0499997 0 +3100 0.869999 0.0499996 0 +3101 0.8799979999999999 0.0499999 0 +3102 0.889997 0.0500004 0 +3103 0.899996 0.050001 0 +3104 0.909995 0.0500017 0 +3105 0.919995 0.0500026 0 +3106 0.929996 0.0500027 0 +3107 0.9399960000000001 0.0500024 0 +3108 0.949997 0.0500022 0 +3109 0.949997 0.0600021 0 +3110 0.949998 0.07000199999999999 0 +3111 0.949998 0.0800018 0 +3112 0.949999 0.0900016 0 +3113 0.949999 0.100001 0 +3114 0.95 0.110001 0 +3115 0.95 0.120001 0 +3116 0.95 0.130001 0 +3117 0.95 0.140001 0 +3118 0.95 0.15 0 +3119 0.95 0.16 0 +3120 0.95 0.17 0 +3121 0.95 0.18 0 +3122 0.95 0.19 0 +3123 0.95 0.2 0 +3124 0.95 0.21 0 +3125 0.95 0.22 0 +3126 0.95 0.23 0 +3127 0.95 0.24 0 +3128 0.95 0.25 0 +3129 0.95 0.26 0 +3130 0.949994 0.27 0 +3131 0.950008 0.279989 0 +3132 0.949987 0.289968 0 +3133 0.949933 0.299935 0 +3134 0.949842 0.309908 0 +3135 0.949726 0.31988 0 +3136 0.949583 0.329866 0 +3137 0.9494320000000001 0.339857 0 +3138 0.949336 0.349865 0 +3139 0.949271 0.359876 0 +3140 0.949281 0.369895 0 +3141 0.949365 0.379914 0 +3142 0.949489 0.389928 0 +3143 0.949648 0.399941 0 +3144 0.949743 0.409956 0 +3145 0.949756 0.419976 0 +3146 0.949692 0.429992 0 +3147 0.949599 0.440012 0 +3148 0.949481 0.45003 0 +3149 0.949395 0.460082 0 +3150 0.94938 0.470125 0 +3151 0.949416 0.480187 0 +3152 0.949535 0.490244 0 +3153 0.949707 0.500302 0 +3154 0.949892 0.510307 0 +3155 0.950044 0.52032 0 +3156 0.950139 0.5303020000000001 0 +3157 0.950164 0.540269 0 +3158 0.950106 0.55024 0 +3159 0.949999 0.560204 0 +3160 0.949904 0.570167 0 +3161 0.949873 0.580134 0 +3162 0.949875 0.590107 0 +3163 0.949915 0.600088 0 +3164 0.949926 0.610073 0 +3165 0.949928 0.6200599999999999 0 +3166 0.949916 0.6300519999999999 0 +3167 0.949929 0.640043 0 +3168 0.949944 0.650035 0 +3169 0.9499649999999999 0.6600279999999999 0 +3170 0.949982 0.670022 0 +3171 0.950001 0.680017 0 +3172 0.950018 0.690013 0 +3173 0.950017 0.70001 0 +3174 0.95001 0.7100070000000001 0 +3175 0.950009 0.720005 0 +3176 0.950007 0.730004 0 +3177 0.950005 0.740003 0 +3178 0.950003 0.7500019999999999 0 +3179 0.950001 0.760002 0 +3180 0.950001 0.770001 0 +3181 0.95 0.7800010000000001 0 +3182 0.95 0.790001 0 +3183 0.95 0.8 0 +3184 0.95 0.8100000000000001 0 +3185 0.95 0.82 0 +3186 0.95 0.83 0 +3187 0.95 0.84 0 +3188 0.95 0.85 0 +3189 0.95 0.86 0 +3190 0.95 0.869999 0 +3191 0.95 0.879999 0 +3192 0.949999 0.889998 0 +3193 0.949998 0.899996 0 +3194 0.949997 0.909994 0 +3195 0.949996 0.9199929999999999 0 +3196 0.949996 0.929993 0 +3197 0.949996 0.939994 0 +3198 0.949996 0.949995 0 +3199 0.9399960000000001 0.949996 0 +3200 0.929996 0.949997 0 +3201 0.919997 0.949998 0 +3202 0.9099969999999999 0.949999 0 +3203 0.899998 0.949999 0 +3204 0.889998 0.95 0 +3205 0.8799979999999999 0.95 0 +3206 0.869999 0.95 0 +3207 0.859999 0.95 0 +3208 0.8499989999999999 0.95 0 +3209 0.8399990000000001 0.95 0 +3210 0.83 0.95 0 +3211 0.82 0.949993 0 +3212 0.8100000000000001 0.9499840000000001 0 +3213 0.8 0.949979 0 +3214 0.79 0.949976 0 +3215 0.78 0.949974 0 +3216 0.77 0.949974 0 +3217 0.76 0.949981 0 +3218 0.75 0.9499880000000001 0 +3219 0.74 0.949994 0 +3220 0.73 0.949997 0 +3221 0.72 0.949999 0 +3222 0.71 0.95 0 +3223 0.7 0.95 0 +3224 0.6899999999999999 0.95 0 +3225 0.68 0.9499649999999999 0 +3226 0.669999 0.949968 0 +3227 0.659999 0.949963 0 +3228 0.649999 0.949955 0 +3229 0.639999 0.949924 0 +3230 0.629999 0.949915 0 +3231 0.620011 0.949824 0 +3232 0.61002 0.949761 0 +3233 0.600041 0.949681 0 +3234 0.590056 0.9496289999999999 0 +3235 0.580083 0.949511 0 +3236 0.570105 0.949368 0 +3237 0.560123 0.9492159999999999 0 +3238 0.550135 0.949014 0 +3239 0.5401319999999999 0.948869 0 +3240 0.530127 0.948847 0 +3241 0.5200900000000001 0.948972 0 +3242 0.510068 0.949218 0 +3243 0.500065 0.949443 0 +3244 0.490074 0.949568 0 +3245 0.480086 0.94958 0 +3246 0.470108 0.949479 0 +3247 0.460129 0.949338 0 +3248 0.450131 0.94921 0 +3249 0.440131 0.949099 0 +3250 0.430112 0.949071 0 +3251 0.420087 0.949067 0 +3252 0.410056 0.9490730000000001 0 +3253 0.400027 0.949095 0 +3254 0.39 0.949157 0 +3255 0.379968 0.949209 0 +3256 0.369933 0.94922 0 +3257 0.359908 0.949247 0 +3258 0.349887 0.949267 0 +3259 0.339867 0.949331 0 +3260 0.329859 0.949394 0 +3261 0.319861 0.949447 0 +3262 0.309868 0.9495440000000001 0 +3263 0.299877 0.949623 0 +3264 0.289894 0.94973 0 +3265 0.27991 0.949803 0 +3266 0.269927 0.949874 0 +3267 0.259942 0.949924 0 +3268 0.249955 0.949959 0 +3269 0.239967 0.94998 0 +3270 0.229976 0.949991 0 +3271 0.219983 0.949996 0 +3272 0.209988 0.949998 0 +3273 0.199992 0.949999 0 +3274 0.189994 0.95 0 +3275 0.179996 0.95 0 +3276 0.169998 0.95 0 +3277 0.159998 0.95 0 +3278 0.149999 0.95 0 +3279 0.14 0.95 0 +3280 0.13 0.95 0 +3281 0.120001 0.95 0 +3282 0.110001 0.95 0 +3283 0.100003 0.95 0 +3284 0.0900041 0.949999 0 +3285 0.0800046 0.949998 0 +3286 0.07000439999999999 0.949998 0 +3287 0.0600039 0.949998 0 +3288 0.0500034 0.949998 0 +3289 0.0500028 0.939998 0 +3290 0.0500022 0.929998 0 +3291 0.0500016 0.919999 0 +3292 0.050001 0.909999 0 +3293 0.0500007 0.899999 0 +3294 0.0500003 0.889999 0 +3295 0.0500001 0.879999 0 +3296 0.05 0.87 0 +3297 0.0499999 0.86 0 +3298 0.0499999 0.85 0 +3299 0.0499999 0.84 0 +3300 0.0499999 0.83 0 +3301 0.0499999 0.82 0 +3302 0.05 0.8100000000000001 0 +3303 0.05 0.8 0 +3304 0.05 0.79 0 +3305 0.05 0.78 0 +3306 0.05 0.77 0 +3307 0.0500173 0.759999 0 +3308 0.0500598 0.749996 0 +3309 0.0501304 0.739991 0 +3310 0.0501701 0.729988 0 +3311 0.0502146 0.719984 0 +3312 0.0502028 0.709983 0 +3313 0.050187 0.699983 0 +3314 0.0501596 0.689983 0 +3315 0.0501186 0.679985 0 +3316 0.0500882 0.6699850000000001 0 +3317 0.0500574 0.659987 0 +3318 0.0500342 0.649988 0 +3319 0.049945 0.639988 0 +3320 0.0498808 0.629993 0 +3321 0.0498521 0.620003 0 +3322 0.0498764 0.610027 0 +3323 0.0500118 0.600038 0 +3324 0.0501824 0.590046 0 +3325 0.0503577 0.58005 0 +3326 0.0504338 0.570036 0 +3327 0.0504544 0.560022 0 +3328 0.0503981 0.54997 0 +3329 0.0503194 0.539919 0 +3330 0.0502762 0.529874 0 +3331 0.0502814 0.519825 0 +3332 0.0502926 0.5098 0 +3333 0.0503183 0.49977 0 +3334 0.0503254 0.489765 0 +3335 0.0503029 0.479747 0 +3336 0.0502462 0.469747 0 +3337 0.0501685 0.459735 0 +3338 0.0501444 0.449731 0 +3339 0.0502041 0.439723 0 +3340 0.0503418 0.429729 0 +3341 0.0505252 0.419734 0 +3342 0.0507294 0.409738 0 +3343 0.0509541 0.399735 0 +3344 0.0511206 0.389743 0 +3345 0.0512093 0.379742 0 +3346 0.0512002 0.369758 0 +3347 0.051116 0.359777 0 +3348 0.0509445 0.349802 0 +3349 0.0507485 0.33982 0 +3350 0.0505734 0.329833 0 +3351 0.0504017 0.319856 0 +3352 0.0502741 0.309876 0 +3353 0.05018 0.299894 0 +3354 0.0501232 0.28991 0 +3355 0.0500798 0.279927 0 +3356 0.0500536 0.269942 0 +3357 0.0500339 0.259956 0 +3358 0.0500193 0.249967 0 +3359 0.0500099 0.239976 0 +3360 0.0500047 0.229983 0 +3361 0.0500021 0.219988 0 +3362 0.0500009 0.209992 0 +3363 0.0500003 0.199994 0 +3364 0.0500001 0.189996 0 +3365 0.05 0.179998 0 +3366 0.05 0.169998 0 +3367 0.0499999 0.159999 0 +3368 0.0499999 0.15 0 +3369 0.0499998 0.14 0 +3370 0.0499998 0.13 0 +3371 0.05 0.120001 0 +3372 0.0500004 0.110001 0 +3373 0.0500008 0.100001 0 +3374 0.0500013 0.090002 0 +3375 0.0500017 0.0800025 0 +3376 0.0500019 0.0700021 0 +3377 0.0500019 0.0600018 0 +3378 0.783829 0.607114 0 +3379 0.789649 0.597186 0 +3380 0.794779 0.587056 0 +3381 0.800056 0.576523 0 +3382 0.807088 0.563826 0 +3383 0.806489 0.550007 0 +3384 0.806761 0.538822 0 +3385 0.807235 0.528464 0 +3386 0.807763 0.518727 0 +3387 0.808176 0.5102 0 +3388 0.808254 0.503914 0 +3389 0.813653 0.5007779999999999 0 +3390 0.821059 0.495896 0 +3391 0.8218 0.482604 0 +3392 0.828017 0.488876 0 +3393 0.815542 0.476336 0 +3394 0.810086 0.469552 0 +3395 0.805843 0.462226 0 +3396 0.8029809999999999 0.454189 0 +3397 0.801246 0.445341 0 +3398 0.79997 0.435909 0 +3399 0.798779 0.425929 0 +3400 0.797237 0.415654 0 +3401 0.7948539999999999 0.404535 0 +3402 0.790252 0.394011 0 +3403 0.785516 0.384418 0 +3404 0.780424 0.375369 0 +3405 0.775168 0.367417 0 +3406 0.7692 0.361097 0 +3407 0.774413 0.354329 0 +3408 0.778763 0.345581 0 +3409 0.780681 0.335371 0 +3410 0.771197 0.323859 0 +3411 0.781287 0.32519 0 +3412 0.761647 0.323443 0 +3413 0.753016 0.324863 0 +3414 0.749806 0.316816 0 +3415 0.744798 0.308017 0 +3416 0.737464 0.300033 0 +3417 0.729905 0.29263 0 +3418 0.7223619999999999 0.285072 0 +3419 0.715216 0.277218 0 +3420 0.707439 0.268701 0 +3421 0.698718 0.261194 0 +3422 0.690086 0.253754 0 +3423 0.681505 0.24652 0 +3424 0.672455 0.239735 0 +3425 0.662654 0.235399 0 +3426 0.654281 0.232192 0 +3427 0.648549 0.229982 0 +3428 0.647514 0.223953 0 +3429 0.6459 0.215848 0 +3430 0.634033 0.209155 0 +3431 0.643296 0.206864 0 +3432 0.625444 0.212394 0 +3433 0.617789 0.215579 0 +3434 0.612296 0.218123 0 +3435 0.607186 0.214735 0 +3436 0.599564 0.210051 0 +3437 0.589961 0.205332 0 +3438 0.578843 0.202186 0 +3439 0.568171 0.19986 0 +3440 0.557547 0.197935 0 +3441 0.54719 0.196345 0 +3442 0.537197 0.195211 0 +3443 0.527713 0.19474 0 +3444 0.518907 0.195125 0 +3445 0.51151 0.195661 0 +3446 0.50626 0.19614 0 +3447 0.503201 0.191856 0 +3448 0.498637 0.186178 0 +3449 0.492759 0.179734 0 +3450 0.485535 0.174057 0 +3451 0.470722 0.176645 0 +3452 0.477359 0.16829 0 +3453 0.466866 0.186014 0 +3454 0.465036 0.194675 0 +3455 0.456547 0.194403 0 +3456 0.447281 0.195545 0 +3457 0.437622 0.197467 0 +3458 0.42785 0.199956 0 +3459 0.41791 0.202498 0 +3460 0.407877 0.204732 0 +3461 0.397065 0.206559 0 +3462 0.383476 0.207708 0 +3463 0.371478 0.216554 0 +3464 0.361241 0.2231 0 +3465 0.35139 0.229014 0 +3466 0.341482 0.234683 0 +3467 0.331606 0.240463 0 +3468 0.321954 0.246668 0 +3469 0.312821 0.253607 0 +3470 0.303783 0.260643 0 +3471 0.2946 0.267359 0 +3472 0.284776 0.274134 0 +3473 0.272192 0.281694 0 +3474 0.266339 0.29387 0 +3475 0.261026 0.302987 0 +3476 0.255927 0.310746 0 +3477 0.250514 0.317782 0 +3478 0.245186 0.324498 0 +3479 0.240535 0.330884 0 +3480 0.235692 0.336369 0 +3481 0.231082 0.340624 0 +3482 0.225184 0.342977 0 +3483 0.218389 0.345023 0 +3484 0.210745 0.34753 0 +3485 0.207999 0.357645 0 +3486 0.203444 0.351293 0 +3487 0.212399 0.361389 0 +3488 0.21182 0.366971 0 +3489 0.212458 0.373962 0 +3490 0.213162 0.381105 0 +3491 0.213917 0.387316 0 +3492 0.207792 0.392375 0 +3493 0.206311 0.402845 0 +3494 0.205007 0.412655 0 +3495 0.203425 0.422359 0 +3496 0.201235 0.432039 0 +3497 0.198205 0.441564 0 +3498 0.194328 0.451904 0 +3499 0.188766 0.464985 0 +3500 0.190843 0.479081 0 +3501 0.191702 0.490869 0 +3502 0.192263 0.501989 0 +3503 0.192785 0.513146 0 +3504 0.193471 0.524265 0 +3505 0.194223 0.535439 0 +3506 0.194869 0.546586 0 +3507 0.195213 0.558489 0 +3508 0.194825 0.573222 0 +3509 0.20171 0.585742 0 +3510 0.207152 0.595872 0 +3511 0.212143 0.605249 0 +3512 0.216793 0.6139869999999999 0 +3513 0.221554 0.622372 0 +3514 0.226467 0.63 0 +3515 0.231753 0.636564 0 +3516 0.551637 0.804285 0 +3517 0.56534 0.802397 0 +3518 0.576896 0.800897 0 +3519 0.588643 0.799552 0 +3520 0.602638 0.798729 0 +3521 0.6140060000000001 0.790462 0 +3522 0.62357 0.7844449999999999 0 +3523 0.6326310000000001 0.7791169999999999 0 +3524 0.6415689999999999 0.7741209999999999 0 +3525 0.650103 0.768937 0 +3526 0.657913 0.7632330000000001 0 +3527 0.666071 0.771315 0 +3528 0.677888 0.771933 0 +3529 0.6883899999999999 0.764418 0 +3530 0.686949 0.772142 0 +3531 0.690196 0.756417 0 +3532 0.692114 0.74876 0 +3533 0.694493 0.741908 0 +3534 0.699267 0.7363420000000001 0 +3535 0.7053469999999999 0.730534 0 +3536 0.712009 0.724239 0 +3537 0.718967 0.717414 0 +3538 0.725975 0.710237 0 +3539 0.732742 0.702597 0 +3540 0.738804 0.6944709999999999 0 +3541 0.744208 0.686218 0 +3542 0.748828 0.677772 0 +3543 0.752756 0.670076 0 +3544 0.756076 0.663264 0 +3545 0.758405 0.6585259999999999 0 +3546 0.763599 0.657979 0 +3547 0.770848 0.657076 0 +3548 0.779051 0.655496 0 +3549 0.7878579999999999 0.653508 0 +3550 0.796129 0.6411289999999999 0 +3551 0.797143 0.65147 0 +3552 0.794649 0.630096 0 +3553 0.792724 0.616235 0 +3554 0.939997 0.0600024 0 +3555 0.939997 0.0700022 0 +3556 0.939998 0.0800019 0 +3557 0.939999 0.0900017 0 +3558 0.939999 0.100001 0 +3559 0.9399999999999999 0.110001 0 +3560 0.9399999999999999 0.120001 0 +3561 0.9399999999999999 0.130001 0 +3562 0.9399999999999999 0.140001 0 +3563 0.9399999999999999 0.15 0 +3564 0.9399999999999999 0.16 0 +3565 0.9399999999999999 0.17 0 +3566 0.9399999999999999 0.18 0 +3567 0.9399999999999999 0.19 0 +3568 0.9399999999999999 0.2 0 +3569 0.9399999999999999 0.21 0 +3570 0.9399999999999999 0.22 0 +3571 0.9399999999999999 0.23 0 +3572 0.9399999999999999 0.24 0 +3573 0.93999 0.25 0 +3574 0.9399650000000001 0.260001 0 +3575 0.939987 0.269975 0 +3576 0.940009 0.279942 0 +3577 0.9399960000000001 0.289886 0 +3578 0.939924 0.299834 0 +3579 0.939791 0.309785 0 +3580 0.939589 0.31975 0 +3581 0.9393629999999999 0.329725 0 +3582 0.939152 0.339727 0 +3583 0.9389960000000001 0.349743 0 +3584 0.938887 0.359776 0 +3585 0.938845 0.369811 0 +3586 0.938932 0.379846 0 +3587 0.939185 0.389877 0 +3588 0.939431 0.399899 0 +3589 0.93958 0.409927 0 +3590 0.9396 0.419952 0 +3591 0.9395289999999999 0.429978 0 +3592 0.939378 0.440005 0 +3593 0.9392160000000001 0.45009 0 +3594 0.939095 0.460177 0 +3595 0.939074 0.470303 0 +3596 0.939173 0.480423 0 +3597 0.9393899999999999 0.490547 0 +3598 0.939662 0.50061 0 +3599 0.939935 0.510657 0 +3600 0.940151 0.520648 0 +3601 0.940311 0.53061 0 +3602 0.9403550000000001 0.540565 0 +3603 0.94025 0.550489 0 +3604 0.940063 0.560407 0 +3605 0.939922 0.570336 0 +3606 0.939856 0.580284 0 +3607 0.939881 0.5902500000000001 0 +3608 0.9398919999999999 0.600218 0 +3609 0.939898 0.610194 0 +3610 0.939855 0.620175 0 +3611 0.939856 0.630149 0 +3612 0.939879 0.640127 0 +3613 0.939922 0.650107 0 +3614 0.9399690000000001 0.66009 0 +3615 0.940026 0.6700739999999999 0 +3616 0.940076 0.6800620000000001 0 +3617 0.940074 0.6900500000000001 0 +3618 0.94007 0.700039 0 +3619 0.940072 0.710031 0 +3620 0.940055 0.7200260000000001 0 +3621 0.940041 0.730021 0 +3622 0.940026 0.740017 0 +3623 0.94001 0.750013 0 +3624 0.939997 0.76001 0 +3625 0.939988 0.770008 0 +3626 0.939988 0.780006 0 +3627 0.939992 0.790004 0 +3628 0.939995 0.800003 0 +3629 0.939998 0.810002 0 +3630 0.939999 0.820001 0 +3631 0.9399999999999999 0.830001 0 +3632 0.939991 0.84 0 +3633 0.939992 0.85 0 +3634 0.939995 0.859999 0 +3635 0.939997 0.869999 0 +3636 0.939998 0.8799979999999999 0 +3637 0.939998 0.889998 0 +3638 0.939998 0.899997 0 +3639 0.939997 0.909995 0 +3640 0.9399960000000001 0.919995 0 +3641 0.9399960000000001 0.929995 0 +3642 0.9399960000000001 0.939995 0 +3643 0.254869 0.690647 0 +3644 0.261698 0.698231 0 +3645 0.268664 0.706032 0 +3646 0.275822 0.714027 0 +3647 0.283088 0.72207 0 +3648 0.291255 0.7304079999999999 0 +3649 0.300738 0.737256 0 +3650 0.30979 0.743358 0 +3651 0.318733 0.749273 0 +3652 0.327476 0.75508 0 +3653 0.336169 0.760531 0 +3654 0.34511 0.765187 0 +3655 0.341993 0.776539 0 +3656 0.347352 0.788337 0 +3657 0.360925 0.795123 0 +3658 0.351763 0.79813 0 +3659 0.370073 0.792866 0 +3660 0.378922 0.790747 0 +3661 0.387348 0.788848 0 +3662 0.3951 0.787346 0 +3663 0.402186 0.786844 0 +3664 0.409072 0.78875 0 +3665 0.416495 0.791837 0 +3666 0.42495 0.795552 0 +3667 0.433945 0.798515 0 +3668 0.443391 0.800877 0 +3669 0.452973 0.802677 0 +3670 0.462536 0.803912 0 +3671 0.47183 0.80442 0 +3672 0.48075 0.803943 0 +3673 0.488143 0.803521 0 +3674 0.493493 0.803166 0 +3675 0.496334 0.807604 0 +3676 0.500529 0.813418 0 +3677 0.5057120000000001 0.819989 0 +3678 0.511886 0.826604 0 +3679 0.526722 0.826559 0 +3680 0.518769 0.833153 0 +3681 0.534152 0.8198220000000001 0 +3682 0.5417149999999999 0.812705 0 +3683 0.0600018 0.0600015 0 +3684 0.0700016 0.0600011 0 +3685 0.0800014 0.0600008 0 +3686 0.0900012 0.0600004 0 +3687 0.100001 0.0600002 0 +3688 0.110001 0.06 0 +3689 0.120001 0.0599999 0 +3690 0.130001 0.0599999 0 +3691 0.14 0.0599999 0 +3692 0.15 0.0599999 0 +3693 0.16 0.0599999 0 +3694 0.17 0.0599999 0 +3695 0.18 0.0599999 0 +3696 0.19 0.0599999 0 +3697 0.2 0.06 0 +3698 0.21 0.06 0 +3699 0.22 0.06 0 +3700 0.230003 0.0600653 0 +3701 0.240018 0.0601833 0 +3702 0.250034 0.0602982 0 +3703 0.260054 0.0604208 0 +3704 0.27007 0.0605118 0 +3705 0.280089 0.0605942 0 +3706 0.290096 0.060619 0 +3707 0.300102 0.0606278 0 +3708 0.310103 0.0606232 0 +3709 0.320136 0.0606034 0 +3710 0.330156 0.0606008 0 +3711 0.34018 0.0606202 0 +3712 0.350188 0.0606314 0 +3713 0.360193 0.0606706 0 +3714 0.370189 0.0607224 0 +3715 0.3802 0.0607694 0 +3716 0.390212 0.0608134 0 +3717 0.400252 0.0608247 0 +3718 0.410267 0.0607767 0 +3719 0.420297 0.0607519 0 +3720 0.430312 0.0607194 0 +3721 0.440342 0.060632 0 +3722 0.450355 0.0604805 0 +3723 0.460341 0.0602427 0 +3724 0.470278 0.0600817 0 +3725 0.480214 0.0600784 0 +3726 0.490141 0.0601884 0 +3727 0.500068 0.0603748 0 +3728 0.510023 0.0606381 0 +3729 0.520006 0.0609276 0 +3730 0.530027 0.0611863 0 +3731 0.540056 0.0613366 0 +3732 0.550122 0.0613847 0 +3733 0.5601660000000001 0.0612827 0 +3734 0.570213 0.0611391 0 +3735 0.580242 0.0609813 0 +3736 0.590264 0.0608749 0 +3737 0.6002690000000001 0.0607857 0 +3738 0.610276 0.0607145 0 +3739 0.620265 0.0606673 0 +3740 0.630252 0.0606185 0 +3741 0.640222 0.0605356 0 +3742 0.6501749999999999 0.0603907 0 +3743 0.660131 0.0602313 0 +3744 0.670078 0.060069 0 +3745 0.680029 0.0599511 0 +3746 0.689992 0.0598917 0 +3747 0.699963 0.0598513 0 +3748 0.709947 0.0598495 0 +3749 0.719937 0.0598391 0 +3750 0.7299369999999999 0.0598543 0 +3751 0.739941 0.0598668 0 +3752 0.7499479999999999 0.0598961 0 +3753 0.759956 0.0599303 0 +3754 0.769963 0.0599581 0 +3755 0.779971 0.059977 0 +3756 0.789977 0.0599882 0 +3757 0.799983 0.0599944 0 +3758 0.809987 0.0599974 0 +3759 0.819991 0.0599988 0 +3760 0.829993 0.0599994 0 +3761 0.839995 0.0599996 0 +3762 0.849996 0.0599996 0 +3763 0.859997 0.0599996 0 +3764 0.869997 0.0599998 0 +3765 0.879997 0.0600002 0 +3766 0.889997 0.0600007 0 +3767 0.899996 0.0600012 0 +3768 0.909996 0.0600018 0 +3769 0.919996 0.0600023 0 +3770 0.929996 0.0600024 0 +3771 0.215405 0.655768 0 +3772 0.220214 0.648227 0 +3773 0.223136 0.669181 0 +3774 0.219869 0.664166 0 +3775 0.228252 0.675519 0 +3776 0.234271 0.682515 0 +3777 0.240567 0.689752 0 +3778 0.247056 0.697214 0 +3779 0.253706 0.704848 0 +3780 0.260566 0.7125939999999999 0 +3781 0.267341 0.720446 0 +3782 0.274387 0.729061 0 +3783 0.281814 0.7403149999999999 0 +3784 0.294506 0.746194 0 +3785 0.304233 0.751851 0 +3786 0.313246 0.757449 0 +3787 0.32194 0.763193 0 +3788 0.330969 0.769272 0 +3789 0.213631 0.66417 0 +3790 0.215998 0.672238 0 +3791 0.220532 0.680225 0 +3792 0.226275 0.687999 0 +3793 0.232437 0.695724 0 +3794 0.238791 0.703441 0 +3795 0.245326 0.711086 0 +3796 0.251982 0.718645 0 +3797 0.258662 0.726166 0 +3798 0.26421 0.734241 0 +3799 0.26876 0.743262 0 +3800 0.299277 0.760404 0 +3801 0.290043 0.756094 0 +3802 0.307812 0.765536 0 +3803 0.316135 0.77102 0 +3804 0.324053 0.7771439999999999 0 +3805 0.331847 0.7845490000000001 0 +3806 0.337951 0.79323 0 +3807 0.342831 0.801851 0 +3808 0.355849 0.80716 0 +3809 0.347141 0.810401 0 +3810 0.364852 0.80459 0 +3811 0.373876 0.802277 0 +3812 0.382487 0.799948 0 +3813 0.390423 0.797337 0 +3814 0.397212 0.794636 0 +3815 0.402108 0.792367 0 +3816 0.280042 0.752974 0 +3817 0.269888 0.753038 0 +3818 0.406672 0.795414 0 +3819 0.41337 0.7997379999999999 0 +3820 0.421702 0.8043090000000001 0 +3821 0.431286 0.808179 0 +3822 0.441232 0.810715 0 +3823 0.451437 0.812624 0 +3824 0.461671 0.813902 0 +3825 0.471962 0.813714 0 +3826 0.481488 0.812418 0 +3827 0.489687 0.810381 0 +3828 0.492727 0.817882 0 +3829 0.497536 0.8254050000000001 0 +3830 0.5036079999999999 0.832687 0 +3831 0.510538 0.839544 0 +3832 0.52581 0.839902 0 +3833 0.51784 0.84631 0 +3834 0.533588 0.833394 0 +3835 0.540683 0.826782 0 +3836 0.547497 0.820559 0 +3837 0.556305 0.816347 0 +3838 0.5668 0.813658 0 +3839 0.577584 0.811679 0 +3840 0.588244 0.811079 0 +3841 0.5988790000000001 0.812033 0 +3842 0.6288049999999999 0.793163 0 +3843 0.6205889999999999 0.799387 0 +3844 0.63748 0.787884 0 +3845 0.646351 0.782848 0 +3846 0.655443 0.777686 0 +3847 0.613224 0.807208 0 +3848 0.607949 0.815761 0 +3849 0.798434 0.602952 0 +3850 0.803495 0.59251 0 +3851 0.808895 0.582837 0 +3852 0.81563 0.573739 0 +3853 0.81685 0.538219 0 +3854 0.81741 0.548247 0 +3855 0.816898 0.528324 0 +3856 0.8169650000000001 0.518346 0 +3857 0.816546 0.508788 0 +3858 0.827175 0.505215 0 +3859 0.834541 0.49517 0 +3860 0.83474 0.48165 0 +3861 0.840996 0.487379 0 +3862 0.828318 0.475834 0 +3863 0.822025 0.470254 0 +3864 0.816509 0.464517 0 +3865 0.812329 0.458817 0 +3866 0.810624 0.451902 0 +3867 0.809764 0.443621 0 +3868 0.80924 0.434566 0 +3869 0.80874 0.424978 0 +3870 0.808196 0.414143 0 +3871 0.807705 0.400461 0 +3872 0.799754 0.388691 0 +3873 0.793979 0.378839 0 +3874 0.788436 0.369572 0 +3875 0.782151 0.360772 0 +3876 0.81926 0.558387 0 +3877 0.8242969999999999 0.5670230000000001 0 +3878 0.929996 0.939997 0 +3879 0.919997 0.939998 0 +3880 0.9099969999999999 0.939999 0 +3881 0.899998 0.939999 0 +3882 0.889998 0.9399999999999999 0 +3883 0.8799979999999999 0.9399999999999999 0 +3884 0.869999 0.9399999999999999 0 +3885 0.859999 0.9399999999999999 0 +3886 0.8499989999999999 0.9399999999999999 0 +3887 0.8399990000000001 0.939993 0 +3888 0.829998 0.939961 0 +3889 0.819997 0.93993 0 +3890 0.809997 0.939912 0 +3891 0.799996 0.939899 0 +3892 0.789995 0.939891 0 +3893 0.779995 0.939891 0 +3894 0.769995 0.939916 0 +3895 0.759996 0.9399380000000001 0 +3896 0.749997 0.939954 0 +3897 0.739998 0.939961 0 +3898 0.729998 0.9399690000000001 0 +3899 0.7199989999999999 0.93998 0 +3900 0.709999 0.939989 0 +3901 0.699999 0.93999 0 +3902 0.689999 0.93993 0 +3903 0.679997 0.939918 0 +3904 0.669995 0.939904 0 +3905 0.659995 0.939897 0 +3906 0.649995 0.939891 0 +3907 0.639996 0.939877 0 +3908 0.630011 0.939782 0 +3909 0.620028 0.939651 0 +3910 0.610059 0.939524 0 +3911 0.600088 0.939454 0 +3912 0.590131 0.939347 0 +3913 0.580171 0.939214 0 +3914 0.570204 0.939032 0 +3915 0.560227 0.938816 0 +3916 0.550231 0.938568 0 +3917 0.540214 0.938375 0 +3918 0.530158 0.938342 0 +3919 0.52011 0.938608 0 +3920 0.510096 0.93899 0 +3921 0.500096 0.939329 0 +3922 0.490128 0.939497 0 +3923 0.480173 0.939456 0 +3924 0.470224 0.93928 0 +3925 0.460254 0.939016 0 +3926 0.450268 0.9388 0 +3927 0.440253 0.938658 0 +3928 0.430214 0.938608 0 +3929 0.420167 0.938577 0 +3930 0.410115 0.938588 0 +3931 0.40006 0.938638 0 +3932 0.39 0.938706 0 +3933 0.379933 0.93876 0 +3934 0.369872 0.938798 0 +3935 0.359814 0.938839 0 +3936 0.349765 0.9389110000000001 0 +3937 0.339742 0.938992 0 +3938 0.329729 0.939047 0 +3939 0.319731 0.939175 0 +3940 0.309736 0.939287 0 +3941 0.299763 0.939436 0 +3942 0.289787 0.939567 0 +3943 0.27982 0.939697 0 +3944 0.269851 0.9397990000000001 0 +3945 0.259882 0.939883 0 +3946 0.249909 0.939932 0 +3947 0.239932 0.939964 0 +3948 0.22995 0.939983 0 +3949 0.219964 0.939992 0 +3950 0.209974 0.939997 0 +3951 0.199982 0.939993 0 +3952 0.189988 0.939993 0 +3953 0.179992 0.939995 0 +3954 0.169995 0.939997 0 +3955 0.159996 0.939999 0 +3956 0.149998 0.9399999999999999 0 +3957 0.139999 0.9399999999999999 0 +3958 0.13 0.9399999999999999 0 +3959 0.120001 0.9399999999999999 0 +3960 0.110001 0.9399999999999999 0 +3961 0.100002 0.9399999999999999 0 +3962 0.09000320000000001 0.939999 0 +3963 0.08000350000000001 0.939998 0 +3964 0.0700033 0.939998 0 +3965 0.0600031 0.939998 0 +3966 0.75974 0.313811 0 +3967 0.756458 0.301393 0 +3968 0.745619 0.292734 0 +3969 0.737141 0.285692 0 +3970 0.72982 0.278781 0 +3971 0.72327 0.270742 0 +3972 0.716658 0.259795 0 +3973 0.705525 0.252469 0 +3974 0.696508 0.245204 0 +3975 0.688228 0.237159 0 +3976 0.678356 0.227247 0 +3977 0.665243 0.225307 0 +3978 0.655546 0.224033 0 +3979 0.654731 0.214978 0 +3980 0.652879 0.205591 0 +3981 0.6402409999999999 0.197455 0 +3982 0.650302 0.195956 0 +3983 0.630077 0.199846 0 +3984 0.620704 0.204222 0 +3985 0.612874 0.209066 0 +3986 0.605585 0.202252 0 +3987 0.594904 0.19405 0 +3988 0.580742 0.191566 0 +3989 0.569165 0.189544 0 +3990 0.558299 0.187749 0 +3991 0.54756 0.186173 0 +3992 0.537046 0.18506 0 +3993 0.526884 0.185173 0 +3994 0.517509 0.186572 0 +3995 0.509501 0.188861 0 +3996 0.488032 0.830722 0 +3997 0.483699 0.821439 0 +3998 0.494805 0.838907 0 +3999 0.5024 0.846068 0 +4000 0.50991 0.852817 0 +4001 0.524934 0.853303 0 +4002 0.517296 0.8597860000000001 0 +4003 0.532828 0.846882 0 +4004 0.540408 0.840305 0 +4005 0.547265 0.833264 0 +4006 0.551257 0.826776 0 +4007 0.558706 0.826345 0 +4008 0.568223 0.82423 0 +4009 0.578099 0.8221580000000001 0 +4010 0.58787 0.821536 0 +4011 0.597113 0.822055 0 +4012 0.604375 0.82216 0 +4013 0.621092 0.814584 0 +4014 0.614725 0.8222429999999999 0 +4015 0.626584 0.807044 0 +4016 0.633917 0.801612 0 +4017 0.642032 0.796675 0 +4018 0.650541 0.791926 0 +4019 0.659309 0.78738 0 +4020 0.668783 0.783413 0 +4021 0.67888 0.781505 0 +4022 0.688062 0.780013 0 +4023 0.693358 0.772099 0 +4024 0.696369 0.777873 0 +4025 0.696422 0.766333 0 +4026 0.698531 0.75831 0 +4027 0.699361 0.750556 0 +4028 0.699546 0.744849 0 +4029 0.704501 0.741987 0 +4030 0.711244 0.737407 0 +4031 0.718701 0.73143 0 +4032 0.726063 0.7244660000000001 0 +4033 0.7334079999999999 0.717029 0 +4034 0.741138 0.70895 0 +4035 0.747433 0.699707 0 +4036 0.752869 0.690592 0 +4037 0.757252 0.681804 0 +4038 0.760483 0.672938 0 +4039 0.762758 0.665034 0 +4040 0.456949 0.184394 0 +4041 0.446332 0.185358 0 +4042 0.436152 0.187376 0 +4043 0.426202 0.189991 0 +4044 0.41642 0.192634 0 +4045 0.406823 0.194751 0 +4046 0.397472 0.19589 0 +4047 0.387795 0.193744 0 +4048 0.355421 0.214659 0 +4049 0.364408 0.208259 0 +4050 0.345892 0.220259 0 +4051 0.336082 0.225607 0 +4052 0.326188 0.230967 0 +4053 0.315949 0.237143 0 +4054 0.306728 0.244854 0 +4055 0.298084 0.251997 0 +4056 0.289022 0.258594 0 +4057 0.279453 0.264225 0 +4058 0.268894 0.268809 0 +4059 0.252122 0.29883 0 +4060 0.255784 0.290431 0 +4061 0.247404 0.30607 0 +4062 0.242346 0.312889 0 +4063 0.237306 0.319626 0 +4064 0.233159 0.326203 0 +4065 0.230151 0.332238 0 +4066 0.228061 0.336574 0 +4067 0.258096 0.280688 0 +4068 0.257572 0.270486 0 +4069 0.372624 0.200225 0 +4070 0.377931 0.190301 0 +4071 0.22305 0.33704 0 +4072 0.215959 0.338016 0 +4073 0.208045 0.34019 0 +4074 0.199548 0.34356 0 +4075 0.195777 0.356646 0 +4076 0.190969 0.348096 0 +4077 0.202308 0.365061 0 +4078 0.204433 0.374386 0 +4079 0.205141 0.382617 0 +4080 0.0600023 0.929998 0 +4081 0.0600017 0.919999 0 +4082 0.0600012 0.909999 0 +4083 0.0600007 0.899999 0 +4084 0.0600004 0.889999 0 +4085 0.0600002 0.879999 0 +4086 0.06 0.87 0 +4087 0.0599999 0.86 0 +4088 0.0599999 0.85 0 +4089 0.0599999 0.84 0 +4090 0.0599999 0.83 0 +4091 0.0599999 0.82 0 +4092 0.0599999 0.8100000000000001 0 +4093 0.06 0.8 0 +4094 0.06 0.79 0 +4095 0.06 0.78 0 +4096 0.0600285 0.769997 0 +4097 0.0600963 0.759987 0 +4098 0.0601969 0.749973 0 +4099 0.0602799 0.739966 0 +4100 0.0603651 0.729956 0 +4101 0.0604017 0.719951 0 +4102 0.0604101 0.709947 0 +4103 0.0603944 0.699941 0 +4104 0.0603237 0.689944 0 +4105 0.0602661 0.679939 0 +4106 0.0601945 0.669943 0 +4107 0.0601318 0.659938 0 +4108 0.0600176 0.649932 0 +4109 0.0599055 0.639935 0 +4110 0.0598101 0.629948 0 +4111 0.0597288 0.619978 0 +4112 0.059765 0.610004 0 +4113 0.059886 0.600027 0 +4114 0.0600876 0.590039 0 +4115 0.0602942 0.580036 0 +4116 0.060408 0.570017 0 +4117 0.0604181 0.559962 0 +4118 0.0603682 0.549884 0 +4119 0.0602728 0.539818 0 +4120 0.0602484 0.529752 0 +4121 0.0602584 0.519719 0 +4122 0.0603176 0.509686 0 +4123 0.0603912 0.499654 0 +4124 0.0604234 0.489625 0 +4125 0.0604008 0.479598 0 +4126 0.0603114 0.469584 0 +4127 0.0601979 0.459564 0 +4128 0.0601806 0.449557 0 +4129 0.0603041 0.439555 0 +4130 0.0605281 0.429555 0 +4131 0.0608119 0.419556 0 +4132 0.061122 0.409547 0 +4133 0.0614071 0.399543 0 +4134 0.0616252 0.389539 0 +4135 0.0617527 0.379538 0 +4136 0.0617305 0.369541 0 +4137 0.0615667 0.359567 0 +4138 0.0613333 0.349582 0 +4139 0.0610801 0.339595 0 +4140 0.0608149 0.329638 0 +4141 0.0605813 0.319676 0 +4142 0.0603893 0.309714 0 +4143 0.0602635 0.299751 0 +4144 0.0601736 0.289795 0 +4145 0.0601215 0.279835 0 +4146 0.0600799 0.269871 0 +4147 0.0600515 0.259902 0 +4148 0.0600314 0.249927 0 +4149 0.0600175 0.239947 0 +4150 0.060009 0.229962 0 +4151 0.0600042 0.219973 0 +4152 0.0600019 0.209981 0 +4153 0.0600008 0.199987 0 +4154 0.0600057 0.189991 0 +4155 0.0600129 0.179994 0 +4156 0.0600127 0.169996 0 +4157 0.0600085 0.159998 0 +4158 0.0600046 0.149999 0 +4159 0.0600021 0.139999 0 +4160 0.0600009 0.13 0 +4161 0.0600006 0.12 0 +4162 0.0600007 0.110001 0 +4163 0.060001 0.100001 0 +4164 0.0600013 0.0900015 0 +4165 0.0600016 0.0800017 0 +4166 0.0600017 0.0700016 0 +4167 0.664543 0.214581 0 +4168 0.662648 0.20454 0 +4169 0.660191 0.194612 0 +4170 0.6481130000000001 0.186148 0 +4171 0.657975 0.184893 0 +4172 0.637659 0.187339 0 +4173 0.6245230000000001 0.188502 0 +4174 0.6142840000000001 0.196046 0 +4175 0.606178 0.18852 0 +4176 0.6138130000000001 0.182657 0 +4177 0.929997 0.0700022 0 +4178 0.929998 0.0800019 0 +4179 0.929999 0.0900016 0 +4180 0.929999 0.100001 0 +4181 0.929999 0.110001 0 +4182 0.93 0.120001 0 +4183 0.93 0.130001 0 +4184 0.93 0.140001 0 +4185 0.93 0.15 0 +4186 0.93 0.16 0 +4187 0.93 0.17 0 +4188 0.93 0.18 0 +4189 0.93 0.19 0 +4190 0.93 0.2 0 +4191 0.93 0.21 0 +4192 0.93 0.22 0 +4193 0.929994 0.230001 0 +4194 0.929959 0.240003 0 +4195 0.92992 0.250005 0 +4196 0.9299190000000001 0.259973 0 +4197 0.929964 0.26993 0 +4198 0.930022 0.279857 0 +4199 0.930047 0.289777 0 +4200 0.929964 0.299691 0 +4201 0.929746 0.309615 0 +4202 0.92945 0.31955 0 +4203 0.929088 0.329512 0 +4204 0.928802 0.339516 0 +4205 0.928528 0.349551 0 +4206 0.92832 0.359612 0 +4207 0.928219 0.36969 0 +4208 0.928387 0.379771 0 +4209 0.928781 0.389829 0 +4210 0.929187 0.39987 0 +4211 0.92943 0.40989 0 +4212 0.929477 0.419907 0 +4213 0.929362 0.429923 0 +4214 0.92914 0.440026 0 +4215 0.928906 0.450165 0 +4216 0.92874 0.460374 0 +4217 0.928698 0.470594 0 +4218 0.928889 0.480837 0 +4219 0.929238 0.491027 0 +4220 0.929651 0.501158 0 +4221 0.930036 0.5112100000000001 0 +4222 0.930388 0.521195 0 +4223 0.930634 0.531126 0 +4224 0.930673 0.540998 0 +4225 0.930503 0.55085 0 +4226 0.930219 0.560724 0 +4227 0.92994 0.570622 0 +4228 0.92984 0.580556 0 +4229 0.929853 0.590509 0 +4230 0.929883 0.600467 0 +4231 0.929844 0.6104270000000001 0 +4232 0.929818 0.620376 0 +4233 0.929824 0.6303339999999999 0 +4234 0.929859 0.64029 0 +4235 0.929947 0.650257 0 +4236 0.9300580000000001 0.6602209999999999 0 +4237 0.930155 0.670194 0 +4238 0.930185 0.68016 0 +4239 0.930206 0.690133 0 +4240 0.930218 0.700115 0 +4241 0.930189 0.710098 0 +4242 0.930158 0.720079 0 +4243 0.93011 0.730063 0 +4244 0.930064 0.740051 0 +4245 0.930024 0.75004 0 +4246 0.929988 0.760031 0 +4247 0.929984 0.770023 0 +4248 0.92998 0.780016 0 +4249 0.929982 0.790011 0 +4250 0.929988 0.8000080000000001 0 +4251 0.929993 0.810005 0 +4252 0.9299770000000001 0.820003 0 +4253 0.929952 0.83 0 +4254 0.9299539999999999 0.8399990000000001 0 +4255 0.929952 0.849998 0 +4256 0.929965 0.859997 0 +4257 0.92998 0.869997 0 +4258 0.92999 0.879997 0 +4259 0.929994 0.889997 0 +4260 0.929996 0.899996 0 +4261 0.929997 0.909996 0 +4262 0.929996 0.919996 0 +4263 0.929996 0.929996 0 +4264 0.505718 0.18148 0 +4265 0.500111 0.174153 0 +4266 0.493 0.167305 0 +4267 0.484774 0.161048 0 +4268 0.468469 0.161802 0 +4269 0.476694 0.154352 0 +4270 0.45849 0.171141 0 +4271 0.196049 0.401932 0 +4272 0.19616 0.391995 0 +4273 0.195651 0.411291 0 +4274 0.194734 0.420604 0 +4275 0.192952 0.429539 0 +4276 0.18968 0.438174 0 +4277 0.185138 0.446827 0 +4278 0.179134 0.455868 0 +4279 0.181921 0.492389 0 +4280 0.180503 0.482078 0 +4281 0.182457 0.503135 0 +4282 0.183023 0.513907 0 +4283 0.1837 0.524685 0 +4284 0.184472 0.535482 0 +4285 0.185017 0.546337 0 +4286 0.184773 0.557034 0 +4287 0.182841 0.568115 0 +4288 0.198899 0.601785 0 +4289 0.193091 0.59284 0 +4290 0.204083 0.61049 0 +4291 0.209046 0.619282 0 +4292 0.214006 0.6277700000000001 0 +4293 0.219731 0.635433 0 +4294 0.225984 0.641866 0 +4295 0.770509 0.665509 0 +4296 0.77912 0.665116 0 +4297 0.788184 0.663673 0 +4298 0.797508 0.661987 0 +4299 0.806667 0.6499509999999999 0 +4300 0.807096 0.660355 0 +4301 0.805867 0.6394879999999999 0 +4302 0.805047 0.629019 0 +4303 0.804949 0.617804 0 +4304 0.807951 0.606882 0 +4305 0.811978 0.597307 0 +4306 0.816979 0.588527 0 +4307 0.823164 0.580694 0 +4308 0.829991 0.574231 0 +4309 0.83229 0.561959 0 +4310 0.837253 0.568956 0 +4311 0.828247 0.554829 0 +4312 0.826947 0.546557 0 +4313 0.826534 0.537428 0 +4314 0.826482 0.5276 0 +4315 0.826616 0.517477 0 +4316 0.214968 0.330342 0 +4317 0.223264 0.330593 0 +4318 0.206104 0.332018 0 +4319 0.196962 0.335062 0 +4320 0.187693 0.339033 0 +4321 0.181856 0.353102 0 +4322 0.178308 0.343654 0 +4323 0.186746 0.361926 0 +4324 0.19251 0.36997 0 +4325 0.197392 0.375633 0 +4326 0.19587 0.382733 0 +4327 0.186096 0.584228 0 +4328 0.177729 0.57778 0 +4329 0.177555 0.471827 0 +4330 0.171312 0.463546 0 +4331 0.204646 0.323012 0 +4332 0.215148 0.321547 0 +4333 0.194602 0.325791 0 +4334 0.184905 0.329692 0 +4335 0.175281 0.334102 0 +4336 0.168656 0.348559 0 +4337 0.165624 0.33874 0 +4338 0.172255 0.358423 0 +4339 0.177307 0.368186 0 +4340 0.18422 0.379012 0 +4341 0.185205 0.391441 0 +4342 0.186039 0.401674 0 +4343 0.186431 0.411038 0 +4344 0.186442 0.419649 0 +4345 0.185596 0.427114 0 +4346 0.182038 0.434119 0 +4347 0.177153 0.441393 0 +4348 0.171098 0.448916 0 +4349 0.164278 0.456428 0 +4350 0.164104 0.470084 0 +4351 0.157372 0.463776 0 +4352 0.169367 0.476544 0 +4353 0.171478 0.484733 0 +4354 0.172382 0.494149 0 +4355 0.172751 0.504261 0 +4356 0.17322 0.514649 0 +4357 0.173969 0.525068 0 +4358 0.174841 0.535429 0 +4359 0.17553 0.545569 0 +4360 0.1753 0.55531 0 +4361 0.173665 0.564582 0 +4362 0.169579 0.572821 0 +4363 0.171742 0.585838 0 +4364 0.164404 0.580371 0 +4365 0.178787 0.5923389999999999 0 +4366 0.185419 0.5996939999999999 0 +4367 0.191245 0.607797 0 +4368 0.19657 0.616289 0 +4369 0.201554 0.625041 0 +4370 0.206714 0.63366 0 +4371 0.212732 0.642111 0 +4372 0.919997 0.929998 0 +4373 0.9099969999999999 0.929998 0 +4374 0.899998 0.929999 0 +4375 0.889998 0.93 0 +4376 0.8799979999999999 0.93 0 +4377 0.869999 0.93 0 +4378 0.859999 0.93 0 +4379 0.849998 0.929976 0 +4380 0.839993 0.92992 0 +4381 0.829989 0.92986 0 +4382 0.819986 0.92981 0 +4383 0.809983 0.929773 0 +4384 0.79998 0.92975 0 +4385 0.789979 0.929749 0 +4386 0.779981 0.9297879999999999 0 +4387 0.769984 0.929825 0 +4388 0.759987 0.929839 0 +4389 0.74999 0.929846 0 +4390 0.739993 0.929874 0 +4391 0.7299949999999999 0.929908 0 +4392 0.719996 0.929916 0 +4393 0.709996 0.929917 0 +4394 0.699994 0.929861 0 +4395 0.689988 0.929828 0 +4396 0.679983 0.929813 0 +4397 0.66998 0.929809 0 +4398 0.65998 0.929824 0 +4399 0.649985 0.929836 0 +4400 0.64 0.929776 0 +4401 0.630031 0.929585 0 +4402 0.620075 0.929375 0 +4403 0.610118 0.929242 0 +4404 0.600177 0.9291469999999999 0 +4405 0.590238 0.929037 0 +4406 0.580297 0.928849 0 +4407 0.5703510000000001 0.928633 0 +4408 0.560373 0.928374 0 +4409 0.550358 0.928073 0 +4410 0.540285 0.927783 0 +4411 0.530182 0.927744 0 +4412 0.520109 0.928188 0 +4413 0.510097 0.928816 0 +4414 0.500131 0.929308 0 +4415 0.490217 0.929487 0 +4416 0.480319 0.9293670000000001 0 +4417 0.470413 0.929021 0 +4418 0.460476 0.928634 0 +4419 0.450501 0.928293 0 +4420 0.440461 0.928113 0 +4421 0.430394 0.928016 0 +4422 0.420314 0.927982 0 +4423 0.410222 0.928003 0 +4424 0.400122 0.928067 0 +4425 0.390007 0.928155 0 +4426 0.37989 0.928213 0 +4427 0.369774 0.928285 0 +4428 0.35968 0.928384 0 +4429 0.349623 0.92849 0 +4430 0.339572 0.928575 0 +4431 0.329552 0.928698 0 +4432 0.319541 0.928835 0 +4433 0.309561 0.928992 0 +4434 0.299591 0.929194 0 +4435 0.289641 0.929399 0 +4436 0.27969 0.929579 0 +4437 0.269748 0.929737 0 +4438 0.259798 0.929823 0 +4439 0.249844 0.929894 0 +4440 0.239882 0.929943 0 +4441 0.229914 0.929973 0 +4442 0.219938 0.929989 0 +4443 0.209956 0.929972 0 +4444 0.199969 0.929968 0 +4445 0.189979 0.929963 0 +4446 0.179985 0.929963 0 +4447 0.16999 0.929972 0 +4448 0.159994 0.929983 0 +4449 0.149996 0.929991 0 +4450 0.139998 0.929996 0 +4451 0.129999 0.929998 0 +4452 0.12 0.929999 0 +4453 0.110001 0.929999 0 +4454 0.100002 0.929999 0 +4455 0.0900022 0.929999 0 +4456 0.0800024 0.929999 0 +4457 0.0700025 0.929998 0 +4458 0.204603 0.651295 0 +4459 0.204482 0.6642670000000001 0 +4460 0.206882 0.6750699999999999 0 +4461 0.212017 0.68469 0 +4462 0.217797 0.69328 0 +4463 0.22398 0.701543 0 +4464 0.23027 0.709533 0 +4465 0.236694 0.717279 0 +4466 0.243242 0.724616 0 +4467 0.249635 0.731602 0 +4468 0.255109 0.7387089999999999 0 +4469 0.259102 0.746283 0 +4470 0.260703 0.754508 0 +4471 0.269747 0.761756 0 +4472 0.261147 0.762665 0 +4473 0.278091 0.762413 0 +4474 0.286447 0.764923 0 +4475 0.294502 0.768805 0 +4476 0.302348 0.773352 0 +4477 0.310013 0.778406 0 +4478 0.317082 0.784405 0 +4479 0.323814 0.791118 0 +4480 0.329497 0.798879 0 +4481 0.334487 0.806594 0 +4482 0.338935 0.814495 0 +4483 0.351025 0.819058 0 +4484 0.342844 0.82219 0 +4485 0.359729 0.816375 0 +4486 0.368773 0.814032 0 +4487 0.377941 0.8117529999999999 0 +4488 0.386842 0.809074 0 +4489 0.790583 0.351263 0 +4490 0.791259 0.33778 0 +4491 0.791507 0.326819 0 +4492 0.78107 0.314964 0 +4493 0.7914949999999999 0.316544 0 +4494 0.770636 0.313944 0 +4495 0.0700016 0.0700012 0 +4496 0.0800014 0.0700008 0 +4497 0.0900012 0.07000049999999999 0 +4498 0.100001 0.0700003 0 +4499 0.110001 0.0700001 0 +4500 0.120001 0.07000000000000001 0 +4501 0.130001 0.0699999 0 +4502 0.14 0.0699999 0 +4503 0.15 0.0699999 0 +4504 0.16 0.0699999 0 +4505 0.17 0.0699999 0 +4506 0.18 0.0699999 0 +4507 0.19 0.0699999 0 +4508 0.2 0.07000000000000001 0 +4509 0.21 0.07000000000000001 0 +4510 0.22001 0.07009410000000001 0 +4511 0.230034 0.0702363 0 +4512 0.240059 0.070414 0 +4513 0.250095 0.0706061 0 +4514 0.260127 0.07074229999999999 0 +4515 0.270165 0.0708828 0 +4516 0.280188 0.07095890000000001 0 +4517 0.290209 0.0710047 0 +4518 0.300225 0.0710216 0 +4519 0.31027 0.0709584 0 +4520 0.320301 0.0708988 0 +4521 0.330332 0.0708883 0 +4522 0.340344 0.07088899999999999 0 +4523 0.350355 0.0709283 0 +4524 0.360354 0.07098640000000001 0 +4525 0.370373 0.071077 0 +4526 0.380392 0.0711685 0 +4527 0.390441 0.0712255 0 +4528 0.40047 0.07122240000000001 0 +4529 0.410529 0.071226 0 +4530 0.420571 0.07117320000000001 0 +4531 0.430645 0.0710756 0 +4532 0.440711 0.070961 0 +4533 0.450741 0.0707314 0 +4534 0.460665 0.0703034 0 +4535 0.470556 0.0699753 0 +4536 0.480404 0.0699283 0 +4537 0.490244 0.0701045 0 +4538 0.500119 0.0703524 0 +4539 0.510049 0.0707333 0 +4540 0.520025 0.0711642 0 +4541 0.530052 0.0715616 0 +4542 0.540158 0.07185610000000001 0 +4543 0.550248 0.07189429999999999 0 +4544 0.560327 0.0717588 0 +4545 0.570395 0.0715702 0 +4546 0.580437 0.0713598 0 +4547 0.59046 0.07122729999999999 0 +4548 0.600476 0.07111629999999999 0 +4549 0.61047 0.0710324 0 +4550 0.620455 0.07098459999999999 0 +4551 0.630423 0.0709359 0 +4552 0.64037 0.0708024 0 +4553 0.650318 0.07060139999999999 0 +4554 0.660241 0.07034169999999999 0 +4555 0.670156 0.07008259999999999 0 +4556 0.680076 0.06988419999999999 0 +4557 0.690007 0.0697671 0 +4558 0.699958 0.0697398 0 +4559 0.709916 0.0697419 0 +4560 0.719902 0.06974080000000001 0 +4561 0.729893 0.0697448 0 +4562 0.739896 0.0697781 0 +4563 0.749903 0.069838 0 +4564 0.759915 0.06988659999999999 0 +4565 0.769927 0.06992810000000001 0 +4566 0.77994 0.0699583 0 +4567 0.789953 0.0699775 0 +4568 0.799963 0.0699885 0 +4569 0.809972 0.0699944 0 +4570 0.819979 0.0699974 0 +4571 0.829985 0.0699987 0 +4572 0.839989 0.0699993 0 +4573 0.849992 0.06999950000000001 0 +4574 0.859994 0.0699997 0 +4575 0.869995 0.07000000000000001 0 +4576 0.879996 0.0700004 0 +4577 0.889996 0.0700008 0 +4578 0.899996 0.0700013 0 +4579 0.9099969999999999 0.0700017 0 +4580 0.919997 0.07000199999999999 0 +4581 0.0700018 0.919999 0 +4582 0.0700012 0.909999 0 +4583 0.0700008 0.899999 0 +4584 0.0700004 0.889999 0 +4585 0.0700002 0.879999 0 +4586 0.0700001 0.87 0 +4587 0.07000000000000001 0.86 0 +4588 0.0699999 0.85 0 +4589 0.0699999 0.84 0 +4590 0.0699999 0.83 0 +4591 0.0699999 0.82 0 +4592 0.0699999 0.8100000000000001 0 +4593 0.07000000000000001 0.8 0 +4594 0.07000000000000001 0.79 0 +4595 0.0700244 0.779993 0 +4596 0.0701054 0.769974 0 +4597 0.0702228 0.759951 0 +4598 0.0703622 0.749934 0 +4599 0.07050289999999999 0.739911 0 +4600 0.0706373 0.729895 0 +4601 0.0707035 0.719879 0 +4602 0.0707125 0.709857 0 +4603 0.07063460000000001 0.699858 0 +4604 0.0705441 0.689837 0 +4605 0.0704323 0.679841 0 +4606 0.070316 0.669815 0 +4607 0.0701856 0.659806 0 +4608 0.0700455 0.649799 0 +4609 0.0699029 0.639806 0 +4610 0.0697234 0.62984 0 +4611 0.06957729999999999 0.6198939999999999 0 +4612 0.0695448 0.609943 0 +4613 0.06965929999999999 0.599984 0 +4614 0.06993920000000001 0.590021 0 +4615 0.0701854 0.5800110000000001 0 +4616 0.07033399999999999 0.569964 0 +4617 0.0703592 0.559866 0 +4618 0.0702434 0.549779 0 +4619 0.0701291 0.539705 0 +4620 0.07007330000000001 0.5296650000000001 0 +4621 0.0701518 0.519638 0 +4622 0.0703112 0.509592 0 +4623 0.0704554 0.49955 0 +4624 0.0705513 0.48949 0 +4625 0.0705248 0.479434 0 +4626 0.0703645 0.469401 0 +4627 0.0702178 0.459379 0 +4628 0.0702203 0.449357 0 +4629 0.0704033 0.439346 0 +4630 0.0707222 0.429345 0 +4631 0.071161 0.419317 0 +4632 0.0715746 0.409295 0 +4633 0.07195219999999999 0.399272 0 +4634 0.0722767 0.389215 0 +4635 0.07240190000000001 0.379177 0 +4636 0.0723206 0.369181 0 +4637 0.0720951 0.359174 0 +4638 0.07177269999999999 0.349174 0 +4639 0.07141840000000001 0.339229 0 +4640 0.0710649 0.32929 0 +4641 0.07073119999999999 0.31936 0 +4642 0.07048119999999999 0.309434 0 +4643 0.0703059 0.299528 0 +4644 0.0702136 0.289612 0 +4645 0.07015100000000001 0.279693 0 +4646 0.070101 0.269762 0 +4647 0.0700602 0.259819 0 +4648 0.0700339 0.249865 0 +4649 0.07001839999999999 0.239902 0 +4650 0.0700095 0.229929 0 +4651 0.0700046 0.21995 0 +4652 0.0700086 0.209965 0 +4653 0.0700326 0.199975 0 +4654 0.0700551 0.189983 0 +4655 0.0700534 0.179988 0 +4656 0.0700475 0.169992 0 +4657 0.0700349 0.159995 0 +4658 0.0700215 0.149997 0 +4659 0.0700115 0.139998 0 +4660 0.0700057 0.129999 0 +4661 0.07000290000000001 0.12 0 +4662 0.0700017 0.11 0 +4663 0.0700013 0.100001 0 +4664 0.0700013 0.09000089999999999 0 +4665 0.07000140000000001 0.08000110000000001 0 +4666 0.472792 0.824139 0 +4667 0.474626 0.837375 0 +4668 0.485472 0.846181 0 +4669 0.494374 0.853192 0 +4670 0.5024690000000001 0.859733 0 +4671 0.509987 0.866323 0 +4672 0.524011 0.867195 0 +4673 0.516602 0.87365 0 +4674 0.531509 0.860603 0 +4675 0.539345 0.854367 0 +4676 0.547818 0.847595 0 +4677 0.557395 0.838571 0 +4678 0.569238 0.8349 0 +4679 0.579067 0.832028 0 +4680 0.588075 0.830766 0 +4681 0.598306 0.833193 0 +4682 0.608063 0.828664 0 +4683 0.6382 0.809713 0 +4684 0.631622 0.812985 0 +4685 0.646011 0.805487 0 +4686 0.654269 0.801088 0 +4687 0.662759 0.79688 0 +4688 0.671613 0.793326 0 +4689 0.680764 0.7907960000000001 0 +4690 0.689823 0.78857 0 +4691 0.698559 0.78618 0 +4692 0.7054319999999999 0.771696 0 +4693 0.70758 0.783301 0 +4694 0.708168 0.75951 0 +4695 0.707251 0.749547 0 +4696 0.716286 0.745838 0 +4697 0.724772 0.739181 0 +4698 0.732573 0.731871 0 +4699 0.740499 0.724384 0 +4700 0.750853 0.716214 0 +4701 0.7567700000000001 0.70436 0 +4702 0.762541 0.694529 0 +4703 0.766451 0.684205 0 +4704 0.769033 0.674725 0 +4705 0.778214 0.6748150000000001 0 +4706 0.787781 0.67399 0 +4707 0.797419 0.672466 0 +4708 0.807118 0.670775 0 +4709 0.8167720000000001 0.658821 0 +4710 0.816859 0.669084 0 +4711 0.8163589999999999 0.648607 0 +4712 0.815608 0.63854 0 +4713 0.814852 0.628664 0 +4714 0.814902 0.618951 0 +4715 0.816937 0.609616 0 +4716 0.820343 0.601253 0 +4717 0.825033 0.59351 0 +4718 0.830317 0.5863969999999999 0 +4719 0.835546 0.58034 0 +4720 0.842225 0.575997 0 +4721 0.844826 0.563708 0 +4722 0.849853 0.571241 0 +4723 0.839569 0.556925 0 +4724 0.834525 0.552539 0 +4725 0.835784 0.545779 0 +4726 0.835975 0.536835 0 +4727 0.8358449999999999 0.527577 0 +4728 0.835896 0.518138 0 +4729 0.8375899999999999 0.50843 0 +4730 0.841819 0.499877 0 +4731 0.847236 0.492664 0 +4732 0.84748 0.48021 0 +4733 0.853553 0.486141 0 +4734 0.840992 0.474233 0 +4735 0.8343390000000001 0.468608 0 +4736 0.827497 0.46369 0 +4737 0.8215479999999999 0.459466 0 +4738 0.81811 0.443565 0 +4739 0.817591 0.45108 0 +4740 0.818507 0.434677 0 +4741 0.81872 0.425209 0 +4742 0.819316 0.415362 0 +4743 0.820997 0.404843 0 +4744 0.80219 0.373111 0 +4745 0.80791 0.381963 0 +4746 0.796884 0.363422 0 +4747 0.815612 0.390017 0 +4748 0.825091 0.395331 0 +4749 0.444953 0.174308 0 +4750 0.434114 0.177166 0 +4751 0.424193 0.180027 0 +4752 0.41455 0.182907 0 +4753 0.405428 0.185723 0 +4754 0.398294 0.187751 0 +4755 0.391951 0.181374 0 +4756 0.380985 0.179791 0 +4757 0.369133 0.186113 0 +4758 0.372079 0.177619 0 +4759 0.364618 0.194253 0 +4760 0.357775 0.200688 0 +4761 0.349709 0.206419 0 +4762 0.340758 0.211383 0 +4763 0.331369 0.216003 0 +4764 0.321134 0.220751 0 +4765 0.308377 0.225519 0 +4766 0.299863 0.236345 0 +4767 0.291958 0.243874 0 +4768 0.283647 0.250001 0 +4769 0.274544 0.254832 0 +4770 0.265251 0.258711 0 +4771 0.255605 0.260992 0 +4772 0.247473 0.271015 0 +4773 0.246813 0.262431 0 +4774 0.247337 0.279938 0 +4775 0.24624 0.288403 0 +4776 0.244016 0.295707 0 +4777 0.239672 0.301769 0 +4778 0.234137 0.308078 0 +4779 0.77659 0.685383 0 +4780 0.787111 0.6844170000000001 0 +4781 0.797136 0.682988 0 +4782 0.807032 0.681261 0 +4783 0.816759 0.6794289999999999 0 +4784 0.826561 0.667353 0 +4785 0.826418 0.677575 0 +4786 0.82659 0.65716 0 +4787 0.826164 0.6471170000000001 0 +4788 0.8253200000000001 0.637375 0 +4789 0.824298 0.6281060000000001 0 +4790 0.823944 0.619292 0 +4791 0.824685 0.6115620000000001 0 +4792 0.828144 0.604788 0 +4793 0.832689 0.5979640000000001 0 +4794 0.837288 0.590933 0 +4795 0.839722 0.584919 0 +4796 0.846044 0.58335 0 +4797 0.853997 0.579274 0 +4798 0.85773 0.565962 0 +4799 0.8623960000000001 0.57431 0 +4800 0.852657 0.557542 0 +4801 0.846257 0.548089 0 +4802 0.845745 0.536505 0 +4803 0.84502 0.526994 0 +4804 0.8446360000000001 0.5185070000000001 0 +4805 0.845452 0.510601 0 +4806 0.848596 0.503471 0 +4807 0.853056 0.49729 0 +4808 0.858722 0.492241 0 +4809 0.860135 0.479999 0 +4810 0.86571 0.487026 0 +4811 0.853957 0.473405 0 +4812 0.847427 0.466351 0 +4813 0.83952 0.460761 0 +4814 0.831908 0.456314 0 +4815 0.824419 0.452924 0 +4816 0.826529 0.44494 0 +4817 0.827753 0.436196 0 +4818 0.828628 0.426861 0 +4819 0.829869 0.417374 0 +4820 0.831663 0.407789 0 +4821 0.83468 0.398865 0 +4822 0.82989 0.38722 0 +4823 0.8383930000000001 0.39086 0 +4824 0.821848 0.382469 0 +4825 0.815263 0.376044 0 +4826 0.810126 0.368108 0 +4827 0.806441 0.359246 0 +4828 0.80323 0.348958 0 +4829 0.802357 0.338148 0 +4830 0.802023 0.327782 0 +4831 0.801934 0.317761 0 +4832 0.791872 0.306547 0 +4833 0.802141 0.308061 0 +4834 0.781593 0.304889 0 +4835 0.7704220000000001 0.3032 0 +4836 0.509139 0.16834 0 +4837 0.514334 0.177673 0 +4838 0.500982 0.160737 0 +4839 0.492447 0.153914 0 +4840 0.484284 0.147447 0 +4841 0.469207 0.147082 0 +4842 0.476693 0.140384 0 +4843 0.461068 0.153379 0 +4844 0.451748 0.159486 0 +4845 0.441195 0.163546 0 +4846 0.431195 0.166921 0 +4847 0.421449 0.170167 0 +4848 0.411829 0.173346 0 +4849 0.402284 0.176833 0 +4850 0.6752280000000001 0.213422 0 +4851 0.672462 0.202586 0 +4852 0.669815 0.192734 0 +4853 0.667351 0.183095 0 +4854 0.656419 0.175176 0 +4855 0.665257 0.17361 0 +4856 0.647029 0.176098 0 +4857 0.637196 0.176584 0 +4858 0.626702 0.176379 0 +4859 0.616964 0.174124 0 +4860 0.834928 0.447869 0 +4861 0.837085 0.438644 0 +4862 0.838446 0.429091 0 +4863 0.839758 0.419471 0 +4864 0.84174 0.410131 0 +4865 0.843993 0.401477 0 +4866 0.846387 0.393858 0 +4867 0.84256 0.3836 0 +4868 0.850596 0.38726 0 +4869 0.834551 0.38008 0 +4870 0.82725 0.376123 0 +4871 0.821549 0.371293 0 +4872 0.8182160000000001 0.364607 0 +4873 0.815821 0.356615 0 +4874 0.814015 0.347563 0 +4875 0.812963 0.337886 0 +4876 0.812553 0.328222 0 +4877 0.812358 0.31866 0 +4878 0.812335 0.309295 0 +4879 0.802996 0.298631 0 +4880 0.812881 0.300274 0 +4881 0.793068 0.296813 0 +4882 0.7829 0.294792 0 +4883 0.772635 0.292456 0 +4884 0.761727 0.2893 0 +4885 0.751877 0.283892 0 +4886 0.743438 0.278523 0 +4887 0.736699 0.273341 0 +4888 0.731985 0.26637 0 +4889 0.728341 0.258119 0 +4890 0.703452 0.237193 0 +4891 0.710805 0.243734 0 +4892 0.696244 0.229481 0 +4893 0.689924 0.220362 0 +4894 0.685631 0.209707 0 +4895 0.682187 0.199761 0 +4896 0.679141 0.189985 0 +4897 0.67635 0.180468 0 +4898 0.673717 0.171195 0 +4899 0.66354 0.165052 0 +4900 0.670966 0.162362 0 +4901 0.655592 0.165708 0 +4902 0.646768 0.166126 0 +4903 0.637418 0.166552 0 +4904 0.62776 0.166152 0 +4905 0.618333 0.164968 0 +4906 0.6087 0.171888 0 +4907 0.609446 0.163705 0 +4908 0.607984 0.178427 0 +4909 0.601398 0.180328 0 +4910 0.591648 0.181783 0 +4911 0.580498 0.180643 0 +4912 0.569529 0.179077 0 +4913 0.558491 0.177327 0 +4914 0.5473980000000001 0.175717 0 +4915 0.53637 0.174757 0 +4916 0.524851 0.174709 0 +4917 0.719056 0.248404 0 +4918 0.727793 0.249404 0 +4919 0.408304 0.807108 0 +4920 0.401865 0.800845 0 +4921 0.417243 0.8138609999999999 0 +4922 0.427976 0.817979 0 +4923 0.438864 0.820841 0 +4924 0.449928 0.822895 0 +4925 0.46109 0.824125 0 +4926 0.521208 0.161758 0 +4927 0.509289 0.153168 0 +4928 0.499863 0.146442 0 +4929 0.491311 0.139946 0 +4930 0.483564 0.133322 0 +4931 0.469835 0.133056 0 +4932 0.476432 0.126264 0 +4933 0.46277 0.139374 0 +4934 0.45492 0.144956 0 +4935 0.446231 0.149704 0 +4936 0.436926 0.15351 0 +4937 0.427607 0.156975 0 +4938 0.418421 0.160362 0 +4939 0.409239 0.163447 0 +4940 0.400066 0.166314 0 +4941 0.390911 0.169001 0 +4942 0.381859 0.169888 0 +4943 0.373629 0.169363 0 +4944 0.364377 0.174871 0 +4945 0.366714 0.167982 0 +4946 0.361817 0.182379 0 +4947 0.358251 0.18886 0 +4948 0.352275 0.19355 0 +4949 0.344835 0.19806 0 +4950 0.336422 0.202234 0 +4951 0.327439 0.206312 0 +4952 0.318046 0.209735 0 +4953 0.307971 0.212043 0 +4954 0.285659 0.236571 0 +4955 0.292246 0.230015 0 +4956 0.278171 0.242037 0 +4957 0.269902 0.246324 0 +4958 0.261245 0.249643 0 +4959 0.252941 0.252395 0 +4960 0.245434 0.254517 0 +4961 0.238209 0.262679 0 +4962 0.237809 0.254511 0 +4963 0.238329 0.27113 0 +4964 0.237614 0.279525 0 +4965 0.237849 0.287481 0 +4966 0.23828 0.293442 0 +4967 0.233168 0.2969 0 +4968 0.226191 0.302246 0 +4969 0.202868 0.313036 0 +4970 0.216452 0.310126 0 +4971 0.191989 0.316376 0 +4972 0.181991 0.320172 0 +4973 0.172259 0.32449 0 +4974 0.162657 0.329052 0 +4975 0.155793 0.343302 0 +4976 0.15311 0.333586 0 +4977 0.158604 0.353247 0 +4978 0.161872 0.363359 0 +4979 0.166267 0.373378 0 +4980 0.170965 0.38338 0 +4981 0.174182 0.393951 0 +4982 0.176305 0.403249 0 +4983 0.177631 0.412052 0 +4984 0.178973 0.419795 0 +4985 0.180127 0.425433 0 +4986 0.175811 0.429391 0 +4987 0.170276 0.435096 0 +4988 0.163883 0.442009 0 +4989 0.157145 0.449415 0 +4990 0.150551 0.457071 0 +4991 0.151294 0.471641 0 +4992 0.143621 0.465414 0 +4993 0.158459 0.476347 0 +4994 0.163763 0.47965 0 +4995 0.163463 0.486058 0 +4996 0.16309 0.495016 0 +4997 0.163008 0.504983 0 +4998 0.163324 0.515337 0 +4999 0.164208 0.525665 0 +5000 0.165332 0.535714 0 +5001 0.166404 0.545313 0 +5002 0.166853 0.554193 0 +5003 0.166075 0.561867 0 +5004 0.162361 0.568379 0 +5005 0.157382 0.574977 0 +5006 0.158504 0.587222 0 +5007 0.151916 0.581468 0 +5008 0.16525 0.593074 0 +5009 0.171896 0.599436 0 +5010 0.17816 0.606331 0 +5011 0.183958 0.613773 0 +5012 0.189237 0.621806 0 +5013 0.193855 0.630296 0 +5014 0.198599 0.63968 0 +5015 0.296753 0.221338 0 +5016 0.298008 0.211364 0 +5017 0.640676 0.818642 0 +5018 0.630093 0.821837 0 +5019 0.649488 0.814511 0 +5020 0.65783 0.8101930000000001 0 +5021 0.666087 0.806033 0 +5022 0.674474 0.802503 0 +5023 0.683095 0.799839 0 +5024 0.691794 0.7974869999999999 0 +5025 0.700408 0.795093 0 +5026 0.709027 0.792869 0 +5027 0.717285 0.782347 0 +5028 0.717639 0.79172 0 +5029 0.7180569999999999 0.77135 0 +5030 0.72153 0.757606 0 +5031 0.919997 0.919997 0 +5032 0.9099969999999999 0.919998 0 +5033 0.899998 0.919999 0 +5034 0.889998 0.919999 0 +5035 0.8799979999999999 0.92 0 +5036 0.869999 0.92 0 +5037 0.859992 0.919968 0 +5038 0.849981 0.919901 0 +5039 0.83997 0.919802 0 +5040 0.8299609999999999 0.919705 0 +5041 0.819952 0.9196260000000001 0 +5042 0.809945 0.919569 0 +5043 0.799943 0.919543 0 +5044 0.789947 0.919574 0 +5045 0.779954 0.919627 0 +5046 0.769962 0.919638 0 +5047 0.75997 0.919655 0 +5048 0.749978 0.919685 0 +5049 0.739984 0.919722 0 +5050 0.729984 0.919721 0 +5051 0.719983 0.9197419999999999 0 +5052 0.709978 0.9197149999999999 0 +5053 0.69997 0.919693 0 +5054 0.68995 0.9196800000000001 0 +5055 0.679939 0.919671 0 +5056 0.669939 0.9196800000000001 0 +5057 0.659949 0.919743 0 +5058 0.649972 0.919785 0 +5059 0.640029 0.919654 0 +5060 0.630091 0.919336 0 +5061 0.620155 0.918996 0 +5062 0.610219 0.9188499999999999 0 +5063 0.600295 0.918784 0 +5064 0.590384 0.918658 0 +5065 0.5804820000000001 0.918451 0 +5066 0.570537 0.918193 0 +5067 0.56057 0.9179040000000001 0 +5068 0.550509 0.917544 0 +5069 0.540368 0.917104 0 +5070 0.530154 0.917177 0 +5071 0.520029 0.9177689999999999 0 +5072 0.510011 0.918767 0 +5073 0.500138 0.919469 0 +5074 0.490326 0.919642 0 +5075 0.48055 0.919367 0 +5076 0.470739 0.918802 0 +5077 0.460865 0.918173 0 +5078 0.450879 0.917691 0 +5079 0.440801 0.917438 0 +5080 0.430694 0.917311 0 +5081 0.420551 0.917285 0 +5082 0.410391 0.917309 0 +5083 0.400218 0.917399 0 +5084 0.390027 0.917488 0 +5085 0.379831 0.917594 0 +5086 0.369675 0.917733 0 +5087 0.359553 0.917885 0 +5088 0.349445 0.918028 0 +5089 0.339373 0.918153 0 +5090 0.329327 0.9182900000000001 0 +5091 0.31931 0.918426 0 +5092 0.30933 0.918632 0 +5093 0.299377 0.918913 0 +5094 0.289441 0.919205 0 +5095 0.279527 0.91947 0 +5096 0.269607 0.919637 0 +5097 0.25969 0.919767 0 +5098 0.249762 0.919864 0 +5099 0.239822 0.919916 0 +5100 0.229871 0.919955 0 +5101 0.219908 0.9199310000000001 0 +5102 0.209936 0.919918 0 +5103 0.199956 0.919896 0 +5104 0.189971 0.919887 0 +5105 0.179981 0.919906 0 +5106 0.169987 0.91993 0 +5107 0.159992 0.919954 0 +5108 0.149995 0.919974 0 +5109 0.139997 0.919986 0 +5110 0.129999 0.9199929999999999 0 +5111 0.12 0.919997 0 +5112 0.11 0.919998 0 +5113 0.100001 0.919999 0 +5114 0.0900014 0.919999 0 +5115 0.0800017 0.919999 0 +5116 0.155417 0.484539 0 +5117 0.153675 0.494499 0 +5118 0.153045 0.505193 0 +5119 0.153194 0.516086 0 +5120 0.154352 0.526748 0 +5121 0.155926 0.536905 0 +5122 0.157738 0.546449 0 +5123 0.159405 0.554411 0 +5124 0.160648 0.560018 0 +5125 0.156436 0.5638879999999999 0 +5126 0.150978 0.5692469999999999 0 +5127 0.145216 0.575767 0 +5128 0.14688 0.587986 0 +5129 0.140281 0.583291 0 +5130 0.15252 0.593519 0 +5131 0.158574 0.599783 0 +5132 0.164949 0.606027 0 +5133 0.171163 0.61246 0 +5134 0.176959 0.619241 0 +5135 0.182014 0.626543 0 +5136 0.185747 0.634535 0 +5137 0.18921 0.643732 0 +5138 0.19223 0.654129 0 +5139 0.193647 0.665766 0 +5140 0.194923 0.679287 0 +5141 0.202904 0.690182 0 +5142 0.209245 0.699139 0 +5143 0.215425 0.707587 0 +5144 0.221678 0.715803 0 +5145 0.228002 0.723741 0 +5146 0.23485 0.730807 0 +5147 0.241613 0.737216 0 +5148 0.247353 0.7431720000000001 0 +5149 0.251344 0.749109 0 +5150 0.25256 0.756054 0 +5151 0.252876 0.763687 0 +5152 0.261328 0.770685 0 +5153 0.252963 0.7718390000000001 0 +5154 0.269115 0.7698120000000001 0 +5155 0.27624 0.76992 0 +5156 0.282713 0.772813 0 +5157 0.289567 0.776658 0 +5158 0.296819 0.780815 0 +5159 0.303946 0.785405 0 +5160 0.310521 0.790932 0 +5161 0.316376 0.797589 0 +5162 0.321801 0.804566 0 +5163 0.326697 0.812006 0 +5164 0.331255 0.819202 0 +5165 0.335434 0.825983 0 +5166 0.345838 0.830183 0 +5167 0.338553 0.832492 0 +5168 0.354142 0.827885 0 +5169 0.363072 0.825707 0 +5170 0.372456 0.823636 0 +5171 0.382108 0.821363 0 +5172 0.391562 0.818277 0 +5173 0.919998 0.0800018 0 +5174 0.919998 0.0900015 0 +5175 0.919999 0.100001 0 +5176 0.919999 0.110001 0 +5177 0.92 0.120001 0 +5178 0.92 0.130001 0 +5179 0.92 0.140001 0 +5180 0.92 0.15 0 +5181 0.92 0.16 0 +5182 0.92 0.17 0 +5183 0.92 0.18 0 +5184 0.92 0.19 0 +5185 0.92 0.200001 0 +5186 0.919999 0.210002 0 +5187 0.919973 0.220003 0 +5188 0.919917 0.230013 0 +5189 0.919857 0.24002 0 +5190 0.919799 0.250005 0 +5191 0.919816 0.259969 0 +5192 0.9199040000000001 0.269906 0 +5193 0.920064 0.279797 0 +5194 0.920172 0.289657 0 +5195 0.920078 0.299512 0 +5196 0.919778 0.309365 0 +5197 0.919276 0.319235 0 +5198 0.918802 0.329173 0 +5199 0.918355 0.339168 0 +5200 0.917979 0.349246 0 +5201 0.917628 0.359377 0 +5202 0.917465 0.369553 0 +5203 0.917671 0.379739 0 +5204 0.918316 0.389828 0 +5205 0.918984 0.399848 0 +5206 0.919345 0.409832 0 +5207 0.919393 0.419806 0 +5208 0.919204 0.42988 0 +5209 0.918894 0.440026 0 +5210 0.918563 0.450289 0 +5211 0.918269 0.46063 0 +5212 0.918214 0.471063 0 +5213 0.918563 0.481466 0 +5214 0.919109 0.491783 0 +5215 0.9197 0.501987 0 +5216 0.920269 0.512059 0 +5217 0.920772 0.522002 0 +5218 0.921105 0.531842 0 +5219 0.9211819999999999 0.541605 0 +5220 0.920951 0.551387 0 +5221 0.9204369999999999 0.5611699999999999 0 +5222 0.9199349999999999 0.5710190000000001 0 +5223 0.919799 0.580964 0 +5224 0.919861 0.590906 0 +5225 0.91992 0.600846 0 +5226 0.91988 0.610768 0 +5227 0.91979 0.620702 0 +5228 0.919757 0.630625 0 +5229 0.919847 0.640582 0 +5230 0.920028 0.650524 0 +5231 0.920202 0.660466 0 +5232 0.920332 0.670397 0 +5233 0.920398 0.680343 0 +5234 0.920428 0.690304 0 +5235 0.920409 0.700257 0 +5236 0.920365 0.71021 0 +5237 0.920296 0.720174 0 +5238 0.920221 0.730142 0 +5239 0.920133 0.740112 0 +5240 0.920051 0.750085 0 +5241 0.920033 0.760063 0 +5242 0.92001 0.770045 0 +5243 0.920006 0.780031 0 +5244 0.919998 0.790021 0 +5245 0.919994 0.800014 0 +5246 0.919936 0.810003 0 +5247 0.919895 0.8199959999999999 0 +5248 0.919868 0.829991 0 +5249 0.919852 0.839986 0 +5250 0.919885 0.849985 0 +5251 0.919909 0.859985 0 +5252 0.91994 0.869987 0 +5253 0.919966 0.879989 0 +5254 0.919983 0.889991 0 +5255 0.919992 0.899994 0 +5256 0.919996 0.909996 0 +5257 0.0800013 0.08000069999999999 0 +5258 0.0900011 0.0800004 0 +5259 0.100001 0.08000019999999999 0 +5260 0.110001 0.0800001 0 +5261 0.120001 0.08 0 +5262 0.13 0.08 0 +5263 0.14 0.0799999 0 +5264 0.15 0.0799999 0 +5265 0.16 0.0799999 0 +5266 0.17 0.0799999 0 +5267 0.18 0.0799999 0 +5268 0.19 0.0799999 0 +5269 0.2 0.08 0 +5270 0.210016 0.0800925 0 +5271 0.220042 0.0802495 0 +5272 0.230076 0.0804865 0 +5273 0.240127 0.080748 0 +5274 0.250178 0.0809685 0 +5275 0.260249 0.0811924 0 +5276 0.270303 0.08133890000000001 0 +5277 0.280357 0.081444 0 +5278 0.290409 0.0815135 0 +5279 0.300471 0.08146299999999999 0 +5280 0.310518 0.0813521 0 +5281 0.32056 0.08125400000000001 0 +5282 0.330584 0.0811977 0 +5283 0.340602 0.0812219 0 +5284 0.350598 0.0812722 0 +5285 0.360618 0.08138090000000001 0 +5286 0.370633 0.0815105 0 +5287 0.380674 0.0816477 0 +5288 0.390721 0.08172740000000001 0 +5289 0.400809 0.0817864 0 +5290 0.410897 0.08176659999999999 0 +5291 0.421006 0.0816524 0 +5292 0.431143 0.08150399999999999 0 +5293 0.441289 0.0813879 0 +5294 0.451352 0.0810801 0 +5295 0.461279 0.0802802 0 +5296 0.471019 0.0796805 0 +5297 0.480693 0.0796509 0 +5298 0.490395 0.0799444 0 +5299 0.50017 0.080274 0 +5300 0.5100440000000001 0.0807638 0 +5301 0.520002 0.0813808 0 +5302 0.530092 0.08204359999999999 0 +5303 0.540228 0.0824757 0 +5304 0.55037 0.0824952 0 +5305 0.560536 0.0823275 0 +5306 0.5706329999999999 0.0820449 0 +5307 0.58069 0.0817504 0 +5308 0.590715 0.0815649 0 +5309 0.6007169999999999 0.08148030000000001 0 +5310 0.61072 0.08137610000000001 0 +5311 0.620713 0.081344 0 +5312 0.630688 0.08131670000000001 0 +5313 0.640662 0.0811636 0 +5314 0.650581 0.080868 0 +5315 0.660478 0.0804647 0 +5316 0.670342 0.080057 0 +5317 0.680213 0.079734 0 +5318 0.690087 0.07957359999999999 0 +5319 0.6999649999999999 0.07959819999999999 0 +5320 0.709893 0.0796061 0 +5321 0.719844 0.0796084 0 +5322 0.7298289999999999 0.0796187 0 +5323 0.739822 0.0796804 0 +5324 0.749833 0.079744 0 +5325 0.759849 0.0798222 0 +5326 0.769869 0.0798777 0 +5327 0.77989 0.0799173 0 +5328 0.78991 0.07994900000000001 0 +5329 0.799928 0.07997170000000001 0 +5330 0.809944 0.0799855 0 +5331 0.819957 0.07999299999999999 0 +5332 0.829968 0.0799967 0 +5333 0.8399759999999999 0.0799984 0 +5334 0.849983 0.0799993 0 +5335 0.8599869999999999 0.07999970000000001 0 +5336 0.86999 0.0800001 0 +5337 0.879993 0.0800005 0 +5338 0.889994 0.0800008 0 +5339 0.899996 0.08000119999999999 0 +5340 0.9099969999999999 0.0800015 0 +5341 0.08000110000000001 0.909999 0 +5342 0.08000069999999999 0.899999 0 +5343 0.0800004 0.889999 0 +5344 0.08000019999999999 0.879999 0 +5345 0.0800001 0.87 0 +5346 0.08 0.86 0 +5347 0.0799999 0.85 0 +5348 0.0799999 0.84 0 +5349 0.0799999 0.83 0 +5350 0.0799999 0.82 0 +5351 0.0799999 0.8100000000000001 0 +5352 0.0800112 0.8 0 +5353 0.0800351 0.78999 0 +5354 0.08012370000000001 0.779968 0 +5355 0.0802471 0.769934 0 +5356 0.0804357 0.7599 0 +5357 0.0806307 0.7498590000000001 0 +5358 0.08086699999999999 0.73982 0 +5359 0.0810464 0.729783 0 +5360 0.0811085 0.71974 0 +5361 0.08107 0.709715 0 +5362 0.0809547 0.699676 0 +5363 0.0807964 0.689663 0 +5364 0.08062510000000001 0.6796180000000001 0 +5365 0.08045090000000001 0.6696029999999999 0 +5366 0.080286 0.659569 0 +5367 0.08010440000000001 0.649559 0 +5368 0.0799101 0.639578 0 +5369 0.0796473 0.629634 0 +5370 0.0793522 0.619716 0 +5371 0.079205 0.609827 0 +5372 0.0793475 0.599935 0 +5373 0.07967829999999999 0.589985 0 +5374 0.08003689999999999 0.579976 0 +5375 0.0802614 0.569882 0 +5376 0.0802148 0.559746 0 +5377 0.08003200000000001 0.549637 0 +5378 0.0798214 0.539578 0 +5379 0.07977579999999999 0.52957 0 +5380 0.079939 0.519572 0 +5381 0.0802412 0.509555 0 +5382 0.08054119999999999 0.499472 0 +5383 0.0807011 0.489367 0 +5384 0.08062809999999999 0.479295 0 +5385 0.0803857 0.469234 0 +5386 0.0801864 0.45919 0 +5387 0.080181 0.449156 0 +5388 0.08043980000000001 0.439151 0 +5389 0.080981 0.429096 0 +5390 0.0815931 0.419042 0 +5391 0.0821253 0.408966 0 +5392 0.0826346 0.39885 0 +5393 0.0830144 0.388735 0 +5394 0.0831186 0.378669 0 +5395 0.0830031 0.368605 0 +5396 0.08266950000000001 0.358557 0 +5397 0.0822348 0.3486 0 +5398 0.0817558 0.338674 0 +5399 0.0812349 0.328774 0 +5400 0.0807947 0.318902 0 +5401 0.0804747 0.309063 0 +5402 0.0803218 0.299219 0 +5403 0.0802461 0.289374 0 +5404 0.0801876 0.279505 0 +5405 0.08013149999999999 0.269619 0 +5406 0.0800833 0.259712 0 +5407 0.08004 0.249785 0 +5408 0.0800167 0.239842 0 +5409 0.0800063 0.229885 0 +5410 0.08002380000000001 0.219916 0 +5411 0.0800693 0.20994 0 +5412 0.0801135 0.199957 0 +5413 0.0801323 0.18997 0 +5414 0.0801371 0.179979 0 +5415 0.08011459999999999 0.169986 0 +5416 0.0800887 0.159991 0 +5417 0.08005859999999999 0.149994 0 +5418 0.0800338 0.139997 0 +5419 0.0800177 0.129998 0 +5420 0.0800088 0.119999 0 +5421 0.0800043 0.11 0 +5422 0.0800023 0.1 0 +5423 0.0800015 0.0900005 0 +5424 0.844061 0.451719 0 +5425 0.846558 0.441499 0 +5426 0.848308 0.431438 0 +5427 0.849873 0.421441 0 +5428 0.851554 0.41188 0 +5429 0.85285 0.402953 0 +5430 0.852464 0.396213 0 +5431 0.857807 0.392001 0 +5432 0.855008 0.379876 0 +5433 0.863598 0.384685 0 +5434 0.8464660000000001 0.376161 0 +5435 0.838287 0.373001 0 +5436 0.831148 0.370189 0 +5437 0.826084 0.368049 0 +5438 0.825462 0.3627 0 +5439 0.824676 0.355327 0 +5440 0.823827 0.34682 0 +5441 0.823315 0.337837 0 +5442 0.822997 0.328575 0 +5443 0.822744 0.319244 0 +5444 0.8224630000000001 0.310092 0 +5445 0.822151 0.301412 0 +5446 0.814003 0.291632 0 +5447 0.822464 0.293579 0 +5448 0.804794 0.289558 0 +5449 0.795087 0.287372 0 +5450 0.785321 0.285097 0 +5451 0.775496 0.282476 0 +5452 0.765786 0.279107 0 +5453 0.756475 0.27489 0 +5454 0.748059 0.271039 0 +5455 0.7415119999999999 0.269125 0 +5456 0.739778 0.262995 0 +5457 0.736815 0.255873 0 +5458 0.735121 0.248972 0 +5459 0.728799 0.241985 0 +5460 0.735798 0.242267 0 +5461 0.721957 0.240785 0 +5462 0.716114 0.236507 0 +5463 0.710323 0.230365 0 +5464 0.7046289999999999 0.222967 0 +5465 0.699503 0.214563 0 +5466 0.695198 0.205382 0 +5467 0.691503 0.196009 0 +5468 0.688198 0.186669 0 +5469 0.6851660000000001 0.177358 0 +5470 0.682189 0.168144 0 +5471 0.679007 0.159093 0 +5472 0.66745 0.154331 0 +5473 0.675391 0.150353 0 +5474 0.662258 0.158619 0 +5475 0.65579 0.156838 0 +5476 0.647023 0.156385 0 +5477 0.637784 0.156537 0 +5478 0.628454 0.156602 0 +5479 0.619167 0.155906 0 +5480 0.610062 0.15479 0 +5481 0.600261 0.16265 0 +5482 0.600876 0.153461 0 +5483 0.600268 0.171783 0 +5484 0.731562 0.747433 0 +5485 0.739142 0.739309 0 +5486 0.746066 0.732263 0 +5487 0.753633 0.727151 0 +5488 0.774039 0.698249 0 +5489 0.766004 0.707425 0 +5490 0.5907019999999999 0.171437 0 +5491 0.5804 0.170219 0 +5492 0.5697179999999999 0.168554 0 +5493 0.558792 0.166822 0 +5494 0.54781 0.165179 0 +5495 0.535998 0.16357 0 +5496 0.146214 0.481402 0 +5497 0.143839 0.49305 0 +5498 0.14276 0.504891 0 +5499 0.142546 0.51718 0 +5500 0.144562 0.529179 0 +5501 0.146849 0.539694 0 +5502 0.149259 0.549113 0 +5503 0.15261 0.557443 0 +5504 0.145593 0.562307 0 +5505 0.138956 0.568879 0 +5506 0.132667 0.5773 0 +5507 0.136614 0.591521 0 +5508 0.128677 0.587407 0 +5509 0.14316 0.592936 0 +5510 0.146145 0.599027 0 +5511 0.151832 0.605839 0 +5512 0.158157 0.612331 0 +5513 0.16453 0.618499 0 +5514 0.170523 0.624491 0 +5515 0.17527 0.630358 0 +5516 0.177805 0.637661 0 +5517 0.179719 0.645985 0 +5518 0.181614 0.655649 0 +5519 0.182416 0.665771 0 +5520 0.182412 0.676171 0 +5521 0.200843 0.7054820000000001 0 +5522 0.194797 0.69725 0 +5523 0.206855 0.713847 0 +5524 0.213029 0.72226 0 +5525 0.219422 0.730379 0 +5526 0.22647 0.7381 0 +5527 0.234619 0.743632 0 +5528 0.241467 0.748158 0 +5529 0.246046 0.7513069999999999 0 +5530 0.245347 0.756753 0 +5531 0.244545 0.764178 0 +5532 0.244298 0.772427 0 +5533 0.253497 0.780312 0 +5534 0.244612 0.781172 0 +5535 0.261951 0.778759 0 +5536 0.269341 0.776996 0 +5537 0.274726 0.775436 0 +5538 0.278605 0.77924 0 +5539 0.284277 0.783941 0 +5540 0.291336 0.7879119999999999 0 +5541 0.29801 0.792234 0 +5542 0.303918 0.797584 0 +5543 0.309411 0.803671 0 +5544 0.314455 0.810721 0 +5545 0.319316 0.817962 0 +5546 0.324386 0.82467 0 +5547 0.32923 0.830325 0 +5548 0.333054 0.834274 0 +5549 0.339198 0.83977 0 +5550 0.331791 0.839683 0 +5551 0.347432 0.838601 0 +5552 0.356294 0.83701 0 +5553 0.365662 0.835295 0 +5554 0.375509 0.833501 0 +5555 0.385551 0.831503 0 +5556 0.396626 0.829031 0 +5557 0.424514 0.828939 0 +5558 0.410011 0.825063 0 +5559 0.436551 0.831354 0 +5560 0.448035 0.833353 0 +5561 0.45993 0.83527 0 +5562 0.188047 0.689788 0 +5563 0.180236 0.685221 0 +5564 0.909995 0.909996 0 +5565 0.899996 0.909996 0 +5566 0.889996 0.909995 0 +5567 0.879996 0.9099969999999999 0 +5568 0.86998 0.909958 0 +5569 0.8599599999999999 0.909875 0 +5570 0.8499370000000001 0.909752 0 +5571 0.839914 0.909606 0 +5572 0.829893 0.909469 0 +5573 0.819877 0.909358 0 +5574 0.809869 0.909277 0 +5575 0.799874 0.909267 0 +5576 0.789888 0.909321 0 +5577 0.779901 0.909354 0 +5578 0.769921 0.909395 0 +5579 0.7599399999999999 0.909415 0 +5580 0.749953 0.909419 0 +5581 0.739955 0.909421 0 +5582 0.729955 0.909455 0 +5583 0.7199449999999999 0.909485 0 +5584 0.709938 0.909503 0 +5585 0.69989 0.9094950000000001 0 +5586 0.6898609999999999 0.9094989999999999 0 +5587 0.679854 0.909491 0 +5588 0.669866 0.909523 0 +5589 0.659905 0.90968 0 +5590 0.649989 0.909771 0 +5591 0.640095 0.909544 0 +5592 0.6302140000000001 0.908987 0 +5593 0.620295 0.908469 0 +5594 0.61037 0.908338 0 +5595 0.600461 0.908358 0 +5596 0.590571 0.908276 0 +5597 0.580661 0.908036 0 +5598 0.570776 0.90772 0 +5599 0.560819 0.907481 0 +5600 0.55077 0.907112 0 +5601 0.540644 0.906545 0 +5602 0.530033 0.906011 0 +5603 0.519473 0.907426 0 +5604 0.509693 0.908963 0 +5605 0.5000019999999999 0.909956 0 +5606 0.490463 0.910098 0 +5607 0.480919 0.909535 0 +5608 0.471286 0.908612 0 +5609 0.461484 0.907647 0 +5610 0.45147 0.906938 0 +5611 0.441337 0.9066380000000001 0 +5612 0.43112 0.906537 0 +5613 0.420871 0.906485 0 +5614 0.410611 0.906536 0 +5615 0.400332 0.90663 0 +5616 0.390036 0.906763 0 +5617 0.379793 0.90695 0 +5618 0.369581 0.907184 0 +5619 0.359401 0.907393 0 +5620 0.349251 0.907573 0 +5621 0.33914 0.907722 0 +5622 0.329068 0.907837 0 +5623 0.319039 0.907967 0 +5624 0.309042 0.908234 0 +5625 0.299096 0.908635 0 +5626 0.289195 0.909043 0 +5627 0.279313 0.909361 0 +5628 0.269441 0.909564 0 +5629 0.259559 0.909728 0 +5630 0.249664 0.909808 0 +5631 0.239757 0.909882 0 +5632 0.229829 0.909875 0 +5633 0.219882 0.909846 0 +5634 0.20992 0.909815 0 +5635 0.199947 0.909789 0 +5636 0.189965 0.909805 0 +5637 0.179978 0.909834 0 +5638 0.169986 0.90988 0 +5639 0.159991 0.909922 0 +5640 0.149995 0.909953 0 +5641 0.139997 0.9099739999999999 0 +5642 0.129998 0.909986 0 +5643 0.119999 0.9099930000000001 0 +5644 0.11 0.9099969999999999 0 +5645 0.1 0.909998 0 +5646 0.09000089999999999 0.909999 0 +5647 0.9099969999999999 0.09000130000000001 0 +5648 0.909998 0.100001 0 +5649 0.909998 0.110001 0 +5650 0.909999 0.120001 0 +5651 0.909999 0.130001 0 +5652 0.909999 0.140001 0 +5653 0.91 0.150001 0 +5654 0.91 0.160001 0 +5655 0.91 0.170001 0 +5656 0.91 0.180001 0 +5657 0.91 0.190002 0 +5658 0.909992 0.200005 0 +5659 0.909941 0.210009 0 +5660 0.909874 0.220026 0 +5661 0.909767 0.23004 0 +5662 0.909668 0.240063 0 +5663 0.909608 0.250065 0 +5664 0.909614 0.260043 0 +5665 0.909797 0.269942 0 +5666 0.910143 0.279754 0 +5667 0.910389 0.289518 0 +5668 0.910332 0.299247 0 +5669 0.9098579999999999 0.308967 0 +5670 0.909123 0.318727 0 +5671 0.908435 0.328599 0 +5672 0.907852 0.338619 0 +5673 0.907303 0.348757 0 +5674 0.906811 0.359023 0 +5675 0.906465 0.369413 0 +5676 0.90685 0.379818 0 +5677 0.9078079999999999 0.389946 0 +5678 0.908895 0.399907 0 +5679 0.909375 0.409781 0 +5680 0.909397 0.419713 0 +5681 0.909102 0.429746 0 +5682 0.908672 0.439946 0 +5683 0.908162 0.450355 0 +5684 0.907689 0.460968 0 +5685 0.907545 0.471687 0 +5686 0.908162 0.482362 0 +5687 0.909018 0.492882 0 +5688 0.909843 0.503179 0 +5689 0.910618 0.513263 0 +5690 0.911299 0.523136 0 +5691 0.911803 0.532828 0 +5692 0.91198 0.542444 0 +5693 0.911627 0.552022 0 +5694 0.910748 0.561653 0 +5695 0.910009 0.571492 0 +5696 0.909714 0.581485 0 +5697 0.909928 0.591448 0 +5698 0.910044 0.601365 0 +5699 0.909932 0.611279 0 +5700 0.909725 0.621157 0 +5701 0.909676 0.6311 0 +5702 0.9098579999999999 0.641033 0 +5703 0.910139 0.650923 0 +5704 0.910428 0.660818 0 +5705 0.9106030000000001 0.670725 0 +5706 0.910685 0.680639 0 +5707 0.91072 0.690547 0 +5708 0.910678 0.70046 0 +5709 0.9106109999999999 0.710387 0 +5710 0.910509 0.720317 0 +5711 0.910373 0.730254 0 +5712 0.910222 0.740195 0 +5713 0.910161 0.750145 0 +5714 0.910121 0.760104 0 +5715 0.910101 0.7700709999999999 0 +5716 0.910064 0.780046 0 +5717 0.910026 0.790029 0 +5718 0.90992 0.8 0 +5719 0.909836 0.809982 0 +5720 0.909754 0.819967 0 +5721 0.909717 0.829951 0 +5722 0.909737 0.83995 0 +5723 0.909765 0.849948 0 +5724 0.9098309999999999 0.859954 0 +5725 0.9098810000000001 0.869962 0 +5726 0.909932 0.879972 0 +5727 0.909967 0.889981 0 +5728 0.909986 0.89999 0 +5729 0.0900014 0.0900002 0 +5730 0.100001 0.0900001 0 +5731 0.110001 0.0900001 0 +5732 0.120001 0.0900001 0 +5733 0.130001 0.0900002 0 +5734 0.140001 0.0900001 0 +5735 0.150001 0.0900001 0 +5736 0.160001 0.09 0 +5737 0.170001 0.08999989999999999 0 +5738 0.18 0.0899997 0 +5739 0.19 0.0899996 0 +5740 0.200011 0.0900632 0 +5741 0.210031 0.0902042 0 +5742 0.220068 0.0904683 0 +5743 0.230122 0.0907828 0 +5744 0.240192 0.0911377 0 +5745 0.250298 0.0914761 0 +5746 0.260403 0.0917446 0 +5747 0.27051 0.0919224 0 +5748 0.280624 0.0920646 0 +5749 0.290737 0.09210119999999999 0 +5750 0.300825 0.092003 0 +5751 0.310893 0.091805 0 +5752 0.32093 0.091636 0 +5753 0.330948 0.09154279999999999 0 +5754 0.340929 0.09154229999999999 0 +5755 0.350933 0.0916541 0 +5756 0.360933 0.0917811 0 +5757 0.370959 0.0919784 0 +5758 0.381014 0.0921973 0 +5759 0.39112 0.0923485 0 +5760 0.401254 0.0924418 0 +5761 0.411399 0.09244090000000001 0 +5762 0.421567 0.09221360000000001 0 +5763 0.431784 0.09197370000000001 0 +5764 0.442048 0.0918639 0 +5765 0.452423 0.0915724 0 +5766 0.462571 0.09015430000000001 0 +5767 0.471958 0.0891102 0 +5768 0.48107 0.08913840000000001 0 +5769 0.490504 0.0897355 0 +5770 0.500176 0.09005299999999999 0 +5771 0.509929 0.09064460000000001 0 +5772 0.519867 0.0915784 0 +5773 0.52995 0.0925986 0 +5774 0.540184 0.0932587 0 +5775 0.550528 0.0932254 0 +5776 0.560794 0.09295200000000001 0 +5777 0.570955 0.0925397 0 +5778 0.5809800000000001 0.0920419 0 +5779 0.590968 0.0918914 0 +5780 0.6009949999999999 0.0918525 0 +5781 0.6110370000000001 0.0916874 0 +5782 0.621094 0.0917115 0 +5783 0.6311369999999999 0.09177589999999999 0 +5784 0.641107 0.0916006 0 +5785 0.651057 0.0911758 0 +5786 0.660913 0.0905927 0 +5787 0.670726 0.0899663 0 +5788 0.680485 0.08946320000000001 0 +5789 0.690214 0.08928220000000001 0 +5790 0.699976 0.0894129 0 +5791 0.70983 0.08947049999999999 0 +5792 0.719756 0.0894562 0 +5793 0.729722 0.08945930000000001 0 +5794 0.739726 0.089503 0 +5795 0.749731 0.089617 0 +5796 0.759751 0.08971510000000001 0 +5797 0.769778 0.0897922 0 +5798 0.779809 0.0898593 0 +5799 0.78984 0.0899068 0 +5800 0.799871 0.08994249999999999 0 +5801 0.809898 0.08996750000000001 0 +5802 0.819921 0.0899831 0 +5803 0.82994 0.0899918 0 +5804 0.839955 0.0899963 0 +5805 0.849967 0.0899985 0 +5806 0.859976 0.0899995 0 +5807 0.869982 0.0900001 0 +5808 0.879988 0.0900005 0 +5809 0.889991 0.09000080000000001 0 +5810 0.899995 0.0900011 0 +5811 0.0900005 0.899999 0 +5812 0.09000039999999999 0.889999 0 +5813 0.0900002 0.879999 0 +5814 0.0900002 0.869999 0 +5815 0.0900001 0.86 0 +5816 0.09 0.85 0 +5817 0.08999989999999999 0.84 0 +5818 0.0899998 0.83 0 +5819 0.0899997 0.82 0 +5820 0.09003609999999999 0.810001 0 +5821 0.090072 0.799993 0 +5822 0.0901628 0.789973 0 +5823 0.0902958 0.779931 0 +5824 0.09051289999999999 0.769884 0 +5825 0.09075569999999999 0.759825 0 +5826 0.0910704 0.749758 0 +5827 0.0913959 0.739689 0 +5828 0.0915861 0.729618 0 +5829 0.09163590000000001 0.719534 0 +5830 0.09154039999999999 0.709477 0 +5831 0.0913487 0.699424 0 +5832 0.0911139 0.689375 0 +5833 0.0908621 0.679322 0 +5834 0.0906404 0.669268 0 +5835 0.09040810000000001 0.659231 0 +5836 0.0901938 0.649193 0 +5837 0.0899467 0.639184 0 +5838 0.0895957 0.629232 0 +5839 0.0890426 0.619393 0 +5840 0.0886943 0.609629 0 +5841 0.08884359999999999 0.599866 0 +5842 0.08934259999999999 0.590002 0 +5843 0.08989519999999999 0.579943 0 +5844 0.0902205 0.569746 0 +5845 0.09008289999999999 0.559503 0 +5846 0.0897221 0.5493400000000001 0 +5847 0.08937580000000001 0.539347 0 +5848 0.0892202 0.529451 0 +5849 0.0895673 0.519583 0 +5850 0.0901333 0.509591 0 +5851 0.0906189 0.499506 0 +5852 0.0908583 0.489374 0 +5853 0.0907444 0.479215 0 +5854 0.0903851 0.469118 0 +5855 0.0900523 0.459043 0 +5856 0.0900242 0.449022 0 +5857 0.0904363 0.43896 0 +5858 0.09126099999999999 0.428888 0 +5859 0.0921057 0.418744 0 +5860 0.0927586 0.408573 0 +5861 0.0933905 0.398349 0 +5862 0.0938546 0.388142 0 +5863 0.09397659999999999 0.377957 0 +5864 0.09374010000000001 0.367813 0 +5865 0.0932684 0.357773 0 +5866 0.0926681 0.347807 0 +5867 0.09195979999999999 0.337913 0 +5868 0.09128269999999999 0.32809 0 +5869 0.090722 0.318322 0 +5870 0.0903957 0.308584 0 +5871 0.0902826 0.298843 0 +5872 0.09027549999999999 0.289078 0 +5873 0.0902592 0.279282 0 +5874 0.0902005 0.269448 0 +5875 0.0901023 0.259579 0 +5876 0.09003940000000001 0.249682 0 +5877 0.0900021 0.239762 0 +5878 0.0900249 0.229821 0 +5879 0.09008960000000001 0.219867 0 +5880 0.0901684 0.209902 0 +5881 0.090227 0.19993 0 +5882 0.0902427 0.189951 0 +5883 0.0902425 0.179967 0 +5884 0.090214 0.169978 0 +5885 0.0901589 0.159986 0 +5886 0.09010799999999999 0.149992 0 +5887 0.0900667 0.139995 0 +5888 0.0900376 0.129997 0 +5889 0.0900194 0.119998 0 +5890 0.0900089 0.109999 0 +5891 0.0900036 0.0999999 0 +5892 0.590751 0.16149 0 +5893 0.58074 0.159902 0 +5894 0.570407 0.158092 0 +5895 0.559756 0.156348 0 +5896 0.548933 0.154571 0 +5897 0.537978 0.152359 0 +5898 0.526474 0.149213 0 +5899 0.515683 0.143758 0 +5900 0.506138 0.138129 0 +5901 0.497619 0.13253 0 +5902 0.489908 0.126107 0 +5903 0.482906 0.119144 0 +5904 0.469454 0.119464 0 +5905 0.475313 0.113045 0 +5906 0.463403 0.125898 0 +5907 0.456895 0.131631 0 +5908 0.449524 0.136325 0 +5909 0.441323 0.140441 0 +5910 0.43258 0.143804 0 +5911 0.423803 0.147279 0 +5912 0.415255 0.150748 0 +5913 0.406546 0.153562 0 +5914 0.397721 0.156145 0 +5915 0.389098 0.158609 0 +5916 0.381099 0.160773 0 +5917 0.373822 0.162056 0 +5918 0.368576 0.162854 0 +5919 0.360681 0.164164 0 +5920 0.365151 0.158541 0 +5921 0.356966 0.171465 0 +5922 0.35506 0.179217 0 +5923 0.353917 0.184883 0 +5924 0.34844 0.186684 0 +5925 0.341039 0.189482 0 +5926 0.332847 0.192868 0 +5927 0.324206 0.196353 0 +5928 0.315336 0.199254 0 +5929 0.306458 0.201532 0 +5930 0.297796 0.202102 0 +5931 0.289475 0.210179 0 +5932 0.289497 0.201488 0 +5933 0.288341 0.21831 0 +5934 0.285605 0.225252 0 +5935 0.280219 0.230283 0 +5936 0.273097 0.234513 0 +5937 0.265126 0.237957 0 +5938 0.257039 0.241166 0 +5939 0.249398 0.244626 0 +5940 0.244267 0.248444 0 +5941 0.238089 0.246436 0 +5942 0.229496 0.254359 0 +5943 0.229523 0.245718 0 +5944 0.229914 0.262637 0 +5945 0.229616 0.270594 0 +5946 0.225961 0.279583 0 +5947 0.229291 0.289545 0 +5948 0.22021 0.294033 0 +5949 0.210146 0.299134 0 +5950 0.199065 0.302974 0 +5951 0.188654 0.30657 0 +5952 0.178614 0.310568 0 +5953 0.168855 0.314891 0 +5954 0.159417 0.319481 0 +5955 0.150256 0.324152 0 +5956 0.143425 0.337647 0 +5957 0.141083 0.328321 0 +5958 0.145749 0.347423 0 +5959 0.148179 0.357588 0 +5960 0.151164 0.367932 0 +5961 0.154833 0.378588 0 +5962 0.160038 0.388705 0 +5963 0.16448 0.39778 0 +5964 0.167809 0.406116 0 +5965 0.169167 0.414535 0 +5966 0.171972 0.422775 0 +5967 0.164548 0.427523 0 +5968 0.157404 0.434394 0 +5969 0.150495 0.441808 0 +5970 0.144122 0.449608 0 +5971 0.137433 0.457049 0 +5972 0.134897 0.475906 0 +5973 0.129599 0.46371 0 +5974 0.141357 0.5537609999999999 0 +5975 0.133145 0.560009 0 +5976 0.119754 0.582908 0 +5977 0.123265 0.568846 0 +5978 0.126125 0.597573 0 +5979 0.117327 0.593508 0 +5980 0.13648 0.602882 0 +5981 0.144563 0.612224 0 +5982 0.151884 0.619164 0 +5983 0.158885 0.625115 0 +5984 0.165299 0.629854 0 +5985 0.170196 0.633042 0 +5986 0.170149 0.638774 0 +5987 0.17049 0.6467039999999999 0 +5988 0.171325 0.655986 0 +5989 0.172114 0.665611 0 +5990 0.172066 0.675382 0 +5991 0.171607 0.68455 0 +5992 0.178005 0.691441 0 +5993 0.171747 0.692656 0 +5994 0.182033 0.696445 0 +5995 0.186831 0.703555 0 +5996 0.192195 0.7116440000000001 0 +5997 0.198031 0.719847 0 +5998 0.203892 0.728227 0 +5999 0.210022 0.7373189999999999 0 +6000 0.21694 0.748292 0 +6001 0.229213 0.752231 0 +6002 0.238066 0.755088 0 +6003 0.236192 0.763448 0 +6004 0.235301 0.772369 0 +6005 0.23547 0.781516 0 +6006 0.245493 0.790164 0 +6007 0.236115 0.790797 0 +6008 0.254694 0.789018 0 +6009 0.263628 0.786909 0 +6010 0.272076 0.783899 0 +6011 0.276722 0.792445 0 +6012 0.286163 0.7952090000000001 0 +6013 0.292864 0.798256 0 +6014 0.29783 0.803349 0 +6015 0.302486 0.80969 0 +6016 0.307199 0.816852 0 +6017 0.324836 0.836711 0 +6018 0.330294 0.847452 0 +6019 0.321239 0.8451880000000001 0 +6020 0.33912 0.848007 0 +6021 0.348177 0.847533 0 +6022 0.357601 0.846464 0 +6023 0.367366 0.845168 0 +6024 0.377496 0.843747 0 +6025 0.388032 0.84219 0 +6026 0.398865 0.840663 0 +6027 0.410841 0.839512 0 +6028 0.422999 0.840578 0 +6029 0.434588 0.842127 0 +6030 0.445808 0.84387 0 +6031 0.456625 0.846325 0 +6032 0.467603 0.849989 0 +6033 0.477965 0.855519 0 +6034 0.487265 0.861215 0 +6035 0.495524 0.866712 0 +6036 0.503112 0.872592 0 +6037 0.5092680000000001 0.879349 0 +6038 0.522774 0.88196 0 +6039 0.514285 0.887257 0 +6040 0.530103 0.87485 0 +6041 0.537222 0.8681950000000001 0 +6042 0.545018 0.862617 0 +6043 0.553883 0.856905 0 +6044 0.563473 0.850843 0 +6045 0.572939 0.8448560000000001 0 +6046 0.581115 0.840534 0 +6047 0.587216 0.837769 0 +6048 0.613774 0.836734 0 +6049 0.605672 0.842618 0 +6050 0.621577 0.830035 0 +6051 0.855107 0.45703 0 +6052 0.856772 0.444376 0 +6053 0.858342 0.433614 0 +6054 0.859943 0.423209 0 +6055 0.861811 0.412825 0 +6056 0.863731 0.400949 0 +6057 0.871713 0.391177 0 +6058 0.869 0.375647 0 +6059 0.881381 0.381556 0 +6060 0.859118 0.371444 0 +6061 0.849803 0.368091 0 +6062 0.840953 0.365414 0 +6063 0.832786 0.363432 0 +6064 0.833384 0.355732 0 +6065 0.833601 0.347205 0 +6066 0.833538 0.338278 0 +6067 0.833417 0.328974 0 +6068 0.833162 0.319518 0 +6069 0.832356 0.310055 0 +6070 0.831016 0.30128 0 +6071 0.828877 0.294951 0 +6072 0.824998 0.286143 0 +6073 0.83297 0.289718 0 +6074 0.816303 0.283249 0 +6075 0.807047 0.280586 0 +6076 0.797662 0.278166 0 +6077 0.788174 0.27571 0 +6078 0.778711 0.272916 0 +6079 0.769379 0.269473 0 +6080 0.760109 0.265503 0 +6081 0.749564 0.260928 0 +6082 0.7439519999999999 0.252882 0 +6083 0.740558 0.248308 0 +6084 0.742397 0.243285 0 +6085 0.736626 0.235317 0 +6086 0.744387 0.236221 0 +6087 0.729604 0.235486 0 +6088 0.724341 0.235866 0 +6089 0.721462 0.231326 0 +6090 0.717658 0.224846 0 +6091 0.713216 0.217496 0 +6092 0.708664 0.209457 0 +6093 0.704409 0.200893 0 +6094 0.7005439999999999 0.192088 0 +6095 0.697062 0.18313 0 +6096 0.69391 0.174092 0 +6097 0.690871 0.165009 0 +6098 0.687684 0.155918 0 +6099 0.684195 0.146832 0 +6100 0.670859 0.141292 0 +6101 0.680531 0.137621 0 +6102 0.659829 0.146342 0 +6103 0.64784 0.145974 0 +6104 0.637923 0.146422 0 +6105 0.628681 0.147138 0 +6106 0.619699 0.146847 0 +6107 0.610802 0.145853 0 +6108 0.601804 0.144293 0 +6109 0.591436 0.151722 0 +6110 0.5925859999999999 0.142111 0 +6111 0.7866379999999999 0.695541 0 +6112 0.797157 0.693683 0 +6113 0.807123 0.691809 0 +6114 0.81681 0.689829 0 +6115 0.826336 0.68786 0 +6116 0.835986 0.675812 0 +6117 0.835803 0.685959 0 +6118 0.836324 0.665571 0 +6119 0.836575 0.655318 0 +6120 0.83613 0.645197 0 +6121 0.835024 0.635491 0 +6122 0.833388 0.626525 0 +6123 0.831742 0.618628 0 +6124 0.830363 0.612954 0 +6125 0.834448 0.608846 0 +6126 0.840031 0.602757 0 +6127 0.847056 0.593762 0 +6128 0.857535 0.5882270000000001 0 +6129 0.866459 0.582955 0 +6130 0.870869 0.569129 0 +6131 0.875796 0.577801 0 +6132 0.866002 0.560874 0 +6133 0.8613960000000001 0.552411 0 +6134 0.857565 0.54339 0 +6135 0.855486 0.533775 0 +6136 0.226754 0.7622370000000001 0 +6137 0.225882 0.772025 0 +6138 0.226021 0.781699 0 +6139 0.226607 0.791248 0 +6140 0.236948 0.800191 0 +6141 0.227342 0.800742 0 +6142 0.246507 0.79937 0 +6143 0.256041 0.798042 0 +6144 0.26558 0.796 0 +6145 0.216057 0.7616309999999999 0 +6146 0.215936 0.772374 0 +6147 0.216283 0.782237 0 +6148 0.216996 0.791798 0 +6149 0.217726 0.801301 0 +6150 0.228037 0.810322 0 +6151 0.21835 0.810817 0 +6152 0.2377 0.809723 0 +6153 0.247347 0.808833 0 +6154 0.256905 0.807491 0 +6155 0.266266 0.805613 0 +6156 0.275435 0.803496 0 +6157 0.283822 0.802924 0 +6158 0.289461 0.803023 0 +6159 0.29197 0.80802 0 +6160 0.295394 0.8147799999999999 0 +6161 0.299616 0.822219 0 +6162 0.762794 0.716947 0 +6163 0.762255 0.726432 0 +6164 0.206367 0.783292 0 +6165 0.205603 0.773597 0 +6166 0.207359 0.792679 0 +6167 0.20817 0.801992 0 +6168 0.208718 0.811346 0 +6169 0.21885 0.820428 0 +6170 0.209095 0.8208259999999999 0 +6171 0.228588 0.819983 0 +6172 0.238367 0.819387 0 +6173 0.248132 0.818512 0 +6174 0.257874 0.817269 0 +6175 0.267377 0.815372 0 +6176 0.276418 0.812854 0 +6177 0.284824 0.810536 0 +6178 0.899984 0.899985 0 +6179 0.889983 0.899984 0 +6180 0.87995 0.899936 0 +6181 0.869919 0.899855 0 +6182 0.8598789999999999 0.899722 0 +6183 0.849835 0.899535 0 +6184 0.839794 0.8993409999999999 0 +6185 0.829762 0.899162 0 +6186 0.819739 0.8990010000000001 0 +6187 0.809737 0.898899 0 +6188 0.799754 0.8989200000000001 0 +6189 0.789776 0.898977 0 +6190 0.779815 0.899062 0 +6191 0.769857 0.8991 0 +6192 0.759885 0.899062 0 +6193 0.749901 0.899038 0 +6194 0.739912 0.899038 0 +6195 0.729907 0.899129 0 +6196 0.719895 0.899212 0 +6197 0.709823 0.899251 0 +6198 0.699755 0.899273 0 +6199 0.689731 0.899309 0 +6200 0.679725 0.899291 0 +6201 0.669745 0.899318 0 +6202 0.659833 0.899621 0 +6203 0.65001 0.899828 0 +6204 0.640242 0.899515 0 +6205 0.630448 0.898584 0 +6206 0.620579 0.89789 0 +6207 0.610567 0.8977039999999999 0 +6208 0.6006010000000001 0.897944 0 +6209 0.590679 0.897959 0 +6210 0.580828 0.897616 0 +6211 0.571005 0.897243 0 +6212 0.561186 0.897177 0 +6213 0.551488 0.896918 0 +6214 0.541521 0.895841 0 +6215 0.529772 0.892571 0 +6216 0.5179859999999999 0.896779 0 +6217 0.508383 0.899481 0 +6218 0.499653 0.901052 0 +6219 0.490644 0.9010049999999999 0 +6220 0.481566 0.899964 0 +6221 0.472205 0.898505 0 +6222 0.462478 0.897025 0 +6223 0.452396 0.896158 0 +6224 0.442054 0.895755 0 +6225 0.431644 0.895662 0 +6226 0.421232 0.895643 0 +6227 0.410831 0.895684 0 +6228 0.400421 0.89581 0 +6229 0.39005 0.896041 0 +6230 0.379749 0.896343 0 +6231 0.369469 0.896656 0 +6232 0.359236 0.896947 0 +6233 0.349051 0.897184 0 +6234 0.338914 0.897338 0 +6235 0.328808 0.897409 0 +6236 0.318726 0.897525 0 +6237 0.308708 0.897846 0 +6238 0.298774 0.898393 0 +6239 0.288907 0.89894 0 +6240 0.279062 0.899282 0 +6241 0.269241 0.8995300000000001 0 +6242 0.259405 0.899662 0 +6243 0.249569 0.899767 0 +6244 0.239693 0.8998 0 +6245 0.229788 0.899762 0 +6246 0.219857 0.899733 0 +6247 0.209904 0.899691 0 +6248 0.199935 0.899695 0 +6249 0.189957 0.899735 0 +6250 0.179971 0.899797 0 +6251 0.169981 0.899849 0 +6252 0.159987 0.899895 0 +6253 0.149991 0.899933 0 +6254 0.139994 0.89996 0 +6255 0.129996 0.8999779999999999 0 +6256 0.119998 0.899989 0 +6257 0.109999 0.899995 0 +6258 0.1 0.899998 0 +6259 0.199415 0.742475 0 +6260 0.194518 0.73343 0 +6261 0.197865 0.793798 0 +6262 0.196471 0.7848579999999999 0 +6263 0.1987 0.802739 0 +6264 0.199138 0.811869 0 +6265 0.199382 0.821204 0 +6266 0.209345 0.830454 0 +6267 0.199518 0.830725 0 +6268 0.219169 0.830126 0 +6269 0.229021 0.829734 0 +6270 0.238913 0.829196 0 +6271 0.248911 0.828481 0 +6272 0.259069 0.827435 0 +6273 0.269174 0.825441 0 +6274 0.278948 0.821942 0 +6275 0.287501 0.818537 0 +6276 0.1952 0.775452 0 +6277 0.291415 0.826608 0 +6278 0.304519 0.830415 0 +6279 0.295859 0.8346479999999999 0 +6280 0.310649 0.840677 0 +6281 0.299722 0.8430879999999999 0 +6282 0.309592 0.853305 0 +6283 0.300824 0.851956 0 +6284 0.319498 0.855257 0 +6285 0.329277 0.856637 0 +6286 0.338788 0.857212 0 +6287 0.348502 0.856941 0 +6288 0.358342 0.856222 0 +6289 0.36836 0.855272 0 +6290 0.378634 0.854167 0 +6291 0.389148 0.853012 0 +6292 0.399904 0.851973 0 +6293 0.410984 0.851491 0 +6294 0.422176 0.851927 0 +6295 0.433122 0.852823 0 +6296 0.443615 0.854063 0 +6297 0.453297 0.856199 0 +6298 0.462125 0.860796 0 +6299 0.471863 0.865215 0 +6300 0.481185 0.869694 0 +6301 0.489834 0.874373 0 +6302 0.49715 0.878961 0 +6303 0.502924 0.88405 0 +6304 0.506178 0.891008 0 +6305 0.536569 0.882064 0 +6306 0.542265 0.875319 0 +6307 0.549681 0.870914 0 +6308 0.558725 0.866992 0 +6309 0.570551 0.86302 0 +6310 0.5785360000000001 0.85341 0 +6311 0.585827 0.847476 0 +6312 0.592543 0.842086 0 +6313 0.598317 0.848843 0 +6314 0.6112570000000001 0.851459 0 +6315 0.603474 0.8566589999999999 0 +6316 0.6193689999999999 0.845579 0 +6317 0.627417 0.8392579999999999 0 +6318 0.635944 0.833109 0 +6319 0.644996 0.82828 0 +6320 0.653575 0.8236520000000001 0 +6321 0.661736 0.819089 0 +6322 0.6695950000000001 0.814791 0 +6323 0.677455 0.81132 0 +6324 0.68551 0.808694 0 +6325 0.693873 0.806469 0 +6326 0.702315 0.8042589999999999 0 +6327 0.710803 0.802206 0 +6328 0.719152 0.800509 0 +6329 0.725382 0.791239 0 +6330 0.727046 0.79874 0 +6331 0.726333 0.783295 0 +6332 0.729024 0.774014 0 +6333 0.733804 0.7636579999999999 0 +6334 0.740328 0.754076 0 +6335 0.746466 0.745624 0 +6336 0.751761 0.738476 0 +6337 0.7557199999999999 0.733429 0 +6338 0.76188 0.734582 0 +6339 0.770923 0.726975 0 +6340 0.770049 0.736096 0 +6341 0.771489 0.718217 0 +6342 0.77215 0.711235 0 +6343 0.778836 0.708332 0 +6344 0.7880740000000001 0.706153 0 +6345 0.7978730000000001 0.704299 0 +6346 0.807557 0.702399 0 +6347 0.817103 0.7002429999999999 0 +6348 0.826536 0.6980229999999999 0 +6349 0.835874 0.6959610000000001 0 +6350 0.845197 0.6844209999999999 0 +6351 0.845121 0.694311 0 +6352 0.845511 0.674336 0 +6353 0.8460760000000001 0.664233 0 +6354 0.8468869999999999 0.653373 0 +6355 0.846341 0.642692 0 +6356 0.844616 0.632507 0 +6357 0.842176 0.623251 0 +6358 0.838654 0.615204 0 +6359 0.845825 0.610027 0 +6360 0.853706 0.6034040000000001 0 +6361 0.861993 0.5969370000000001 0 +6362 0.87018 0.591495 0 +6363 0.878968 0.587358 0 +6364 0.887216 0.571531 0 +6365 0.888949 0.583853 0 +6366 0.879242 0.563253 0 +6367 0.874045 0.55544 0 +6368 0.869903 0.547367 0 +6369 0.866804 0.53866 0 +6370 0.864381 0.529865 0 +6371 0.853735 0.525217 0 +6372 0.8619790000000001 0.521886 0 +6373 0.852333 0.517866 0 +6374 0.852017 0.511782 0 +6375 0.854271 0.506318 0 +6376 0.8575390000000001 0.501664 0 +6377 0.862741 0.498383 0 +6378 0.869472 0.495049 0 +6379 0.8733610000000001 0.481434 0 +6380 0.877552 0.490902 0 +6381 0.8670060000000001 0.473735 0 +6382 0.860598 0.4671 0 +6383 0.899994 0.100001 0 +6384 0.899995 0.110001 0 +6385 0.899995 0.120001 0 +6386 0.899996 0.130001 0 +6387 0.899996 0.140001 0 +6388 0.899996 0.150001 0 +6389 0.899997 0.160001 0 +6390 0.899998 0.170003 0 +6391 0.899999 0.180005 0 +6392 0.899975 0.190007 0 +6393 0.8999200000000001 0.200008 0 +6394 0.899832 0.210019 0 +6395 0.899699 0.220041 0 +6396 0.899566 0.230087 0 +6397 0.899415 0.240147 0 +6398 0.899294 0.250185 0 +6399 0.899303 0.260171 0 +6400 0.899606 0.27004 0 +6401 0.9002599999999999 0.27976 0 +6402 0.900804 0.28935 0 +6403 0.900824 0.298854 0 +6404 0.900083 0.308324 0 +6405 0.898933 0.317884 0 +6406 0.89799 0.327682 0 +6407 0.897244 0.337706 0 +6408 0.896542 0.347946 0 +6409 0.895817 0.35843 0 +6410 0.895282 0.369105 0 +6411 0.89532 0.3802 0 +6412 0.897394 0.390729 0 +6413 0.89907 0.400444 0 +6414 0.89966 0.409784 0 +6415 0.899551 0.419453 0 +6416 0.89911 0.429403 0 +6417 0.898481 0.439654 0 +6418 0.89773 0.450216 0 +6419 0.896966 0.460936 0 +6420 0.896523 0.472405 0 +6421 0.897639 0.483881 0 +6422 0.899006 0.494447 0 +6423 0.900085 0.504897 0 +6424 0.9010860000000001 0.514977 0 +6425 0.902007 0.524737 0 +6426 0.902783 0.534205 0 +6427 0.90313 0.54349 0 +6428 0.9028929999999999 0.552484 0 +6429 0.901461 0.561727 0 +6430 0.899567 0.571828 0 +6431 0.899529 0.582333 0 +6432 0.899995 0.592471 0 +6433 0.900313 0.602149 0 +6434 0.900056 0.6119329999999999 0 +6435 0.899621 0.621798 0 +6436 0.899555 0.63173 0 +6437 0.899838 0.64162 0 +6438 0.900328 0.651489 0 +6439 0.900741 0.6613329999999999 0 +6440 0.900972 0.671179 0 +6441 0.901101 0.681024 0 +6442 0.901106 0.69088 0 +6443 0.9010590000000001 0.700748 0 +6444 0.900961 0.71062 0 +6445 0.900803 0.720506 0 +6446 0.900569 0.73039 0 +6447 0.9003989999999999 0.740293 0 +6448 0.9003060000000001 0.750213 0 +6449 0.900258 0.760144 0 +6450 0.900206 0.770092 0 +6451 0.9001209999999999 0.780051 0 +6452 0.899987 0.789992 0 +6453 0.899831 0.799952 0 +6454 0.899686 0.8099150000000001 0 +6455 0.899589 0.819879 0 +6456 0.899548 0.8298680000000001 0 +6457 0.899567 0.839857 0 +6458 0.899641 0.849871 0 +6459 0.899711 0.859887 0 +6460 0.899799 0.869907 0 +6461 0.899872 0.87993 0 +6462 0.899946 0.889965 0 +6463 0.100004 0.0999998 0 +6464 0.110005 0.1 0 +6465 0.120005 0.0999998 0 +6466 0.130005 0.09999950000000001 0 +6467 0.140005 0.0999993 0 +6468 0.150005 0.0999994 0 +6469 0.160004 0.0999964 0 +6470 0.170003 0.0999937 0 +6471 0.180002 0.0999929 0 +6472 0.189994 0.100026 0 +6473 0.199999 0.100123 0 +6474 0.21002 0.100369 0 +6475 0.220058 0.10071 0 +6476 0.230134 0.101187 0 +6477 0.240257 0.101681 0 +6478 0.250412 0.102138 0 +6479 0.260594 0.102467 0 +6480 0.270799 0.102672 0 +6481 0.281008 0.102809 0 +6482 0.291194 0.102825 0 +6483 0.30132 0.10262 0 +6484 0.311398 0.10232 0 +6485 0.32142 0.102003 0 +6486 0.331371 0.101811 0 +6487 0.341333 0.101837 0 +6488 0.3513 0.102026 0 +6489 0.36129 0.102191 0 +6490 0.371336 0.102482 0 +6491 0.381422 0.102862 0 +6492 0.391574 0.103079 0 +6493 0.401779 0.103242 0 +6494 0.412008 0.103282 0 +6495 0.422214 0.102842 0 +6496 0.432378 0.102364 0 +6497 0.442605 0.102324 0 +6498 0.454655 0.103953 0 +6499 0.464822 0.0996292 0 +6500 0.473074 0.097511 0 +6501 0.481214 0.0980741 0 +6502 0.490488 0.0994712 0 +6503 0.500071 0.0995608 0 +6504 0.509579 0.100286 0 +6505 0.519347 0.101666 0 +6506 0.529429 0.103246 0 +6507 0.539995 0.104319 0 +6508 0.550711 0.104025 0 +6509 0.561212 0.103624 0 +6510 0.571429 0.103015 0 +6511 0.58128 0.102161 0 +6512 0.591135 0.102106 0 +6513 0.601233 0.102293 0 +6514 0.611556 0.102016 0 +6515 0.621642 0.102017 0 +6516 0.631731 0.102308 0 +6517 0.641836 0.102126 0 +6518 0.651826 0.101565 0 +6519 0.66169 0.100708 0 +6520 0.671395 0.0997711 0 +6521 0.6809539999999999 0.0990162 0 +6522 0.690397 0.0987828 0 +6523 0.699887 0.099245 0 +6524 0.709676 0.0993444 0 +6525 0.719615 0.0992695 0 +6526 0.729607 0.0992002 0 +6527 0.739594 0.09925440000000001 0 +6528 0.749593 0.0994346 0 +6529 0.7596039999999999 0.09958649999999999 0 +6530 0.769639 0.0997021 0 +6531 0.779685 0.0997782 0 +6532 0.789734 0.0998513 0 +6533 0.799782 0.0999056 0 +6534 0.809825 0.0999369 0 +6535 0.819862 0.0999627 0 +6536 0.829893 0.09998079999999999 0 +6537 0.8399180000000001 0.0999911 0 +6538 0.849939 0.0999963 0 +6539 0.859955 0.0999988 0 +6540 0.869969 0.0999999 0 +6541 0.879979 0.1 0 +6542 0.889989 0.100001 0 +6543 0.0999998 0.889998 0 +6544 0.1 0.8799979999999999 0 +6545 0.0999999 0.869998 0 +6546 0.0999999 0.859999 0 +6547 0.0999998 0.8499989999999999 0 +6548 0.0999987 0.8399990000000001 0 +6549 0.0999974 0.83 0 +6550 0.100043 0.820003 0 +6551 0.100092 0.810002 0 +6552 0.100194 0.799988 0 +6553 0.100336 0.789955 0 +6554 0.100565 0.779907 0 +6555 0.100852 0.769842 0 +6556 0.101205 0.759753 0 +6557 0.101646 0.74965 0 +6558 0.102029 0.739534 0 +6559 0.102271 0.729394 0 +6560 0.102291 0.719287 0 +6561 0.102122 0.709194 0 +6562 0.101822 0.699113 0 +6563 0.101486 0.689009 0 +6564 0.101157 0.678931 0 +6565 0.100843 0.668859 0 +6566 0.100528 0.658768 0 +6567 0.100266 0.648652 0 +6568 0.100061 0.638535 0 +6569 0.0995193 0.628418 0 +6570 0.0985824 0.61876 0 +6571 0.0978087 0.60932 0 +6572 0.0980968 0.599919 0 +6573 0.0989168 0.59013 0 +6574 0.0997252 0.580131 0 +6575 0.100364 0.569536 0 +6576 0.100013 0.558975 0 +6577 0.09936879999999999 0.548693 0 +6578 0.09867960000000001 0.5387960000000001 0 +6579 0.0983414 0.529262 0 +6580 0.09898849999999999 0.519738 0 +6581 0.0999751 0.509947 0 +6582 0.100724 0.499849 0 +6583 0.101104 0.489539 0 +6584 0.100956 0.479232 0 +6585 0.100355 0.469 0 +6586 0.099759 0.458929 0 +6587 0.0996522 0.448931 0 +6588 0.100279 0.438918 0 +6589 0.101518 0.428789 0 +6590 0.102767 0.41856 0 +6591 0.10349 0.408197 0 +6592 0.10425 0.397802 0 +6593 0.104869 0.387424 0 +6594 0.104937 0.377076 0 +6595 0.104537 0.366829 0 +6596 0.103851 0.35672 0 +6597 0.102996 0.346752 0 +6598 0.102065 0.336921 0 +6599 0.101184 0.32721 0 +6600 0.100492 0.317581 0 +6601 0.100157 0.308001 0 +6602 0.100173 0.298417 0 +6603 0.100337 0.288759 0 +6604 0.100376 0.279041 0 +6605 0.100259 0.269254 0 +6606 0.100124 0.259422 0 +6607 0.100027 0.249555 0 +6608 0.100017 0.239653 0 +6609 0.10008 0.229738 0 +6610 0.100182 0.219805 0 +6611 0.100277 0.20986 0 +6612 0.100317 0.199903 0 +6613 0.10037 0.189934 0 +6614 0.100341 0.179956 0 +6615 0.100288 0.169971 0 +6616 0.100218 0.159981 0 +6617 0.100151 0.149988 0 +6618 0.100098 0.139992 0 +6619 0.100058 0.129995 0 +6620 0.100031 0.119997 0 +6621 0.100014 0.109999 0 +6622 0.581649 0.14971 0 +6623 0.571518 0.147612 0 +6624 0.561152 0.145926 0 +6625 0.550789 0.144243 0 +6626 0.54054 0.141971 0 +6627 0.530548 0.138334 0 +6628 0.5207310000000001 0.13415 0 +6629 0.511466 0.129692 0 +6630 0.502973 0.124844 0 +6631 0.49581 0.119527 0 +6632 0.48986 0.110598 0 +6633 0.480069 0.106324 0 +6634 0.469093 0.107436 0 +6635 0.474114 0.103778 0 +6636 0.445109 0.128329 0 +6637 0.451862 0.124753 0 +6638 0.437181 0.13131 0 +6639 0.428554 0.134281 0 +6640 0.419719 0.137594 0 +6641 0.412043 0.141645 0 +6642 0.403855 0.143932 0 +6643 0.395097 0.146104 0 +6644 0.386233 0.14863 0 +6645 0.378358 0.152279 0 +6646 0.371349 0.155257 0 +6647 0.360802 0.152519 0 +6648 0.367582 0.148374 0 +6649 0.354401 0.158456 0 +6650 0.347208 0.167057 0 +6651 0.34721 0.178562 0 +6652 0.338576 0.180447 0 +6653 0.329859 0.183263 0 +6654 0.321128 0.18642 0 +6655 0.312603 0.189568 0 +6656 0.304408 0.192058 0 +6657 0.296939 0.193556 0 +6658 0.289444 0.192911 0 +6659 0.281299 0.200793 0 +6660 0.281322 0.191959 0 +6661 0.281514 0.209155 0 +6662 0.281487 0.216668 0 +6663 0.26893 0.226876 0 +6664 0.276164 0.224331 0 +6665 0.260909 0.229533 0 +6666 0.252329 0.232535 0 +6667 0.241961 0.236851 0 +6668 0.230293 0.236179 0 +6669 0.220255 0.245896 0 +6670 0.220165 0.236531 0 +6671 0.220945 0.254676 0 +6672 0.222141 0.262748 0 +6673 0.223264 0.268721 0 +6674 0.728413 0.228724 0 +6675 0.725835 0.221141 0 +6676 0.722179 0.213015 0 +6677 0.717795 0.204914 0 +6678 0.713455 0.19661 0 +6679 0.709399 0.18818 0 +6680 0.705761 0.179623 0 +6681 0.702666 0.170882 0 +6682 0.699747 0.161958 0 +6683 0.696712 0.152914 0 +6684 0.693553 0.143719 0 +6685 0.690407 0.134325 0 +6686 0.677304 0.12819 0 +6687 0.68706 0.125045 0 +6688 0.667512 0.131056 0 +6689 0.657169 0.133612 0 +6690 0.646626 0.134788 0 +6691 0.6367930000000001 0.136181 0 +6692 0.628439 0.138218 0 +6693 0.6201759999999999 0.138075 0 +6694 0.611704 0.137141 0 +6695 0.603138 0.135391 0 +6696 0.59456 0.13277 0 +6697 0.583107 0.139595 0 +6698 0.585239 0.129707 0 +6699 0.858671 0.515997 0 +6700 0.85648 0.51215 0 +6701 0.858502 0.508589 0 +6702 0.860274 0.504955 0 +6703 0.886978 0.486532 0 +6704 0.889154 0.497209 0 +6705 0.879906 0.5006119999999999 0 +6706 0.883412 0.473405 0 +6707 0.873198 0.46681 0 +6708 0.866815 0.463155 0 +6709 0.866339 0.455631 0 +6710 0.867182 0.445789 0 +6711 0.868412 0.43556 0 +6712 0.869856 0.425377 0 +6713 0.871583 0.415425 0 +6714 0.874069 0.405736 0 +6715 0.8790249999999999 0.397931 0 +6716 0.887166 0.39295 0 +6717 0.851874 0.359373 0 +6718 0.86172 0.362119 0 +6719 0.84243 0.35717 0 +6720 0.591332 0.854088 0 +6721 0.595963 0.860535 0 +6722 0.607125 0.865522 0 +6723 0.59828 0.868252 0 +6724 0.616356 0.861069 0 +6725 0.62477 0.8545970000000001 0 +6726 0.632931 0.848407 0 +6727 0.641438 0.842707 0 +6728 0.650073 0.837577 0 +6729 0.658372 0.832528 0 +6730 0.666272 0.827649 0 +6731 0.673586 0.823001 0 +6732 0.680274 0.819215 0 +6733 0.6876719999999999 0.817308 0 +6734 0.695782 0.8154709999999999 0 +6735 0.704243 0.813406 0 +6736 0.712797 0.811375 0 +6737 0.721349 0.809379 0 +6738 0.729669 0.807024 0 +6739 0.734065 0.796291 0 +6740 0.73756 0.803651 0 +6741 0.738443 0.778207 0 +6742 0.73404 0.785816 0 +6743 0.74394 0.769018 0 +6744 0.749668 0.759576 0 +6745 0.754816 0.750634 0 +6746 0.759062 0.7422339999999999 0 +6747 0.767651 0.745104 0 +6748 0.779172 0.736962 0 +6749 0.777254 0.747117 0 +6750 0.779914 0.726994 0 +6751 0.779871 0.717477 0 +6752 0.204998 0.289441 0 +6753 0.215126 0.284967 0 +6754 0.19477 0.29316 0 +6755 0.184648 0.29691 0 +6756 0.174706 0.300974 0 +6757 0.164957 0.305306 0 +6758 0.155589 0.310206 0 +6759 0.147055 0.315119 0 +6760 0.138594 0.319532 0 +6761 0.131602 0.331495 0 +6762 0.129715 0.322535 0 +6763 0.133525 0.340944 0 +6764 0.13546 0.350869 0 +6765 0.137426 0.361268 0 +6766 0.139501 0.372296 0 +6767 0.141391 0.386131 0 +6768 0.150258 0.395209 0 +6769 0.156392 0.403058 0 +6770 0.161015 0.408785 0 +6771 0.159186 0.417429 0 +6772 0.137664 0.442573 0 +6773 0.14382 0.434353 0 +6774 0.132057 0.449792 0 +6775 0.125804 0.455164 0 +6776 0.120026 0.466995 0 +6777 0.118037 0.457605 0 +6778 0.122076 0.478344 0 +6779 0.131795 0.50427 0 +6780 0.133083 0.491205 0 +6781 0.130272 0.519543 0 +6782 0.138005 0.543834 0 +6783 0.843403 0.348409 0 +6784 0.843782 0.339208 0 +6785 0.843885 0.329629 0 +6786 0.843724 0.319707 0 +6787 0.843016 0.309356 0 +6788 0.84101 0.297212 0 +6789 0.836769 0.282003 0 +6790 0.8454 0.286818 0 +6791 0.828082 0.278058 0 +6792 0.819098 0.274649 0 +6793 0.809887 0.271687 0 +6794 0.800571 0.269081 0 +6795 0.791262 0.266635 0 +6796 0.782111 0.263743 0 +6797 0.773133 0.260333 0 +6798 0.764367 0.256436 0 +6799 0.755787 0.251786 0 +6800 0.748743 0.246677 0 +6801 0.752158 0.239179 0 +6802 0.7460909999999999 0.227541 0 +6803 0.755331 0.230552 0 +6804 0.736712 0.227241 0 +6805 0.889899 0.889922 0 +6806 0.879858 0.8898509999999999 0 +6807 0.869798 0.889718 0 +6808 0.859729 0.889525 0 +6809 0.849661 0.889289 0 +6810 0.839603 0.889038 0 +6811 0.829553 0.888774 0 +6812 0.8195249999999999 0.88854 0 +6813 0.809526 0.888454 0 +6814 0.799553 0.888487 0 +6815 0.789614 0.888621 0 +6816 0.779689 0.888722 0 +6817 0.769752 0.888723 0 +6818 0.759806 0.888656 0 +6819 0.749853 0.8885459999999999 0 +6820 0.739865 0.888602 0 +6821 0.72985 0.888756 0 +6822 0.719769 0.888897 0 +6823 0.709655 0.88897 0 +6824 0.699584 0.88902 0 +6825 0.689535 0.88912 0 +6826 0.6795 0.889046 0 +6827 0.669512 0.888978 0 +6828 0.659645 0.8895650000000001 0 +6829 0.650006 0.890081 0 +6830 0.640678 0.889746 0 +6831 0.631155 0.888374 0 +6832 0.621032 0.886698 0 +6833 0.610561 0.8870170000000001 0 +6834 0.600553 0.887657 0 +6835 0.590632 0.887806 0 +6836 0.5808449999999999 0.887239 0 +6837 0.571105 0.886973 0 +6838 0.561466 0.88722 0 +6839 0.552461 0.887398 0 +6840 0.5441319999999999 0.88656 0 +6841 0.110017 0.109998 0 +6842 0.120019 0.109997 0 +6843 0.130019 0.109997 0 +6844 0.140018 0.109998 0 +6845 0.150016 0.109989 0 +6846 0.160014 0.109984 0 +6847 0.170011 0.109984 0 +6848 0.179979 0.110005 0 +6849 0.189958 0.110055 0 +6850 0.199941 0.110231 0 +6851 0.209937 0.110544 0 +6852 0.219981 0.111047 0 +6853 0.230081 0.111682 0 +6854 0.240244 0.112388 0 +6855 0.250486 0.113002 0 +6856 0.260801 0.113384 0 +6857 0.271148 0.11357 0 +6858 0.281502 0.113684 0 +6859 0.291786 0.113673 0 +6860 0.301979 0.113333 0 +6861 0.312058 0.112795 0 +6862 0.32201 0.112271 0 +6863 0.33188 0.111943 0 +6864 0.341749 0.112017 0 +6865 0.351632 0.112418 0 +6866 0.36162 0.112583 0 +6867 0.371663 0.112995 0 +6868 0.381763 0.113652 0 +6869 0.391996 0.113917 0 +6870 0.402319 0.114177 0 +6871 0.41275 0.114361 0 +6872 0.422994 0.113475 0 +6873 0.432741 0.112491 0 +6874 0.44205 0.112354 0 +6875 0.450541 0.113776 0 +6876 0.134822 0.532983 0 +6877 0.189792 0.746534 0 +6878 0.18525 0.737964 0 +6879 0.8899860000000001 0.110001 0 +6880 0.889985 0.120001 0 +6881 0.889983 0.130001 0 +6882 0.889983 0.140001 0 +6883 0.889985 0.150002 0 +6884 0.8899899999999999 0.160003 0 +6885 0.889994 0.170005 0 +6886 0.88995 0.180001 0 +6887 0.889894 0.189988 0 +6888 0.889782 0.199986 0 +6889 0.889669 0.209998 0 +6890 0.889494 0.220034 0 +6891 0.889287 0.230111 0 +6892 0.889061 0.240183 0 +6893 0.888887 0.250301 0 +6894 0.888825 0.260365 0 +6895 0.889444 0.270329 0 +6896 0.890501 0.279915 0 +6897 0.891551 0.289212 0 +6898 0.8917119999999999 0.298274 0 +6899 0.890492 0.307041 0 +6900 0.888843 0.316331 0 +6901 0.887479 0.326243 0 +6902 0.886579 0.3363 0 +6903 0.885771 0.346609 0 +6904 0.884803 0.357225 0 +6905 0.883396 0.368234 0 +6906 0.890246 0.401394 0 +6907 0.890518 0.409785 0 +6908 0.889999 0.418899 0 +6909 0.889246 0.428654 0 +6910 0.888364 0.438834 0 +6911 0.887294 0.449172 0 +6912 0.885901 0.460211 0 +6913 0.890423 0.507368 0 +6914 0.891651 0.517437 0 +6915 0.892914 0.527004 0 +6916 0.894081 0.536139 0 +6917 0.89497 0.544744 0 +6918 0.895078 0.552546 0 +6919 0.892607 0.560411 0 +6920 0.89028 0.593931 0 +6921 0.890873 0.60342 0 +6922 0.890505 0.6126779999999999 0 +6923 0.889635 0.62246 0 +6924 0.889298 0.632486 0 +6925 0.889785 0.6424609999999999 0 +6926 0.890602 0.652255 0 +6927 0.891203 0.662022 0 +6928 0.89151 0.671751 0 +6929 0.891618 0.681519 0 +6930 0.891616 0.691309 0 +6931 0.891557 0.701098 0 +6932 0.891417 0.7108989999999999 0 +6933 0.891164 0.720706 0 +6934 0.890853 0.730535 0 +6935 0.890591 0.740385 0 +6936 0.89047 0.75026 0 +6937 0.890415 0.760163 0 +6938 0.890323 0.770085 0 +6939 0.890197 0.779981 0 +6940 0.889977 0.789903 0 +6941 0.88975 0.79982 0 +6942 0.889547 0.809743 0 +6943 0.889392 0.819696 0 +6944 0.8893450000000001 0.829673 0 +6945 0.889382 0.8396940000000001 0 +6946 0.88946 0.849716 0 +6947 0.889568 0.859747 0 +6948 0.889684 0.869794 0 +6949 0.889801 0.879853 0 +6950 0.789082 0.716287 0 +6951 0.798598 0.714916 0 +6952 0.80821 0.713077 0 +6953 0.81769 0.710637 0 +6954 0.82704 0.708084 0 +6955 0.836211 0.705761 0 +6956 0.845267 0.7039530000000001 0 +6957 0.854379 0.693259 0 +6958 0.854363 0.702846 0 +6959 0.854528 0.683504 0 +6960 0.854972 0.673681 0 +6961 0.855842 0.663426 0 +6962 0.858436 0.65159 0 +6963 0.856864 0.639544 0 +6964 0.854758 0.628338 0 +6965 0.8506089999999999 0.618523 0 +6966 0.8594540000000001 0.612106 0 +6967 0.866835 0.6048559999999999 0 +6968 0.873438 0.599401 0 +6969 0.881174 0.596457 0 +6970 0.498852 0.89319 0 +6971 0.491369 0.892578 0 +6972 0.473812 0.888556 0 +6973 0.483026 0.890835 0 +6974 0.464179 0.886483 0 +6975 0.453648 0.884842 0 +6976 0.442773 0.884772 0 +6977 0.432149 0.8847699999999999 0 +6978 0.421544 0.884741 0 +6979 0.410992 0.884775 0 +6980 0.400473 0.884978 0 +6981 0.390056 0.8853220000000001 0 +6982 0.379669 0.885763 0 +6983 0.369345 0.886207 0 +6984 0.359095 0.886612 0 +6985 0.3489 0.886918 0 +6986 0.338746 0.887074 0 +6987 0.328578 0.88708 0 +6988 0.318429 0.887083 0 +6989 0.308326 0.887384 0 +6990 0.298382 0.888227 0 +6991 0.288517 0.888915 0 +6992 0.278755 0.889309 0 +6993 0.269001 0.889516 0 +6994 0.259264 0.889629 0 +6995 0.24947 0.8896849999999999 0 +6996 0.23963 0.889671 0 +6997 0.229743 0.889646 0 +6998 0.219822 0.889605 0 +6999 0.209878 0.889607 0 +7000 0.199916 0.8896579999999999 0 +7001 0.18994 0.889716 0 +7002 0.179957 0.889771 0 +7003 0.169968 0.889825 0 +7004 0.159976 0.889875 0 +7005 0.149983 0.889918 0 +7006 0.139988 0.88995 0 +7007 0.129992 0.889972 0 +7008 0.119996 0.8899860000000001 0 +7009 0.109999 0.889994 0 +7010 0.109999 0.8799940000000001 0 +7011 0.109998 0.869995 0 +7012 0.109998 0.859995 0 +7013 0.109994 0.849996 0 +7014 0.10999 0.839998 0 +7015 0.110015 0.830005 0 +7016 0.110071 0.820011 0 +7017 0.110185 0.81001 0 +7018 0.110336 0.799997 0 +7019 0.110577 0.789967 0 +7020 0.110883 0.7799199999999999 0 +7021 0.111257 0.769829 0 +7022 0.111723 0.75971 0 +7023 0.112269 0.749557 0 +7024 0.112791 0.739376 0 +7025 0.113109 0.729196 0 +7026 0.113086 0.719028 0 +7027 0.112772 0.7088680000000001 0 +7028 0.112335 0.698715 0 +7029 0.111877 0.688568 0 +7030 0.111448 0.678466 0 +7031 0.111015 0.668365 0 +7032 0.110622 0.658218 0 +7033 0.110349 0.647991 0 +7034 0.110168 0.637717 0 +7035 0.109835 0.627117 0 +7036 0.107738 0.617242 0 +7037 0.106137 0.608941 0 +7038 0.106815 0.6006280000000001 0 +7039 0.108229 0.591238 0 +7040 0.109734 0.5808489999999999 0 +7041 0.110883 0.569295 0 +7042 0.107469 0.5373869999999999 0 +7043 0.108762 0.54687 0 +7044 0.106707 0.528987 0 +7045 0.107757 0.520873 0 +7046 0.109536 0.511332 0 +7047 0.110898 0.500677 0 +7048 0.111446 0.489983 0 +7049 0.111328 0.479225 0 +7050 0.110231 0.468527 0 +7051 0.109184 0.458719 0 +7052 0.108808 0.449056 0 +7053 0.109861 0.439611 0 +7054 0.111702 0.429682 0 +7055 0.113723 0.418654 0 +7056 0.114227 0.407845 0 +7057 0.115144 0.39727 0 +7058 0.115862 0.386665 0 +7059 0.116025 0.375964 0 +7060 0.115458 0.365541 0 +7061 0.114425 0.355333 0 +7062 0.113253 0.34535 0 +7063 0.112043 0.335614 0 +7064 0.110903 0.326063 0 +7065 0.110116 0.31661 0 +7066 0.109742 0.307319 0 +7067 0.109963 0.297975 0 +7068 0.110443 0.288476 0 +7069 0.110525 0.278812 0 +7070 0.11035 0.269064 0 +7071 0.110143 0.259255 0 +7072 0.110024 0.249403 0 +7073 0.110041 0.239544 0 +7074 0.110145 0.229661 0 +7075 0.110255 0.219758 0 +7076 0.110343 0.209833 0 +7077 0.110442 0.199888 0 +7078 0.110445 0.189925 0 +7079 0.110412 0.179949 0 +7080 0.110337 0.169964 0 +7081 0.110255 0.159975 0 +7082 0.11018 0.149982 0 +7083 0.110118 0.139988 0 +7084 0.110071 0.129992 0 +7085 0.110039 0.119995 0 +7086 0.33627 0.170284 0 +7087 0.326782 0.173385 0 +7088 0.317695 0.176485 0 +7089 0.309097 0.179961 0 +7090 0.301421 0.183565 0 +7091 0.296186 0.187258 0 +7092 0.29019 0.184747 0 +7093 0.282 0.183195 0 +7094 0.272771 0.191408 0 +7095 0.273182 0.182186 0 +7096 0.272868 0.200462 0 +7097 0.27337 0.20914 0 +7098 0.274333 0.2172 0 +7099 0.266507 0.218619 0 +7100 0.258179 0.220447 0 +7101 0.24934 0.222587 0 +7102 0.239833 0.224723 0 +7103 0.229774 0.225787 0 +7104 0.219818 0.226733 0 +7105 0.210274 0.237516 0 +7106 0.209944 0.227767 0 +7107 0.21088 0.246999 0 +7108 0.21219 0.25617 0 +7109 0.214528 0.264822 0 +7110 0.21804 0.272645 0 +7111 0.200178 0.280046 0 +7112 0.209703 0.276365 0 +7113 0.190392 0.283489 0 +7114 0.180452 0.287213 0 +7115 0.170478 0.291357 0 +7116 0.160577 0.295842 0 +7117 0.150877 0.300853 0 +7118 0.142663 0.30718 0 +7119 0.135849 0.311781 0 +7120 0.128081 0.313939 0 +7121 0.120473 0.324523 0 +7122 0.119307 0.315507 0 +7123 0.121913 0.333804 0 +7124 0.123438 0.343425 0 +7125 0.124961 0.353386 0 +7126 0.126413 0.363724 0 +7127 0.127387 0.374549 0 +7128 0.127541 0.385936 0 +7129 0.150486 0.410746 0 +7130 0.1432 0.404146 0 +7131 0.150866 0.426213 0 +7132 0.14357 0.418875 0 +7133 0.13615 0.427241 0 +7134 0.130498 0.436384 0 +7135 0.126189 0.444202 0 +7136 0.129421 0.549136 0 +7137 0.114834 0.602261 0 +7138 0.121878 0.606841 0 +7139 0.12977 0.61369 0 +7140 0.138354 0.620713 0 +7141 0.146463 0.626856 0 +7142 0.154192 0.632956 0 +7143 0.162446 0.636968 0 +7144 0.160892 0.645787 0 +7145 0.161194 0.655686 0 +7146 0.161795 0.665529 0 +7147 0.16214 0.675373 0 +7148 0.162359 0.68503 0 +7149 0.163199 0.69432 0 +7150 0.174349 0.700336 0 +7151 0.165289 0.703575 0 +7152 0.178147 0.7086710000000001 0 +7153 0.183082 0.716858 0 +7154 0.188706 0.725106 0 +7155 0.500027 0.108445 0 +7156 0.528102 0.114028 0 +7157 0.5179550000000001 0.111477 0 +7158 0.539844 0.117131 0 +7159 0.5514829999999999 0.114907 0 +7160 0.562109 0.114319 0 +7161 0.5723510000000001 0.11345 0 +7162 0.581435 0.111677 0 +7163 0.590642 0.112102 0 +7164 0.601597 0.114088 0 +7165 0.612338 0.112029 0 +7166 0.622314 0.112134 0 +7167 0.632588 0.112985 0 +7168 0.642888 0.112804 0 +7169 0.653046 0.112038 0 +7170 0.662955 0.11081 0 +7171 0.672547 0.109431 0 +7172 0.681799 0.108256 0 +7173 0.690623 0.107811 0 +7174 0.69945 0.109115 0 +7175 0.709407 0.109228 0 +7176 0.719478 0.10901 0 +7177 0.729507 0.108826 0 +7178 0.739459 0.10889 0 +7179 0.749386 0.109233 0 +7180 0.759386 0.109462 0 +7181 0.769429 0.109583 0 +7182 0.7794990000000001 0.109693 0 +7183 0.789573 0.109782 0 +7184 0.799643 0.109834 0 +7185 0.809708 0.109893 0 +7186 0.819767 0.109927 0 +7187 0.829819 0.109955 0 +7188 0.839861 0.109976 0 +7189 0.849897 0.109989 0 +7190 0.8599250000000001 0.109995 0 +7191 0.869949 0.109999 0 +7192 0.8799709999999999 0.11 0 +7193 0.374418 0.144499 0 +7194 0.363813 0.141491 0 +7195 0.369851 0.139486 0 +7196 0.35626 0.14501 0 +7197 0.349215 0.150696 0 +7198 0.341407 0.156266 0 +7199 0.332308 0.160189 0 +7200 0.323052 0.163467 0 +7201 0.313669 0.166571 0 +7202 0.304338 0.170366 0 +7203 0.294275 0.175149 0 +7204 0.283304 0.173802 0 +7205 0.273843 0.172882 0 +7206 0.264142 0.181526 0 +7207 0.264707 0.171864 0 +7208 0.263995 0.191168 0 +7209 0.264288 0.200633 0 +7210 0.265117 0.209847 0 +7211 0.885466 0.5566449999999999 0 +7212 0.881232 0.550241 0 +7213 0.878 0.542562 0 +7214 0.875398 0.534019 0 +7215 0.873156 0.52477 0 +7216 0.86311 0.51097 0 +7217 0.8534119999999999 0.35025 0 +7218 0.854088 0.340654 0 +7219 0.854476 0.330806 0 +7220 0.854564 0.320569 0 +7221 0.8541530000000001 0.309653 0 +7222 0.852731 0.299164 0 +7223 0.854013 0.290117 0 +7224 0.863547 0.352495 0 +7225 0.864499 0.342535 0 +7226 0.865136 0.332399 0 +7227 0.865818 0.321685 0 +7228 0.866567 0.309448 0 +7229 0.861882 0.298818 0 +7230 0.8602109999999999 0.29235 0 +7231 0.85846 0.282281 0 +7232 0.864942 0.288032 0 +7233 0.849631 0.277792 0 +7234 0.840588 0.273589 0 +7235 0.831418 0.269613 0 +7236 0.822228 0.265878 0 +7237 0.812916 0.262634 0 +7238 0.8035369999999999 0.259983 0 +7239 0.794355 0.257821 0 +7240 0.785519 0.254977 0 +7241 0.776861 0.251528 0 +7242 0.7683759999999999 0.247625 0 +7243 0.760097 0.24326 0 +7244 0.585261 0.859449 0 +7245 0.599822 0.87753 0 +7246 0.590396 0.878014 0 +7247 0.5901960000000001 0.869424 0 +7248 0.610059 0.875911 0 +7249 0.622068 0.873071 0 +7250 0.630655 0.863538 0 +7251 0.638702 0.857128 0 +7252 0.647115 0.85167 0 +7253 0.655668 0.846532 0 +7254 0.663839 0.841043 0 +7255 0.671593 0.835526 0 +7256 0.678415 0.83007 0 +7257 0.682557 0.82507 0 +7258 0.688979 0.8255209999999999 0 +7259 0.697248 0.824264 0 +7260 0.705936 0.822498 0 +7261 0.714795 0.820541 0 +7262 0.72362 0.818429 0 +7263 0.732382 0.81585 0 +7264 0.740943 0.8124 0 +7265 0.7454190000000001 0.7988730000000001 0 +7266 0.749435 0.80788 0 +7267 0.74011 0.791307 0 +7268 0.746705 0.78415 0 +7269 0.753844 0.775183 0 +7270 0.759567 0.764503 0 +7271 0.764085 0.7544459999999999 0 +7272 0.735332 0.218151 0 +7273 0.731463 0.209126 0 +7274 0.72698 0.200606 0 +7275 0.72236 0.192359 0 +7276 0.718024 0.184259 0 +7277 0.714383 0.17623 0 +7278 0.711462 0.167899 0 +7279 0.7088 0.159204 0 +7280 0.706026 0.150221 0 +7281 0.703147 0.140948 0 +7282 0.70043 0.131237 0 +7283 0.697433 0.120104 0 +7284 0.6833090000000001 0.11686 0 +7285 0.690405 0.114954 0 +7286 0.674477 0.118888 0 +7287 0.664927 0.120859 0 +7288 0.654814 0.12265 0 +7289 0.6443140000000001 0.123885 0 +7290 0.633001 0.124982 0 +7291 0.627562 0.13098 0 +7292 0.62072 0.129893 0 +7293 0.6128479999999999 0.128698 0 +7294 0.574971 0.124917 0 +7295 0.581599 0.11937 0 +7296 0.588796 0.121311 0 +7297 0.573032 0.136955 0 +7298 0.282624 0.831031 0 +7299 0.287909 0.8388099999999999 0 +7300 0.29183 0.845456 0 +7301 0.293137 0.852863 0 +7302 0.300659 0.8590680000000001 0 +7303 0.294022 0.860376 0 +7304 0.30665 0.86473 0 +7305 0.318129 0.865803 0 +7306 0.328534 0.866606 0 +7307 0.338647 0.866907 0 +7308 0.348674 0.866724 0 +7309 0.358731 0.86622 0 +7310 0.368905 0.865496 0 +7311 0.379226 0.864665 0 +7312 0.389686 0.863824 0 +7313 0.400279 0.863123 0 +7314 0.411028 0.86281 0 +7315 0.421794 0.862969 0 +7316 0.432386 0.863377 0 +7317 0.442449 0.863809 0 +7318 0.450437 0.863969 0 +7319 0.45542 0.87191 0 +7320 0.466928 0.8754999999999999 0 +7321 0.476835 0.878982 0 +7322 0.485475 0.8822489999999999 0 +7323 0.492949 0.885266 0 +7324 0.883825 0.402814 0 +7325 0.882204 0.409116 0 +7326 0.880731 0.417707 0 +7327 0.879524 0.427294 0 +7328 0.87837 0.437326 0 +7329 0.877169 0.447487 0 +7330 0.884024 0.530027 0 +7331 0.882327 0.52069 0 +7332 0.885856 0.5388269999999999 0 +7333 0.887725 0.546417 0 +7334 0.889423 0.5518690000000001 0 +7335 0.875707 0.457493 0 +7336 0.763769 0.234645 0 +7337 0.759235 0.221397 0 +7338 0.768163 0.226412 0 +7339 0.747939 0.215521 0 +7340 0.562574 0.135519 0 +7341 0.5524559999999999 0.134205 0 +7342 0.543051 0.132179 0 +7343 0.53444 0.128005 0 +7344 0.524854 0.124333 0 +7345 0.51537 0.120769 0 +7346 0.5071369999999999 0.117607 0 +7347 0.501009 0.115195 0 +7348 0.508694 0.109423 0 +7349 0.8797199999999999 0.879736 0 +7350 0.869629 0.8795539999999999 0 +7351 0.859528 0.879306 0 +7352 0.849428 0.879005 0 +7353 0.839337 0.878653 0 +7354 0.829254 0.878285 0 +7355 0.819205 0.878004 0 +7356 0.809211 0.877897 0 +7357 0.799272 0.8779979999999999 0 +7358 0.789377 0.878189 0 +7359 0.7794990000000001 0.878347 0 +7360 0.769618 0.878373 0 +7361 0.759736 0.878203 0 +7362 0.749811 0.877976 0 +7363 0.739815 0.878091 0 +7364 0.729741 0.878362 0 +7365 0.719607 0.878596 0 +7366 0.709464 0.87867 0 +7367 0.699326 0.878718 0 +7368 0.6892509999999999 0.878985 0 +7369 0.679339 0.878946 0 +7370 0.669094 0.878408 0 +7371 0.65894 0.879569 0 +7372 0.649676 0.880733 0 +7373 0.641347 0.880959 0 +7374 0.632984 0.878313 0 +7375 0.563256 0.124813 0 +7376 0.553165 0.124525 0 +7377 0.545274 0.124534 0 +7378 0.119994 0.879985 0 +7379 0.119992 0.869986 0 +7380 0.119987 0.8599869999999999 0 +7381 0.11998 0.84999 0 +7382 0.119979 0.8399990000000001 0 +7383 0.120016 0.830013 0 +7384 0.120114 0.820027 0 +7385 0.120277 0.810037 0 +7386 0.120523 0.800041 0 +7387 0.12087 0.790032 0 +7388 0.121272 0.779966 0 +7389 0.121695 0.769872 0 +7390 0.122277 0.759721 0 +7391 0.122973 0.74952 0 +7392 0.123673 0.739278 0 +7393 0.124129 0.729004 0 +7394 0.123977 0.718718 0 +7395 0.123451 0.708457 0 +7396 0.12282 0.698224 0 +7397 0.122235 0.688066 0 +7398 0.121695 0.6779539999999999 0 +7399 0.121164 0.667847 0 +7400 0.120677 0.657732 0 +7401 0.120383 0.647651 0 +7402 0.120476 0.637244 0 +7403 0.121867 0.624417 0 +7404 0.116177 0.61409 0 +7405 0.580997 0.877227 0 +7406 0.570947 0.87627 0 +7407 0.561017 0.877318 0 +7408 0.552528 0.879036 0 +7409 0.546308 0.880305 0 +7410 0.882503 0.604535 0 +7411 0.443286 0.87365 0 +7412 0.432398 0.873899 0 +7413 0.42171 0.873837 0 +7414 0.41105 0.873865 0 +7415 0.400452 0.874133 0 +7416 0.389938 0.874621 0 +7417 0.379507 0.875223 0 +7418 0.369177 0.875833 0 +7419 0.358943 0.876371 0 +7420 0.348789 0.876758 0 +7421 0.338666 0.876895 0 +7422 0.328483 0.8768359999999999 0 +7423 0.31818 0.876632 0 +7424 0.307774 0.876745 0 +7425 0.297636 0.878118 0 +7426 0.287991 0.879125 0 +7427 0.278364 0.879459 0 +7428 0.268791 0.879573 0 +7429 0.259133 0.879579 0 +7430 0.249395 0.879567 0 +7431 0.239574 0.879547 0 +7432 0.229704 0.879522 0 +7433 0.219792 0.879532 0 +7434 0.209849 0.879576 0 +7435 0.199888 0.879633 0 +7436 0.189914 0.879697 0 +7437 0.179933 0.879761 0 +7438 0.169948 0.879822 0 +7439 0.15996 0.879873 0 +7440 0.14997 0.879915 0 +7441 0.139979 0.879946 0 +7442 0.129987 0.879969 0 +7443 0.133086 0.62967 0 +7444 0.141556 0.6346079999999999 0 +7445 0.149266 0.64311 0 +7446 0.152079 0.6759309999999999 0 +7447 0.151516 0.6657960000000001 0 +7448 0.152641 0.68592 0 +7449 0.153657 0.695835 0 +7450 0.155378 0.705852 0 +7451 0.168601 0.7126749999999999 0 +7452 0.157683 0.7163079999999999 0 +7453 0.774195 0.757451 0 +7454 0.7876379999999999 0.748234 0 +7455 0.784961 0.759339 0 +7456 0.78898 0.73729 0 +7457 0.789323 0.726618 0 +7458 0.442159 0.120638 0 +7459 0.448186 0.119676 0 +7460 0.434044 0.12224 0 +7461 0.424742 0.124276 0 +7462 0.413974 0.127029 0 +7463 0.409283 0.134359 0 +7464 0.401947 0.134767 0 +7465 0.392646 0.135614 0 +7466 0.381437 0.137153 0 +7467 0.20567 0.267581 0 +7468 0.196288 0.270502 0 +7469 0.18647 0.273636 0 +7470 0.176426 0.277267 0 +7471 0.166411 0.281604 0 +7472 0.156042 0.285872 0 +7473 0.143345 0.290956 0 +7474 0.136963 0.300736 0 +7475 0.133337 0.306232 0 +7476 0.1272 0.306181 0 +7477 0.118923 0.306613 0 +7478 0.119537 0.297783 0 +7479 0.120375 0.28847 0 +7480 0.120783 0.278699 0 +7481 0.120471 0.268899 0 +7482 0.120117 0.259083 0 +7483 0.119983 0.249275 0 +7484 0.120043 0.239458 0 +7485 0.120148 0.229614 0 +7486 0.120292 0.21974 0 +7487 0.120429 0.209831 0 +7488 0.120505 0.199889 0 +7489 0.120495 0.189925 0 +7490 0.120452 0.179945 0 +7491 0.120372 0.169962 0 +7492 0.120284 0.159973 0 +7493 0.120199 0.149981 0 +7494 0.120132 0.139986 0 +7495 0.12008 0.12999 0 +7496 0.120044 0.119994 0 +7497 0.115475 0.534921 0 +7498 0.117869 0.543834 0 +7499 0.112642 0.529044 0 +7500 0.8799630000000001 0.12 0 +7501 0.879957 0.130001 0 +7502 0.879956 0.140001 0 +7503 0.87996 0.150001 0 +7504 0.8799670000000001 0.160001 0 +7505 0.879905 0.169985 0 +7506 0.879838 0.179961 0 +7507 0.879713 0.189941 0 +7508 0.879607 0.199916 0 +7509 0.879456 0.209909 0 +7510 0.879233 0.219924 0 +7511 0.878924 0.229961 0 +7512 0.878638 0.240101 0 +7513 0.8783609999999999 0.250294 0 +7514 0.878279 0.260533 0 +7515 0.878748 0.27104 0 +7516 0.881046 0.280843 0 +7517 0.882864 0.289532 0 +7518 0.883481 0.29729 0 +7519 0.881517 0.305057 0 +7520 0.8784650000000001 0.314067 0 +7521 0.876953 0.324144 0 +7522 0.875933 0.334413 0 +7523 0.8750869999999999 0.34466 0 +7524 0.873872 0.354894 0 +7525 0.872116 0.365264 0 +7526 0.136803 0.411986 0 +7527 0.126601 0.419118 0 +7528 0.121754 0.431814 0 +7529 0.122076 0.529506 0 +7530 0.126183 0.538928 0 +7531 0.115744 0.523223 0 +7532 0.6137550000000001 0.120696 0 +7533 0.606764 0.120621 0 +7534 0.622497 0.121822 0 +7535 0.119238 0.513966 0 +7536 0.121071 0.502251 0 +7537 0.121989 0.490546 0 +7538 0.881296 0.612829 0 +7539 0.879304 0.622689 0 +7540 0.878976 0.633522 0 +7541 0.879676 0.643695 0 +7542 0.881081 0.653375 0 +7543 0.881895 0.662867 0 +7544 0.8822140000000001 0.672441 0 +7545 0.882274 0.6820929999999999 0 +7546 0.882242 0.691771 0 +7547 0.882152 0.701471 0 +7548 0.881975 0.711181 0 +7549 0.881647 0.720902 0 +7550 0.881192 0.730646 0 +7551 0.880763 0.740439 0 +7552 0.880636 0.750282 0 +7553 0.880617 0.760152 0 +7554 0.880552 0.769979 0 +7555 0.880323 0.779843 0 +7556 0.880019 0.789675 0 +7557 0.879687 0.799524 0 +7558 0.8794110000000001 0.8094170000000001 0 +7559 0.879216 0.819372 0 +7560 0.879156 0.829376 0 +7561 0.879177 0.839407 0 +7562 0.87927 0.849454 0 +7563 0.8794110000000001 0.859521 0 +7564 0.879568 0.8696159999999999 0 +7565 0.118712 0.441158 0 +7566 0.124399 0.407245 0 +7567 0.125505 0.397246 0 +7568 0.130044 0.119994 0 +7569 0.140044 0.119985 0 +7570 0.150043 0.119981 0 +7571 0.160037 0.119984 0 +7572 0.169987 0.120011 0 +7573 0.179939 0.120024 0 +7574 0.189866 0.120108 0 +7575 0.199791 0.120329 0 +7576 0.209758 0.120743 0 +7577 0.219779 0.121398 0 +7578 0.229872 0.122282 0 +7579 0.240086 0.123253 0 +7580 0.250461 0.124032 0 +7581 0.260976 0.124502 0 +7582 0.271553 0.124526 0 +7583 0.282093 0.124629 0 +7584 0.292549 0.124636 0 +7585 0.302843 0.12405 0 +7586 0.312927 0.123204 0 +7587 0.322756 0.122347 0 +7588 0.33242 0.121809 0 +7589 0.341885 0.121972 0 +7590 0.351765 0.122881 0 +7591 0.361806 0.122832 0 +7592 0.37168 0.123282 0 +7593 0.381906 0.124593 0 +7594 0.392281 0.124764 0 +7595 0.402582 0.125067 0 +7596 0.709378 0.119375 0 +7597 0.719646 0.118715 0 +7598 0.729649 0.118286 0 +7599 0.739385 0.118341 0 +7600 0.749067 0.119056 0 +7601 0.759023 0.119349 0 +7602 0.769113 0.11946 0 +7603 0.7792249999999999 0.119566 0 +7604 0.789336 0.119672 0 +7605 0.79945 0.119777 0 +7606 0.809553 0.119825 0 +7607 0.819645 0.119876 0 +7608 0.829723 0.119909 0 +7609 0.83979 0.119942 0 +7610 0.849845 0.119969 0 +7611 0.859889 0.119986 0 +7612 0.86993 0.119996 0 +7613 0.256523 0.210978 0 +7614 0.247634 0.212478 0 +7615 0.238435 0.214049 0 +7616 0.228916 0.215437 0 +7617 0.219247 0.21669 0 +7618 0.209584 0.217868 0 +7619 0.200024 0.228891 0 +7620 0.1998 0.218919 0 +7621 0.200424 0.238815 0 +7622 0.20125 0.24862 0 +7623 0.203043 0.258266 0 +7624 0.362123 0.132988 0 +7625 0.371326 0.132843 0 +7626 0.351353 0.135033 0 +7627 0.344531 0.143037 0 +7628 0.337096 0.147419 0 +7629 0.328531 0.150819 0 +7630 0.319337 0.153598 0 +7631 0.309901 0.156471 0 +7632 0.300378 0.159704 0 +7633 0.29185 0.163473 0 +7634 0.282913 0.164004 0 +7635 0.274115 0.163603 0 +7636 0.265693 0.162766 0 +7637 0.25553 0.170686 0 +7638 0.257205 0.160067 0 +7639 0.25494 0.181026 0 +7640 0.255019 0.19124 0 +7641 0.255548 0.201251 0 +7642 0.799135 0.72576 0 +7643 0.809046 0.723723 0 +7644 0.818643 0.721083 0 +7645 0.8279609999999999 0.718047 0 +7646 0.836907 0.715286 0 +7647 0.845603 0.713193 0 +7648 0.854391 0.712284 0 +7649 0.863555 0.702272 0 +7650 0.863418 0.71177 0 +7651 0.863649 0.692703 0 +7652 0.863809 0.683092 0 +7653 0.867846 0.63537 0 +7654 0.869387 0.646085 0 +7655 0.8667820000000001 0.621963 0 +7656 0.637275 0.870212 0 +7657 0.644221 0.865022 0 +7658 0.652502 0.860366 0 +7659 0.661566 0.855413 0 +7660 0.669739 0.849131 0 +7661 0.677964 0.843149 0 +7662 0.687181 0.835929 0 +7663 0.698221 0.833592 0 +7664 0.707523 0.831643 0 +7665 0.716658 0.829776 0 +7666 0.725804 0.827771 0 +7667 0.734915 0.8252620000000001 0 +7668 0.743808 0.821608 0 +7669 0.752494 0.817245 0 +7670 0.758425 0.802753 0 +7671 0.761468 0.8127529999999999 0 +7672 0.753955 0.792531 0 +7673 0.765439 0.783467 0 +7674 0.7704299999999999 0.768877 0 +7675 0.272553 0.837682 0 +7676 0.28138 0.844097 0 +7677 0.28641 0.847691 0 +7678 0.286019 0.853519 0 +7679 0.286248 0.861158 0 +7680 0.296389 0.868343 0 +7681 0.287146 0.869673 0 +7682 0.87356 0.301492 0 +7683 0.8688439999999999 0.294737 0 +7684 0.872018 0.283309 0 +7685 0.875252 0.290871 0 +7686 0.86605 0.273004 0 +7687 0.853887 0.268397 0 +7688 0.843851 0.264625 0 +7689 0.834582 0.260947 0 +7690 0.825464 0.256837 0 +7691 0.815916 0.253274 0 +7692 0.806026 0.250689 0 +7693 0.797134 0.249636 0 +7694 0.789045 0.246675 0 +7695 0.780726 0.24312 0 +7696 0.77228 0.239055 0 +7697 0.741553 0.204719 0 +7698 0.736076 0.195841 0 +7699 0.730986 0.187629 0 +7700 0.72623 0.18004 0 +7701 0.7222730000000001 0.173134 0 +7702 0.720221 0.16548 0 +7703 0.718119 0.156969 0 +7704 0.7155860000000001 0.148074 0 +7705 0.71292 0.13895 0 +7706 0.710741 0.129462 0 +7707 0.581797 0.867449 0 +7708 0.869915 0.129994 0 +7709 0.869904 0.139991 0 +7710 0.869908 0.149987 0 +7711 0.8698399999999999 0.159963 0 +7712 0.869766 0.169936 0 +7713 0.86963 0.179895 0 +7714 0.869493 0.189831 0 +7715 0.869377 0.199765 0 +7716 0.869239 0.209679 0 +7717 0.868928 0.219609 0 +7718 0.8685079999999999 0.2296 0 +7719 0.8681449999999999 0.239664 0 +7720 0.8678439999999999 0.249858 0 +7721 0.867153 0.26038 0 +7722 0.776542 0.230903 0 +7723 0.773028 0.218654 0 +7724 0.781303 0.223223 0 +7725 0.765501 0.213186 0 +7726 0.757566 0.206524 0 +7727 0.750789 0.198305 0 +7728 0.744698 0.190041 0 +7729 0.738991 0.182129 0 +7730 0.73341 0.175051 0 +7731 0.728253 0.170729 0 +7732 0.72877 0.164074 0 +7733 0.727448 0.155359 0 +7734 0.725163 0.146284 0 +7735 0.72257 0.137426 0 +7736 0.72078 0.128255 0 +7737 0.277943 0.869958 0 +7738 0.268663 0.86972 0 +7739 0.259103 0.869524 0 +7740 0.249367 0.8694539999999999 0 +7741 0.239553 0.86943 0 +7742 0.229672 0.8694499999999999 0 +7743 0.219751 0.8695040000000001 0 +7744 0.209806 0.869579 0 +7745 0.199843 0.869671 0 +7746 0.189875 0.8697510000000001 0 +7747 0.179899 0.869812 0 +7748 0.169918 0.869857 0 +7749 0.159935 0.869893 0 +7750 0.14995 0.869922 0 +7751 0.139966 0.8699480000000001 0 +7752 0.12998 0.869969 0 +7753 0.129972 0.859972 0 +7754 0.129957 0.849979 0 +7755 0.129957 0.8399990000000001 0 +7756 0.130021 0.830025 0 +7757 0.130158 0.82006 0 +7758 0.130399 0.810099 0 +7759 0.130799 0.800133 0 +7760 0.131256 0.790121 0 +7761 0.131716 0.780084 0 +7762 0.132214 0.76999 0 +7763 0.132849 0.7598279999999999 0 +7764 0.13366 0.749569 0 +7765 0.134653 0.739241 0 +7766 0.135115 0.728792 0 +7767 0.134964 0.71832 0 +7768 0.134118 0.707931 0 +7769 0.133237 0.6976560000000001 0 +7770 0.132504 0.687484 0 +7771 0.13188 0.677366 0 +7772 0.13128 0.667307 0 +7773 0.130657 0.657348 0 +7774 0.130059 0.647701 0 +7775 0.130011 0.638683 0 +7776 0.17313 0.72196 0 +7777 0.179565 0.730131 0 +7778 0.782083 0.770885 0 +7779 0.795907 0.761081 0 +7780 0.7931550000000001 0.7726 0 +7781 0.798699 0.748898 0 +7782 0.799325 0.7368 0 +7783 0.869433 0.869378 0 +7784 0.859283 0.869057 0 +7785 0.849137 0.868665 0 +7786 0.838978 0.868197 0 +7787 0.828853 0.867726 0 +7788 0.818789 0.867382 0 +7789 0.808792 0.867277 0 +7790 0.798874 0.8674269999999999 0 +7791 0.789036 0.867766 0 +7792 0.77924 0.868054 0 +7793 0.769473 0.868132 0 +7794 0.759703 0.867772 0 +7795 0.749816 0.867441 0 +7796 0.73976 0.867515 0 +7797 0.729622 0.867977 0 +7798 0.719468 0.868337 0 +7799 0.709259 0.86839 0 +7800 0.698949 0.868314 0 +7801 0.688889 0.8691140000000001 0 +7802 0.679494 0.869283 0 +7803 0.668597 0.865922 0 +7804 0.65717 0.869533 0 +7805 0.648418 0.8723649999999999 0 +7806 0.872964 0.610864 0 +7807 0.872163 0.654909 0 +7808 0.872918 0.663764 0 +7809 0.873054 0.673096 0 +7810 0.87302 0.682625 0 +7811 0.872939 0.692236 0 +7812 0.872831 0.701859 0 +7813 0.872619 0.711479 0 +7814 0.872238 0.721095 0 +7815 0.871583 0.73073 0 +7816 0.871004 0.740453 0 +7817 0.870811 0.750293 0 +7818 0.870949 0.760057 0 +7819 0.870887 0.769823 0 +7820 0.870582 0.779537 0 +7821 0.870132 0.789258 0 +7822 0.869726 0.799051 0 +7823 0.869322 0.808934 0 +7824 0.869081 0.818889 0 +7825 0.868949 0.828915 0 +7826 0.868961 0.838979 0 +7827 0.869063 0.849077 0 +7828 0.869232 0.859201 0 +7829 0.730367 0.12747 0 +7830 0.739417 0.12733 0 +7831 0.748351 0.128925 0 +7832 0.758435 0.129252 0 +7833 0.7686770000000001 0.129282 0 +7834 0.778887 0.129395 0 +7835 0.789077 0.129587 0 +7836 0.799234 0.129695 0 +7837 0.809374 0.129756 0 +7838 0.819499 0.129794 0 +7839 0.829609 0.129846 0 +7840 0.839703 0.129894 0 +7841 0.849786 0.129941 0 +7842 0.859854 0.129973 0 +7843 0.132228 0.405762 0 +7844 0.135358 0.398436 0 +7845 0.128593 0.2984 0 +7846 0.130836 0.288976 0 +7847 0.131073 0.278687 0 +7848 0.130578 0.2687 0 +7849 0.129979 0.258869 0 +7850 0.129847 0.249142 0 +7851 0.129937 0.2394 0 +7852 0.130125 0.229618 0 +7853 0.130313 0.219765 0 +7854 0.13046 0.209858 0 +7855 0.130494 0.199913 0 +7856 0.130512 0.189939 0 +7857 0.130468 0.179962 0 +7858 0.13038 0.169973 0 +7859 0.130294 0.159981 0 +7860 0.130209 0.149985 0 +7861 0.13014 0.139986 0 +7862 0.130086 0.129987 0 +7863 0.87741 0.296477 0 +7864 0.140088 0.129984 0 +7865 0.150082 0.129991 0 +7866 0.160037 0.130021 0 +7867 0.169968 0.130019 0 +7868 0.179844 0.130038 0 +7869 0.189692 0.130145 0 +7870 0.199551 0.130403 0 +7871 0.209439 0.130907 0 +7872 0.219374 0.13172 0 +7873 0.22942 0.132894 0 +7874 0.239651 0.134236 0 +7875 0.250196 0.135296 0 +7876 0.261065 0.135838 0 +7877 0.271963 0.135457 0 +7878 0.282739 0.13553 0 +7879 0.29351 0.135778 0 +7880 0.304077 0.134837 0 +7881 0.31417 0.133504 0 +7882 0.323789 0.132177 0 +7883 0.332894 0.131234 0 +7884 0.34158 0.131271 0 +7885 0.246567 0.202231 0 +7886 0.237405 0.20357 0 +7887 0.228077 0.205182 0 +7888 0.218678 0.206652 0 +7889 0.209111 0.207886 0 +7890 0.199514 0.208898 0 +7891 0.189908 0.219787 0 +7892 0.189803 0.209678 0 +7893 0.19006 0.229973 0 +7894 0.190385 0.240246 0 +7895 0.191265 0.25054 0 +7896 0.193389 0.260664 0 +7897 0.6755949999999999 0.856948 0 +7898 0.683451 0.851718 0 +7899 0.692342 0.846847 0 +7900 0.70069 0.842587 0 +7901 0.70927 0.840707 0 +7902 0.718341 0.839131 0 +7903 0.727707 0.83741 0 +7904 0.737237 0.835013 0 +7905 0.74683 0.8316210000000001 0 +7906 0.75547 0.826641 0 +7907 0.764271 0.822662 0 +7908 0.771034 0.809322 0 +7909 0.773309 0.819439 0 +7910 0.768632 0.797918 0 +7911 0.81012 0.735206 0 +7912 0.82052 0.731352 0 +7913 0.830043 0.727579 0 +7914 0.838633 0.724235 0 +7915 0.846159 0.721773 0 +7916 0.854254 0.721381 0 +7917 0.8630139999999999 0.721284 0 +7918 0.779606 0.783287 0 +7919 0.79103 0.783992 0 +7920 0.803648 0.7747849999999999 0 +7921 0.801545 0.7860510000000001 0 +7922 0.806884 0.763312 0 +7923 0.812064 0.749291 0 +7924 0.136918 0.640131 0 +7925 0.139948 0.859952 0 +7926 0.139928 0.84997 0 +7927 0.139949 0.840004 0 +7928 0.140025 0.8300689999999999 0 +7929 0.140228 0.820143 0 +7930 0.140597 0.810212 0 +7931 0.14112 0.800267 0 +7932 0.141774 0.790277 0 +7933 0.142255 0.780258 0 +7934 0.142735 0.7702 0 +7935 0.143337 0.760046 0 +7936 0.144263 0.749799 0 +7937 0.145472 0.739496 0 +7938 0.146822 0.728585 0 +7939 0.146046 0.7175859999999999 0 +7940 0.144785 0.707081 0 +7941 0.143592 0.696878 0 +7942 0.142654 0.686759 0 +7943 0.141986 0.6766760000000001 0 +7944 0.141356 0.6666 0 +7945 0.140463 0.656593 0 +7946 0.139157 0.647122 0 +7947 0.856213 0.258197 0 +7948 0.846459 0.255637 0 +7949 0.837587 0.252718 0 +7950 0.829346 0.247816 0 +7951 0.8190539999999999 0.243649 0 +7952 0.807209 0.239764 0 +7953 0.799131 0.242845 0 +7954 0.792841 0.239268 0 +7955 0.785035 0.23523 0 +7956 0.15071 0.65529 0 +7957 0.789801 0.227701 0 +7958 0.785905 0.215751 0 +7959 0.7945449999999999 0.219787 0 +7960 0.778455 0.211947 0 +7961 0.772336 0.206277 0 +7962 0.76581 0.199486 0 +7963 0.759289 0.191865 0 +7964 0.752966 0.183946 0 +7965 0.746855 0.175696 0 +7966 0.73959 0.166125 0 +7967 0.737636 0.154224 0 +7968 0.735123 0.144252 0 +7969 0.7317360000000001 0.135986 0 +7970 0.160988 0.728525 0 +7971 0.277869 0.860757 0 +7972 0.26884 0.859924 0 +7973 0.25918 0.8594039999999999 0 +7974 0.249405 0.859325 0 +7975 0.23954 0.859343 0 +7976 0.22962 0.859436 0 +7977 0.219683 0.859552 0 +7978 0.20973 0.859695 0 +7979 0.199779 0.859808 0 +7980 0.189819 0.859891 0 +7981 0.179856 0.859931 0 +7982 0.169884 0.859952 0 +7983 0.159906 0.859944 0 +7984 0.149925 0.859943 0 +7985 0.149912 0.84998 0 +7986 0.149935 0.840074 0 +7987 0.150048 0.830188 0 +7988 0.150308 0.820296 0 +7989 0.150778 0.810403 0 +7990 0.151543 0.800451 0 +7991 0.152394 0.790471 0 +7992 0.152869 0.780446 0 +7993 0.153189 0.77042 0 +7994 0.153608 0.760436 0 +7995 0.154547 0.750571 0 +7996 0.156449 0.740455 0 +7997 0.249502 0.8490760000000001 0 +7998 0.259614 0.849113 0 +7999 0.239477 0.8492690000000001 0 +8000 0.229509 0.849485 0 +8001 0.219561 0.849697 0 +8002 0.209625 0.849889 0 +8003 0.199691 0.85005 0 +8004 0.189766 0.8501339999999999 0 +8005 0.179824 0.850148 0 +8006 0.169862 0.850113 0 +8007 0.159895 0.850052 0 +8008 0.171114 0.735962 0 +8009 0.177273 0.742361 0 +8010 0.180619 0.74999 0 +8011 0.192473 0.755926 0 +8012 0.182657 0.758684 0 +8013 0.194257 0.765706 0 +8014 0.183874 0.7679820000000001 0 +8015 0.185015 0.777492 0 +8016 0.186476 0.786947 0 +8017 0.14217 0.278333 0 +8018 0.140691 0.267975 0 +8019 0.139722 0.258337 0 +8020 0.139577 0.248972 0 +8021 0.139808 0.239437 0 +8022 0.140065 0.229713 0 +8023 0.14028 0.219868 0 +8024 0.14039 0.209944 0 +8025 0.140449 0.199972 0 +8026 0.140462 0.189992 0 +8027 0.1404 0.179999 0 +8028 0.140341 0.170002 0 +8029 0.140257 0.160001 0 +8030 0.140195 0.149999 0 +8031 0.140137 0.139994 0 +8032 0.150114 0.140017 0 +8033 0.160041 0.140022 0 +8034 0.1699 0.140024 0 +8035 0.179697 0.140046 0 +8036 0.189459 0.140149 0 +8037 0.199196 0.14042 0 +8038 0.208928 0.140932 0 +8039 0.218703 0.141885 0 +8040 0.22857 0.143449 0 +8041 0.23868 0.145364 0 +8042 0.249289 0.146817 0 +8043 0.261309 0.148726 0 +8044 0.272701 0.146042 0 +8045 0.283168 0.146128 0 +8046 0.294803 0.148479 0 +8047 0.306185 0.145889 0 +8048 0.316233 0.143702 0 +8049 0.325535 0.141599 0 +8050 0.333738 0.139636 0 +8051 0.339978 0.13794 0 +8052 0.862263 0.730625 0 +8053 0.860835 0.740344 0 +8054 0.86107 0.7503840000000001 0 +8055 0.861478 0.760015 0 +8056 0.861468 0.769566 0 +8057 0.861007 0.779066 0 +8058 0.860436 0.7886570000000001 0 +8059 0.859804 0.798378 0 +8060 0.859297 0.80823 0 +8061 0.858909 0.818196 0 +8062 0.858715 0.828258 0 +8063 0.85869 0.838387 0 +8064 0.85882 0.848577 0 +8065 0.859039 0.858797 0 +8066 0.848811 0.858301 0 +8067 0.8385899999999999 0.857711 0 +8068 0.828434 0.857142 0 +8069 0.818287 0.856673 0 +8070 0.808247 0.856523 0 +8071 0.798361 0.856899 0 +8072 0.788585 0.857424 0 +8073 0.7789430000000001 0.857948 0 +8074 0.769401 0.858117 0 +8075 0.759922 0.85762 0 +8076 0.750018 0.856433 0 +8077 0.739644 0.856867 0 +8078 0.729495 0.857647 0 +8079 0.719425 0.858256 0 +8080 0.709414 0.858298 0 +8081 0.698288 0.8566859999999999 0 +8082 0.687918 0.859894 0 +8083 0.680983 0.862044 0 +8084 0.739128 0.134509 0 +8085 0.745854 0.139808 0 +8086 0.757902 0.139403 0 +8087 0.768436 0.139029 0 +8088 0.778683 0.139179 0 +8089 0.788829 0.139529 0 +8090 0.798987 0.139639 0 +8091 0.809158 0.139666 0 +8092 0.819319 0.139699 0 +8093 0.829461 0.139763 0 +8094 0.839587 0.139841 0 +8095 0.84971 0.139903 0 +8096 0.859827 0.139958 0 +8097 0.859769 0.149929 0 +8098 0.859687 0.159902 0 +8099 0.85955 0.169849 0 +8100 0.85939 0.179773 0 +8101 0.859222 0.189677 0 +8102 0.859119 0.199522 0 +8103 0.859056 0.209314 0 +8104 0.858635 0.219104 0 +8105 0.858056 0.228938 0 +8106 0.857754 0.238723 0 +8107 0.857508 0.248456 0 +8108 0.864059 0.673468 0 +8109 0.864469 0.6643790000000001 0 +8110 0.864971 0.656845 0 +8111 0.823922 0.741662 0 +8112 0.83335 0.736724 0 +8113 0.841656 0.7323769999999999 0 +8114 0.847071 0.728096 0 +8115 0.8534929999999999 0.7299870000000001 0 +8116 0.779816 0.796083 0 +8117 0.790368 0.79575 0 +8118 0.800322 0.796976 0 +8119 0.811322 0.7885799999999999 0 +8120 0.80992 0.799405 0 +8121 0.813567 0.778165 0 +8122 0.816769 0.767857 0 +8123 0.821835 0.757835 0 +8124 0.8294589999999999 0.75026 0 +8125 0.8383350000000001 0.7450329999999999 0 +8126 0.849042 0.7398130000000001 0 +8127 0.703146 0.849596 0 +8128 0.710441 0.849312 0 +8129 0.719377 0.848533 0 +8130 0.728985 0.847352 0 +8131 0.7393150000000001 0.845761 0 +8132 0.750972 0.843427 0 +8133 0.7589050000000001 0.835404 0 +8134 0.767035 0.83185 0 +8135 0.775718 0.829161 0 +8136 0.782644 0.81731 0 +8137 0.784967 0.826911 0 +8138 0.78093 0.807169 0 +8139 0.798353 0.232632 0 +8140 0.803306 0.224325 0 +8141 0.798261 0.211395 0 +8142 0.807576 0.215444 0 +8143 0.789385 0.207987 0 +8144 0.782462 0.206907 0 +8145 0.779544 0.200785 0 +8146 0.77407 0.193525 0 +8147 0.767844 0.185942 0 +8148 0.761451 0.178466 0 +8149 0.755588 0.170718 0 +8150 0.75116 0.161685 0 +8151 0.748342 0.151359 0 +8152 0.245845 0.191778 0 +8153 0.236553 0.193221 0 +8154 0.227344 0.195013 0 +8155 0.218012 0.196708 0 +8156 0.20862 0.197974 0 +8157 0.199147 0.198913 0 +8158 0.189548 0.19958 0 +8159 0.179939 0.210162 0 +8160 0.179861 0.200015 0 +8161 0.179972 0.220408 0 +8162 0.179991 0.230835 0 +8163 0.180134 0.24135 0 +8164 0.180749 0.252539 0 +8165 0.183286 0.263343 0 +8166 0.289706 0.155737 0 +8167 0.282466 0.155259 0 +8168 0.274167 0.155013 0 +8169 0.266934 0.155271 0 +8170 0.24717 0.158295 0 +8171 0.245436 0.16974 0 +8172 0.245416 0.181269 0 +8173 0.260056 0.838154 0 +8174 0.159921 0.840206 0 +8175 0.160059 0.830369 0 +8176 0.160348 0.8205480000000001 0 +8177 0.160917 0.8106950000000001 0 +8178 0.161942 0.800767 0 +8179 0.16321 0.790644 0 +8180 0.163494 0.780409 0 +8181 0.163503 0.770437 0 +8182 0.16353 0.760825 0 +8183 0.164062 0.751709 0 +8184 0.16567 0.743301 0 +8185 0.152983 0.275518 0 +8186 0.15051 0.265969 0 +8187 0.148662 0.257554 0 +8188 0.14901 0.249051 0 +8189 0.149622 0.239749 0 +8190 0.149962 0.230022 0 +8191 0.150172 0.220098 0 +8192 0.150272 0.210094 0 +8193 0.150315 0.200074 0 +8194 0.1503 0.190057 0 +8195 0.150258 0.180046 0 +8196 0.150214 0.170036 0 +8197 0.150163 0.160027 0 +8198 0.150132 0.150019 0 +8199 0.160009 0.15003 0 +8200 0.169804 0.150021 0 +8201 0.179525 0.150032 0 +8202 0.189176 0.150108 0 +8203 0.198734 0.150292 0 +8204 0.208243 0.150746 0 +8205 0.217715 0.151774 0 +8206 0.227023 0.153704 0 +8207 0.23683 0.156544 0 +8208 0.172829 0.266884 0 +8209 0.162927 0.271744 0 +8210 0.849612 0.149862 0 +8211 0.849486 0.159805 0 +8212 0.84933 0.169731 0 +8213 0.849114 0.179638 0 +8214 0.848876 0.189513 0 +8215 0.848841 0.199305 0 +8216 0.849055 0.208864 0 +8217 0.848487 0.218425 0 +8218 0.847706 0.228062 0 +8219 0.847269 0.237892 0 +8220 0.847943 0.246892 0 +8221 0.758968 0.149471 0 +8222 0.768746 0.148483 0 +8223 0.778569 0.148871 0 +8224 0.788503 0.14955 0 +8225 0.798682 0.149603 0 +8226 0.808905 0.149549 0 +8227 0.819107 0.14957 0 +8228 0.829279 0.149658 0 +8229 0.839445 0.149766 0 +8230 0.848529 0.847948 0 +8231 0.838283 0.847227 0 +8232 0.827974 0.846444 0 +8233 0.8177450000000001 0.845828 0 +8234 0.8076100000000001 0.845825 0 +8235 0.797662 0.846306 0 +8236 0.787954 0.847166 0 +8237 0.778538 0.848058 0 +8238 0.769517 0.848518 0 +8239 0.76079 0.847954 0 +8240 0.851152 0.750884 0 +8241 0.852445 0.760275 0 +8242 0.852407 0.76929 0 +8243 0.851708 0.778421 0 +8244 0.850832 0.787794 0 +8245 0.849998 0.797416 0 +8246 0.849265 0.807246 0 +8247 0.848755 0.81725 0 +8248 0.848428 0.82738 0 +8249 0.848414 0.837622 0 +8250 0.23562 0.182372 0 +8251 0.226294 0.185093 0 +8252 0.217297 0.186994 0 +8253 0.208029 0.188219 0 +8254 0.198694 0.189028 0 +8255 0.189257 0.189573 0 +8256 0.179664 0.189917 0 +8257 0.170006 0.200176 0 +8258 0.169921 0.190084 0 +8259 0.170036 0.210338 0 +8260 0.170001 0.220618 0 +8261 0.169802 0.230958 0 +8262 0.169376 0.241886 0 +8263 0.168164 0.254853 0 +8264 0.249441 0.838732 0 +8265 0.239305 0.8391999999999999 0 +8266 0.229313 0.839576 0 +8267 0.219385 0.839892 0 +8268 0.209489 0.840157 0 +8269 0.199606 0.840351 0 +8270 0.189725 0.840467 0 +8271 0.179824 0.840461 0 +8272 0.1699 0.840341 0 +8273 0.7906339999999999 0.806498 0 +8274 0.799658 0.80697 0 +8275 0.808391 0.810034 0 +8276 0.819541 0.801944 0 +8277 0.818294 0.812577 0 +8278 0.821013 0.791566 0 +8279 0.82289 0.7815299999999999 0 +8280 0.825682 0.772118 0 +8281 0.829532 0.763657 0 +8282 0.83466 0.75714 0 +8283 0.842072 0.753506 0 +8284 0.171782 0.745955 0 +8285 0.172403 0.752202 0 +8286 0.173112 0.76044 0 +8287 0.173743 0.769655 0 +8288 0.174417 0.7796729999999999 0 +8289 0.188904 0.795125 0 +8290 0.181656 0.796413 0 +8291 0.175444 0.790851 0 +8292 0.762952 0.841162 0 +8293 0.769417 0.840015 0 +8294 0.777666 0.838517 0 +8295 0.78684 0.837027 0 +8296 0.794546 0.825059 0 +8297 0.796489 0.83572 0 +8298 0.7915759999999999 0.815994 0 +8299 0.812842 0.229502 0 +8300 0.81714 0.219898 0 +8301 0.811412 0.206413 0 +8302 0.821087 0.210489 0 +8303 0.801547 0.202471 0 +8304 0.79016 0.197801 0 +8305 0.783147 0.188259 0 +8306 0.776629 0.179871 0 +8307 0.769374 0.173051 0 +8308 0.7638239999999999 0.166606 0 +8309 0.760782 0.158718 0 +8310 0.15941 0.262759 0 +8311 0.155453 0.256778 0 +8312 0.157936 0.250013 0 +8313 0.159192 0.240547 0 +8314 0.159811 0.230546 0 +8315 0.160034 0.220382 0 +8316 0.160123 0.210244 0 +8317 0.160137 0.200145 0 +8318 0.160102 0.190091 0 +8319 0.16004 0.180059 0 +8320 0.160003 0.170051 0 +8321 0.159981 0.160032 0 +8322 0.839291 0.159675 0 +8323 0.839095 0.16958 0 +8324 0.838796 0.17949 0 +8325 0.838456 0.18946 0 +8326 0.838552 0.199342 0 +8327 0.839618 0.208324 0 +8328 0.838607 0.217298 0 +8329 0.837111 0.226937 0 +8330 0.835491 0.238362 0 +8331 0.840297 0.245916 0 +8332 0.169727 0.160022 0 +8333 0.179376 0.160003 0 +8334 0.188887 0.15999 0 +8335 0.198274 0.160037 0 +8336 0.207486 0.160297 0 +8337 0.216373 0.161174 0 +8338 0.224875 0.163162 0 +8339 0.233681 0.16954 0 +8340 0.823443 0.233879 0 +8341 0.838043 0.8367250000000001 0 +8342 0.827702 0.8357520000000001 0 +8343 0.817372 0.834987 0 +8344 0.8067299999999999 0.834562 0 +8345 0.844272 0.761006 0 +8346 0.8439489999999999 0.768768 0 +8347 0.842724 0.777378 0 +8348 0.841432 0.786474 0 +8349 0.84029 0.79603 0 +8350 0.839341 0.805903 0 +8351 0.838629 0.816019 0 +8352 0.838181 0.826309 0 +8353 0.769364 0.157076 0 +8354 0.77783 0.158093 0 +8355 0.787873 0.159733 0 +8356 0.798461 0.159543 0 +8357 0.808659 0.159372 0 +8358 0.8188879999999999 0.159365 0 +8359 0.82909 0.159524 0 +8360 0.224556 0.17578 0 +8361 0.216168 0.177686 0 +8362 0.207366 0.178693 0 +8363 0.198257 0.179274 0 +8364 0.188936 0.179664 0 +8365 0.179433 0.179904 0 +8366 0.169784 0.180027 0 +8367 0.169705 0.170019 0 +8368 0.179307 0.169944 0 +8369 0.188773 0.169819 0 +8370 0.198035 0.169662 0 +8371 0.206996 0.169507 0 +8372 0.215195 0.169441 0 +8373 0.221692 0.169438 0 +8374 0.798822 0.814838 0 +8375 0.80518 0.821515 0 +8376 0.817173 0.82359 0 +8377 0.828545 0.814472 0 +8378 0.827832 0.825075 0 +8379 0.82948 0.804168 0 +8380 0.830688 0.794096 0 +8381 0.832205 0.784448 0 +8382 0.834221 0.7753679999999999 0 +8383 0.836389 0.767474 0 +8384 0.826745 0.22403 0 +8385 0.829538 0.215098 0 +8386 0.8269609999999999 0.200698 0 +8387 0.832006 0.208077 0 +8388 0.815436 0.197246 0 +8389 0.805749 0.193984 0 +8390 0.797446 0.189741 0 +8391 0.791816 0.182098 0 +8392 0.786126 0.171602 0 +8393 0.775655 0.166666 0 +8394 0.769614 0.16345 0 +8395 0.828856 0.169352 0 +8396 0.828537 0.179229 0 +8397 0.82797 0.189283 0 +8398 0.189516 0.803405 0 +8399 0.189668 0.812234 0 +8400 0.1897 0.821441 0 +8401 0.189707 0.83088 0 +8402 0.170017 0.830616 0 +8403 0.170279 0.820939 0 +8404 0.170854 0.811268 0 +8405 0.172106 0.8015949999999999 0 +8406 0.798571 0.169495 0 +8407 0.80879 0.16894 0 +8408 0.818751 0.169033 0 +8409 0.179894 0.830851 0 +8410 0.818647 0.178519 0 +8411 0.8176949999999999 0.187806 0 +8412 0.808781 0.186147 0 +8413 0.802211 0.184756 0 +8414 0.800408 0.178397 0 +8415 0.180889 0.803501 0 +8416 0.180362 0.812127 0 +8417 0.180061 0.821345 0 +8418 0.809138 0.177971 0 +8419 0.117003 0.449335 0 +8420 0.224977 0.323194 0 +8421 0.228585 0.315268 0 +8422 0.394924 0.805294 0 +8423 0.401003 0.8139 0 +8424 0.817159 0.456437 0 +8425 0.312259 0.824134 0 +8426 0.317959 0.831453 0 +8427 0.204794 0.763395 0 +8428 0.203294 0.7526119999999999 0 +8429 0.457152 0.119178 0 +8430 0.46269 0.112685 0 +8431 0.281134 0.222116 0 +8432 0.731162 0.791115 0 +8433 0.876302 0.6049330000000001 0 +8434 0.112382 0.6084310000000001 0 +8435 0.110049 0.55744 0 +8436 0.120226 0.554592 0 +8437 0.870494 0.514589 0 +8438 0.8809399999999999 0.51068 0 +8439 0.590425 0.863155 0 +8440 0.604963 0.127197 0 +8441 0.597351 0.123843 0 +8442 0.498209 0.887481 0 +8443 0.642347 0.874512 0 +8444 0.83844 0.7618740000000001 0 +8445 0.864625 0.504588 0 +8446 0.8716 0.503595 0 +8447 0.12312 0.449562 0 +8448 0.278725 0.8520450000000001 0 +8449 0.269732 0.849746 0 +$EndNodes +$Elements +1 8170 +0 2 3 8170 +1 7675 8449 7998 8173 +2 7676 8448 8449 7675 +3 7677 7678 8448 7676 +4 8449 7972 7973 7998 +5 8448 7971 7972 8449 +6 7678 7679 7971 8448 +7 7424 7304 7305 7423 +8 7424 7425 7680 7304 +9 6777 8419 8447 6775 +10 8447 7135 6774 6775 +11 8419 7565 7135 8447 +12 7445 7144 7145 7956 +13 7445 7142 7143 7144 +14 8437 8446 6705 8438 +15 7216 8445 8446 8437 +16 6701 6702 8445 7216 +17 8446 6378 6380 6705 +18 8445 6377 6378 8446 +19 6702 6376 6377 8445 +20 8436 7136 5975 5977 +21 5975 5505 5506 5977 +22 7530 7136 8436 7498 +23 8436 8435 7043 7498 +24 6771 5967 5968 7131 +25 6771 5965 5966 5967 +26 5946 7110 6673 5945 +27 5947 4965 4966 4967 +28 3985 3433 3434 3435 +29 3985 3986 4174 3984 +30 4039 3544 3545 3546 +31 4039 4295 4704 4038 +32 3995 3445 3446 3447 +33 3995 4264 4837 3994 +34 3406 2901 2902 2903 +35 3406 3407 3875 3405 +36 3827 3673 3674 3675 +37 3827 3828 3997 3826 +38 8361 8362 8371 8372 +39 8372 8373 8360 8361 +40 8418 8414 8406 8407 +41 8418 8412 8413 8414 +42 8444 8383 8281 8282 +43 8345 8346 8383 8444 +44 8283 8345 8444 8282 +45 8080 8081 8127 8128 +46 8128 8129 8079 8080 +47 7193 7195 7625 7466 +48 7537 7536 7047 7048 +49 6780 5972 5496 5497 +50 6781 6876 7530 7529 +51 6781 5499 5500 6876 +52 5972 6780 7537 6778 +53 7565 7528 7134 7135 +54 7844 6767 6768 7130 +55 7844 7567 7128 6767 +56 7128 7058 7059 7127 +57 7956 7145 7146 7447 +58 8443 7805 7372 7373 +59 7656 7657 7805 8443 +60 7374 7656 8443 7373 +61 7335 6707 6708 6709 +62 7335 7329 6911 6912 +63 6705 6704 6913 8438 +64 6971 7323 8442 6970 +65 8442 6303 6304 6970 +66 7323 6302 6303 8442 +67 7164 8441 7296 7163 +68 7533 8440 8441 7164 +69 7532 7293 8440 7533 +70 8441 6696 6698 7296 +71 8440 6695 6696 8441 +72 7293 6694 6695 8440 +73 7707 7244 8439 7247 +74 8439 6721 6723 7247 +75 7244 6720 6721 8439 +76 7331 8438 6913 6914 +77 7215 8437 8438 7331 +78 6372 6699 7216 8437 +79 6370 6372 8437 7215 +80 7348 7346 7347 7155 +81 7155 6503 6504 7348 +82 8435 6576 6577 7043 +83 8435 7041 6575 6576 +84 8435 8436 5977 7041 +85 7129 6769 6770 6771 +86 7112 7110 5946 6753 +87 5946 5947 5948 6753 +88 8434 7404 7036 7037 +89 7137 7138 7404 8434 +90 7038 7137 8434 7037 +91 8433 7806 6967 6968 +92 7410 7538 7806 8433 +93 6969 7410 8433 6968 +94 8108 6960 6961 8109 +95 6961 6962 8110 8109 +96 6959 6960 8108 7652 +97 8108 7809 7810 7652 +98 7332 6916 6917 7333 +99 6917 6918 7334 7333 +100 6915 6916 7332 7330 +101 7332 7213 7214 7330 +102 6876 6782 7136 7530 +103 7131 5968 5969 6773 +104 8432 6329 6331 6742 +105 6739 6330 6329 8432 +106 7267 6739 8432 6742 +107 6059 6058 7525 6905 +108 8431 6664 7098 6662 +109 5934 5935 6664 8431 +110 5933 5934 8431 6662 +111 6634 8430 6498 6499 +112 8430 8429 6875 6498 +113 8429 6637 7459 6875 +114 8430 6634 5905 5904 +115 8429 8430 5904 5906 +116 6637 8429 5906 5907 +117 6000 8428 6259 5999 +118 6145 8427 8428 6000 +119 6146 6165 8427 6145 +120 8428 8011 6877 6259 +121 8427 8013 8011 8428 +122 6165 6276 8013 8427 +123 6280 8426 6017 6019 +124 6278 8425 8426 6280 +125 6161 6016 8425 6278 +126 8426 5546 5547 6017 +127 8425 5545 5546 8426 +128 6016 5544 5545 8425 +129 8424 3865 3866 4739 +130 4737 3864 3865 8424 +131 4815 4737 8424 4739 +132 4014 4682 4012 3848 +133 4684 5018 4013 4015 +134 4681 6312 6047 4680 +135 8423 4919 4921 5558 +136 5172 8423 5558 5556 +137 4488 8422 8423 5172 +138 8422 4920 4919 8423 +139 3813 3814 4920 8422 +140 3812 3813 8422 4488 +141 4778 8421 4970 4968 +142 8421 8420 4332 4970 +143 8420 4317 4316 4332 +144 8421 4778 4062 4063 +145 8420 8421 4063 4064 +146 4317 8420 4064 4065 +147 4066 4071 4317 4065 +148 3815 3818 4920 3814 +149 8419 7052 7053 7565 +150 6777 7051 7052 8419 +151 6912 6706 6707 7335 +152 8288 8015 8016 8291 +153 8405 8291 8290 8415 +154 8404 8405 8415 8416 +155 8411 8412 8418 8410 +156 8408 8410 8418 8407 +157 8403 8404 8416 8417 +158 8402 8403 8417 8409 +159 8400 8401 8409 8417 +160 8399 8400 8417 8416 +161 8398 8399 8416 8415 +162 8289 8398 8415 8290 +163 8370 8371 8362 8363 +164 8391 8392 8406 8414 +165 8390 8391 8414 8413 +166 8389 8390 8413 8412 +167 8388 8389 8412 8411 +168 8369 8370 8363 8364 +169 8397 8386 8388 8411 +170 8396 8397 8411 8410 +171 8395 8396 8410 8408 +172 8368 8369 8364 8365 +173 8183 8184 8284 8285 +174 8285 8286 8182 8183 +175 8367 8368 8365 8366 +176 8181 8182 8286 8287 +177 8271 8272 8402 8409 +178 8270 8271 8409 8401 +179 8358 8359 8395 8408 +180 8357 8358 8408 8407 +181 8356 8357 8407 8406 +182 8355 8356 8406 8392 +183 8180 8181 8287 8288 +184 8179 8180 8288 8291 +185 8178 8179 8291 8405 +186 8177 8178 8405 8404 +187 8176 8177 8404 8403 +188 8175 8176 8403 8402 +189 8174 8175 8402 8272 +190 8354 8355 8392 8393 +191 6270 6271 8264 8265 +192 8265 8266 6269 6270 +193 8353 8354 8393 8394 +194 8267 6268 6269 8266 +195 6266 6268 8267 8268 +196 8296 8298 8374 8375 +197 8351 8352 8378 8377 +198 8350 8351 8377 8379 +199 6267 6266 8268 8269 +200 8349 8350 8379 8380 +201 6267 8269 8270 8401 +202 6265 6267 8401 8400 +203 6264 6265 8400 8399 +204 6263 6264 8399 8398 +205 6261 6263 8398 8289 +206 8348 8349 8380 8381 +207 8329 8330 8340 8384 +208 8384 8385 8328 8329 +209 8327 8328 8385 8387 +210 8326 8327 8387 8386 +211 8325 8326 8386 8397 +212 8324 8325 8397 8396 +213 8323 8324 8396 8395 +214 8322 8323 8395 8359 +215 8347 8348 8381 8382 +216 8308 8309 8353 8394 +217 8307 8308 8394 8393 +218 8306 8307 8393 8392 +219 8305 8306 8392 8391 +220 8304 8305 8391 8390 +221 8303 8304 8390 8389 +222 8301 8303 8389 8388 +223 8302 8301 8388 8386 +224 8302 8386 8387 8385 +225 8300 8302 8385 8384 +226 8299 8300 8384 8340 +227 8346 8347 8382 8383 +228 8344 8297 8296 8375 +229 8343 8344 8375 8376 +230 8342 8343 8376 8378 +231 8341 8342 8378 8352 +232 8280 8281 8383 8382 +233 8279 8280 8382 8381 +234 8278 8279 8381 8380 +235 8276 8278 8380 8379 +236 8277 8276 8379 8377 +237 8277 8377 8378 8376 +238 8275 8277 8376 8375 +239 8274 8275 8375 8374 +240 8273 8274 8374 8298 +241 8316 8317 8257 8259 +242 8259 8260 8315 8316 +243 8319 8320 8367 8366 +244 8314 8315 8260 8261 +245 8338 8339 8360 8373 +246 8337 8338 8373 8372 +247 8336 8337 8372 8371 +248 8335 8336 8371 8370 +249 8334 8335 8370 8369 +250 8333 8334 8369 8368 +251 8332 8333 8368 8367 +252 8321 8332 8367 8320 +253 8313 8314 8261 8262 +254 8258 8257 8317 8318 +255 8258 8318 8319 8366 +256 8256 8258 8366 8365 +257 8255 8256 8365 8364 +258 8254 8255 8364 8363 +259 8253 8254 8363 8362 +260 8252 8253 8362 8361 +261 8251 8252 8361 8360 +262 8250 8251 8360 8339 +263 8312 8313 8262 8263 +264 8310 8311 8312 8263 +265 8228 8229 8322 8359 +266 8227 8228 8359 8358 +267 8226 8227 8358 8357 +268 8225 8226 8357 8356 +269 8224 8225 8356 8355 +270 8223 8224 8355 8354 +271 8222 8223 8354 8353 +272 8221 8222 8353 8309 +273 8248 8249 8341 8352 +274 8247 8248 8352 8351 +275 8246 8247 8351 8350 +276 8245 8246 8350 8349 +277 8244 8245 8349 8348 +278 8243 8244 8348 8347 +279 8242 8243 8347 8346 +280 8241 8242 8346 8345 +281 8240 8241 8345 8283 +282 8171 8172 8250 8339 +283 8293 8238 8239 8292 +284 8237 8238 8293 8294 +285 8236 8237 8294 8295 +286 8235 8236 8295 8297 +287 8234 8235 8297 8344 +288 8233 8234 8344 8343 +289 8232 8233 8343 8342 +290 8231 8232 8342 8341 +291 8230 8231 8341 8249 +292 8208 8209 8310 8263 +293 7951 7952 8299 8340 +294 7950 7951 8340 8330 +295 8207 8170 8171 8339 +296 8206 8207 8339 8338 +297 8205 8206 8338 8337 +298 8204 8205 8337 8336 +299 8203 8204 8336 8335 +300 8202 8203 8335 8334 +301 8201 8202 8334 8333 +302 8200 8201 8333 8332 +303 8199 8200 8332 8321 +304 7949 7950 8330 8331 +305 8220 7948 7949 8331 +306 8219 8220 8331 8330 +307 8218 8219 8330 8329 +308 8217 8218 8329 8328 +309 8216 8217 8328 8327 +310 8215 8216 8327 8326 +311 8214 8215 8326 8325 +312 8213 8214 8325 8324 +313 8212 8213 8324 8323 +314 8211 8212 8323 8322 +315 8210 8211 8322 8229 +316 8197 8198 8199 8321 +317 8196 8197 8321 8320 +318 8195 8196 8320 8319 +319 8194 8195 8319 8318 +320 8193 8194 8318 8317 +321 8192 8193 8317 8316 +322 8191 8192 8316 8315 +323 8190 8191 8315 8314 +324 8189 8190 8314 8313 +325 8188 8189 8313 8312 +326 8187 8188 8312 8311 +327 8186 8187 8311 8310 +328 8185 8186 8310 8209 +329 8150 8151 8221 8309 +330 8149 8150 8309 8308 +331 8148 8149 8308 8307 +332 8147 8148 8307 8306 +333 8146 8147 8306 8305 +334 8145 8146 8305 8304 +335 8144 8145 8304 8143 +336 8141 8143 8304 8303 +337 8142 8141 8303 8301 +338 8142 8301 8302 8300 +339 8140 8142 8300 8299 +340 8139 8140 8299 7952 +341 7954 8139 7952 7953 +342 8136 8138 8273 8298 +343 8137 8136 8298 8296 +344 8137 8296 8297 8295 +345 8135 8137 8295 8294 +346 8134 8135 8294 8293 +347 8133 8134 8293 8292 +348 8132 8133 8292 8239 +349 8016 6262 6261 8289 +350 8016 8289 8290 8291 +351 8014 8015 8288 8287 +352 8012 8014 8287 8286 +353 8010 8012 8286 8285 +354 8009 8010 8285 8284 +355 8008 8009 8284 8184 +356 6272 8173 8264 6271 +357 8125 8126 8240 8283 +358 8124 8125 8283 8282 +359 8123 8124 8282 8281 +360 8122 8123 8281 8280 +361 8121 8122 8280 8279 +362 8119 8121 8279 8278 +363 8120 8119 8278 8276 +364 8120 8276 8277 8275 +365 8118 8120 8275 8274 +366 8117 8118 8274 8273 +367 8116 8117 8273 8138 +368 8006 8007 8174 8272 +369 8005 8006 8272 8271 +370 8004 8005 8271 8270 +371 8003 8004 8270 8269 +372 8002 8003 8269 8268 +373 8001 8002 8268 8267 +374 8000 8001 8267 8266 +375 7999 8000 8266 8265 +376 7997 7999 8265 8264 +377 7998 7997 8264 8173 +378 8164 8165 8208 8263 +379 8163 8164 8263 8262 +380 8162 8163 8262 8261 +381 8161 8162 8261 8260 +382 8159 8161 8260 8259 +383 8160 8159 8259 8257 +384 8160 8257 8258 8256 +385 8158 8160 8256 8255 +386 8157 8158 8255 8254 +387 8156 8157 8254 8253 +388 8155 8156 8253 8252 +389 8154 8155 8252 8251 +390 8153 8154 8251 8250 +391 8152 8153 8250 8172 +392 8063 8064 8230 8249 +393 8062 8063 8249 8248 +394 8061 8062 8248 8247 +395 8060 8061 8247 8246 +396 8059 8060 8246 8245 +397 8058 8059 8245 8244 +398 8057 8058 8244 8243 +399 8056 8057 8243 8242 +400 8055 8056 8242 8241 +401 8054 8055 8241 8240 +402 8053 8054 8240 8126 +403 8078 8079 8129 8130 +404 8077 8078 8130 8131 +405 8076 8077 8131 8132 +406 8075 8076 8132 8239 +407 8074 8075 8239 8238 +408 8073 8074 8238 8237 +409 8072 8073 8237 8236 +410 8071 8072 8236 8235 +411 8070 8071 8235 8234 +412 8069 8070 8234 8233 +413 8068 8069 8233 8232 +414 8067 8068 8232 8231 +415 8066 8067 8231 8230 +416 8065 8066 8230 8064 +417 8094 8095 8210 8229 +418 8093 8094 8229 8228 +419 8092 8093 8228 8227 +420 8091 8092 8227 8226 +421 8090 8091 8226 8225 +422 8089 8090 8225 8224 +423 8088 8089 8224 8223 +424 8087 8088 8223 8222 +425 8086 8087 8222 8221 +426 8085 8086 8221 8151 +427 8107 7947 7948 8220 +428 8106 8107 8220 8219 +429 8105 8106 8219 8218 +430 8104 8105 8218 8217 +431 8103 8104 8217 8216 +432 8102 8103 8216 8215 +433 8101 8102 8215 8214 +434 8100 8101 8214 8213 +435 8099 8100 8213 8212 +436 8098 8099 8212 8211 +437 8097 8098 8211 8210 +438 8096 8097 8210 8095 +439 8045 8046 8166 8167 +440 8044 8045 8167 8168 +441 8043 8044 8168 8169 +442 7471 7472 8185 8209 +443 7470 7471 8209 8208 +444 7469 7470 8208 8165 +445 8041 8042 8170 8207 +446 8040 8041 8207 8206 +447 8039 8040 8206 8205 +448 8038 8039 8205 8204 +449 8037 8038 8204 8203 +450 8036 8037 8203 8202 +451 8035 8036 8202 8201 +452 8034 8035 8201 8200 +453 8033 8034 8200 8199 +454 8032 8033 8199 8198 +455 8030 8031 8032 8198 +456 8029 8030 8198 8197 +457 8028 8029 8197 8196 +458 8027 8028 8196 8195 +459 8026 8027 8195 8194 +460 8025 8026 8194 8193 +461 8024 8025 8193 8192 +462 8023 8024 8192 8191 +463 8022 8023 8191 8190 +464 8021 8022 8190 8189 +465 8020 8021 8189 8188 +466 8019 8020 8188 8187 +467 8018 8019 8187 8186 +468 8017 8018 8186 8185 +469 7473 8017 8185 7472 +470 7996 7970 8008 8184 +471 7995 7996 8184 8183 +472 7994 7995 8183 8182 +473 7993 7994 8182 8181 +474 7992 7993 8181 8180 +475 7991 7992 8180 8179 +476 7990 7991 8179 8178 +477 7989 7990 8178 8177 +478 7988 7989 8177 8176 +479 7987 7988 8176 8175 +480 7986 7987 8175 8174 +481 7985 7986 8174 8007 +482 6273 7675 8173 6272 +483 7639 7640 8152 8172 +484 7637 7639 8172 8171 +485 7638 7637 8171 8170 +486 7638 8170 8042 8043 +487 7636 7638 8043 8169 +488 7635 7636 8169 8168 +489 7634 7635 8168 8167 +490 7633 7634 8167 8166 +491 7632 7633 8166 8046 +492 7631 7632 8046 8047 +493 7630 7631 8047 8048 +494 7896 7468 7469 8165 +495 7895 7896 8165 8164 +496 7894 7895 8164 8163 +497 7893 7894 8163 8162 +498 7891 7893 8162 8161 +499 7892 7891 8161 8159 +500 7892 8159 8160 8158 +501 7890 7892 8158 8157 +502 7889 7890 8157 8156 +503 7888 7889 8156 8155 +504 7887 7888 8155 8154 +505 7886 7887 8154 8153 +506 7885 7886 8153 8152 +507 7641 7885 8152 7640 +508 7968 7969 8084 8085 +509 7967 7968 8085 8151 +510 7966 7967 8151 8150 +511 7965 7966 8150 8149 +512 7964 7965 8149 8148 +513 7963 7964 8148 8147 +514 7962 7963 8147 8146 +515 7961 7962 8146 8145 +516 7960 7961 8145 8144 +517 7958 7960 8144 8143 +518 7959 7958 8143 8141 +519 7959 8141 8142 8140 +520 7957 7959 8140 8139 +521 7955 7957 8139 7954 +522 7908 7910 8116 8138 +523 7909 7908 8138 8136 +524 7909 8136 8137 8135 +525 7907 7909 8135 8134 +526 7906 7907 8134 8133 +527 7905 7906 8133 8132 +528 7904 7905 8132 8131 +529 7903 7904 8131 8130 +530 7902 7903 8130 8129 +531 7901 7902 8129 8128 +532 7900 7901 8128 8127 +533 7899 7900 8127 8081 +534 7898 7899 8081 8082 +535 7897 7898 8082 8083 +536 7629 7630 8048 8049 +537 8115 8052 8053 8126 +538 8114 8115 8126 8113 +539 8112 8113 8126 8125 +540 8111 8112 8125 8124 +541 7923 8111 8124 8123 +542 7922 7923 8123 8122 +543 7920 7922 8122 8121 +544 7921 7920 8121 8119 +545 7921 8119 8120 8118 +546 7919 7921 8118 8117 +547 7918 7919 8117 8116 +548 7673 7918 8116 7910 +549 7916 7917 8052 8115 +550 7915 7916 8115 8114 +551 7914 7915 8114 8113 +552 7913 7914 8113 8112 +553 7912 7913 8112 8111 +554 7911 7912 8111 7923 +555 7807 7808 8109 8110 +556 7654 7807 8110 6962 +557 7809 8108 8109 7808 +558 7720 7721 7947 8107 +559 7719 7720 8107 8106 +560 7718 7719 8106 8105 +561 7717 7718 8105 8104 +562 7716 7717 8104 8103 +563 7715 7716 8103 8102 +564 7714 7715 8102 8101 +565 7713 7714 8101 8100 +566 7712 7713 8100 8099 +567 7711 7712 8099 8098 +568 7710 7711 8098 8097 +569 7709 7710 8097 8096 +570 7811 7651 7652 7810 +571 7842 7708 7709 8096 +572 7841 7842 8096 8095 +573 7840 7841 8095 8094 +574 7839 7840 8094 8093 +575 7838 7839 8093 8092 +576 7837 7838 8092 8091 +577 7836 7837 8091 8090 +578 7835 7836 8090 8089 +579 7834 7835 8089 8088 +580 7833 7834 8088 8087 +581 7832 7833 8087 8086 +582 7831 7832 8086 8085 +583 7830 7831 8085 8084 +584 7829 7830 8084 7969 +585 7812 7649 7651 7811 +586 7802 7803 7897 8083 +587 7801 7802 8083 8082 +588 7800 7801 8082 8081 +589 7799 7800 8081 8080 +590 7798 7799 8080 8079 +591 7797 7798 8079 8078 +592 7796 7797 8078 8077 +593 7795 7796 8077 8076 +594 7794 7795 8076 8075 +595 7793 7794 8075 8074 +596 7792 7793 8074 8073 +597 7791 7792 8073 8072 +598 7790 7791 8072 8071 +599 7789 7790 8071 8070 +600 7788 7789 8070 8069 +601 7787 7788 8069 8068 +602 7786 7787 8068 8067 +603 7785 7786 8067 8066 +604 7784 7785 8066 8065 +605 7650 7649 7812 7813 +606 7828 7783 7784 8065 +607 7827 7828 8065 8064 +608 7826 7827 8064 8063 +609 7825 7826 8063 8062 +610 7824 7825 8062 8061 +611 7823 7824 8061 8060 +612 7822 7823 8060 8059 +613 7821 7822 8059 8058 +614 7820 7821 8058 8057 +615 7819 7820 8057 8056 +616 7818 7819 8056 8055 +617 7817 7818 8055 8054 +618 7816 7817 8054 8053 +619 7815 7816 8053 8052 +620 7814 7815 8052 7917 +621 6967 7806 7655 6966 +622 7628 7629 8049 8050 +623 7627 7628 8050 8051 +624 7884 7626 7627 8051 +625 7883 7884 8051 8050 +626 7882 7883 8050 8049 +627 7881 7882 8049 8048 +628 7880 7881 8048 8047 +629 7879 7880 8047 8046 +630 7878 7879 8046 8045 +631 7877 7878 8045 8044 +632 7876 7877 8044 8043 +633 7875 7876 8043 8042 +634 7874 7875 8042 8041 +635 7873 7874 8041 8040 +636 7872 7873 8040 8039 +637 7871 7872 8039 8038 +638 7870 7871 8038 8037 +639 7869 7870 8037 8036 +640 7868 7869 8036 8035 +641 7867 7868 8035 8034 +642 7866 7867 8034 8033 +643 7865 7866 8033 8032 +644 7864 7865 8032 8031 +645 7861 7862 7864 8031 +646 7860 7861 8031 8030 +647 7859 7860 8030 8029 +648 7858 7859 8029 8028 +649 7857 7858 8028 8027 +650 7856 7857 8027 8026 +651 7855 7856 8026 8025 +652 7854 7855 8025 8024 +653 7853 7854 8024 8023 +654 7852 7853 8023 8022 +655 7851 7852 8022 8021 +656 7850 7851 8021 8020 +657 7849 7850 8020 8019 +658 7848 7849 8019 8018 +659 7847 7848 8018 8017 +660 7846 7847 8017 7473 +661 7845 7846 7473 7474 +662 6276 6262 8016 8015 +663 8013 6276 8015 8014 +664 8011 8013 8014 8012 +665 6877 8011 8012 8010 +666 6878 6877 8010 8009 +667 7777 6878 8009 8008 +668 7776 7777 8008 7970 +669 7983 7984 7985 8007 +670 7982 7983 8007 8006 +671 7981 7982 8006 8005 +672 7980 7981 8005 8004 +673 7979 7980 8004 8003 +674 7978 7979 8003 8002 +675 7977 7978 8002 8001 +676 7976 7977 8001 8000 +677 7975 7976 8000 7999 +678 7974 7975 7999 7997 +679 7973 7974 7997 7998 +680 7476 7845 7474 7475 +681 7937 7938 7970 7996 +682 7936 7937 7996 7995 +683 7935 7936 7995 7994 +684 7934 7935 7994 7993 +685 7933 7934 7993 7992 +686 7932 7933 7992 7991 +687 7931 7932 7991 7990 +688 7930 7931 7990 7989 +689 7929 7930 7989 7988 +690 7928 7929 7988 7987 +691 7927 7928 7987 7986 +692 7926 7927 7986 7985 +693 7925 7926 7985 7984 +694 7750 7751 7925 7984 +695 7749 7750 7984 7983 +696 7748 7749 7983 7982 +697 7747 7748 7982 7981 +698 7746 7747 7981 7980 +699 7745 7746 7980 7979 +700 7744 7745 7979 7978 +701 7743 7744 7978 7977 +702 7742 7743 7977 7976 +703 7741 7742 7976 7975 +704 7740 7741 7975 7974 +705 7739 7740 7974 7973 +706 7738 7739 7973 7972 +707 7737 7738 7972 7971 +708 7681 7737 7971 7679 +709 7452 7451 7776 7970 +710 7939 7452 7970 7938 +711 7735 7736 7829 7969 +712 7734 7735 7969 7968 +713 7733 7734 7968 7967 +714 7732 7733 7967 7966 +715 7731 7732 7966 7730 +716 7729 7730 7966 7965 +717 7728 7729 7965 7964 +718 7727 7728 7964 7963 +719 7726 7727 7963 7962 +720 7725 7726 7962 7961 +721 7723 7725 7961 7960 +722 7724 7723 7960 7958 +723 7724 7958 7959 7957 +724 7722 7724 7957 7955 +725 7450 7452 7939 7940 +726 7449 7450 7940 7941 +727 7448 7449 7941 7942 +728 7446 7448 7942 7943 +729 7447 7446 7943 7944 +730 7956 7447 7944 7945 +731 7445 7956 7945 7946 +732 7695 7696 7722 7955 +733 7694 7695 7955 7954 +734 7693 7694 7954 7953 +735 7692 7693 7953 7952 +736 7691 7692 7952 7951 +737 7690 7691 7951 7950 +738 7689 7690 7950 7949 +739 7688 7689 7949 7948 +740 7687 7688 7948 7947 +741 7686 7687 7947 7721 +742 7444 7445 7946 7924 +743 7774 7775 7924 7946 +744 7773 7774 7946 7945 +745 7772 7773 7945 7944 +746 7771 7772 7944 7943 +747 7770 7771 7943 7942 +748 7769 7770 7942 7941 +749 7768 7769 7941 7940 +750 7767 7768 7940 7939 +751 7766 7767 7939 7938 +752 7765 7766 7938 7937 +753 7764 7765 7937 7936 +754 7763 7764 7936 7935 +755 7762 7763 7935 7934 +756 7761 7762 7934 7933 +757 7760 7761 7933 7932 +758 7759 7760 7932 7931 +759 7758 7759 7931 7930 +760 7757 7758 7930 7929 +761 7756 7757 7929 7928 +762 7755 7756 7928 7927 +763 7754 7755 7927 7926 +764 7753 7754 7926 7925 +765 7752 7753 7925 7751 +766 7401 7402 7775 7774 +767 7443 7444 7924 7775 +768 7781 7782 7911 7923 +769 7779 7781 7923 7922 +770 7780 7779 7922 7920 +771 7780 7920 7921 7919 +772 7778 7780 7919 7918 +773 7674 7778 7918 7673 +774 7650 7813 7814 7917 +775 7648 7650 7917 7916 +776 7647 7648 7916 7915 +777 7646 7647 7915 7914 +778 7645 7646 7914 7913 +779 7644 7645 7913 7912 +780 7643 7644 7912 7911 +781 7642 7643 7911 7782 +782 7670 7672 7673 7910 +783 7671 7670 7910 7908 +784 7671 7908 7909 7907 +785 7669 7671 7907 7906 +786 7668 7669 7906 7905 +787 7667 7668 7905 7904 +788 7666 7667 7904 7903 +789 7665 7666 7903 7902 +790 7664 7665 7902 7901 +791 7663 7664 7901 7900 +792 7662 7663 7900 7899 +793 7661 7662 7899 7898 +794 7660 7661 7898 7897 +795 7659 7660 7897 7803 +796 7658 7659 7803 7804 +797 7462 7463 7464 7595 +798 7594 7595 7464 7465 +799 7657 7658 7804 7805 +800 7593 7594 7465 7466 +801 7623 7467 7468 7896 +802 7622 7623 7896 7895 +803 7621 7622 7895 7894 +804 7619 7621 7894 7893 +805 7620 7619 7893 7891 +806 7620 7891 7892 7890 +807 7618 7620 7890 7889 +808 7617 7618 7889 7888 +809 7616 7617 7888 7887 +810 7615 7616 7887 7886 +811 7614 7615 7886 7885 +812 7613 7614 7885 7641 +813 7592 7593 7466 7625 +814 7534 7290 7291 7292 +815 7292 7293 7532 7534 +816 7591 7592 7625 7624 +817 7590 7591 7624 7626 +818 7589 7590 7626 7884 +819 7588 7589 7884 7883 +820 7587 7588 7883 7882 +821 7586 7587 7882 7881 +822 7585 7586 7881 7880 +823 7584 7585 7880 7879 +824 7583 7584 7879 7878 +825 7582 7583 7878 7877 +826 7581 7582 7877 7876 +827 7580 7581 7876 7875 +828 7579 7580 7875 7874 +829 7578 7579 7874 7873 +830 7577 7578 7873 7872 +831 7576 7577 7872 7871 +832 7575 7576 7871 7870 +833 7574 7575 7870 7869 +834 7573 7574 7869 7868 +835 7572 7573 7868 7867 +836 7571 7572 7867 7866 +837 7570 7571 7866 7865 +838 7569 7570 7865 7864 +839 7568 7569 7864 7862 +840 6714 7325 7326 6713 +841 7328 7329 6710 6711 +842 6711 6712 7327 7328 +843 7326 7327 6712 6713 +844 7683 7685 7863 7682 +845 7519 7682 7863 7518 +846 7517 7518 7863 7685 +847 7516 7517 7685 7684 +848 6715 7324 7325 6714 +849 7495 7496 7568 7862 +850 7494 7495 7862 7861 +851 7493 7494 7861 7860 +852 7492 7493 7860 7859 +853 7491 7492 7859 7858 +854 7490 7491 7858 7857 +855 7489 7490 7857 7856 +856 7488 7489 7856 7855 +857 7487 7488 7855 7854 +858 7486 7487 7854 7853 +859 7485 7486 7853 7852 +860 7484 7485 7852 7851 +861 7483 7484 7851 7850 +862 7482 7483 7850 7849 +863 7481 7482 7849 7848 +864 7480 7481 7848 7847 +865 7479 7480 7847 7846 +866 7478 7479 7846 7845 +867 7477 7478 7845 7476 +868 7130 7526 7843 7844 +869 7566 7567 7844 7843 +870 7527 7566 7843 7526 +871 7611 7612 7708 7842 +872 7610 7611 7842 7841 +873 7609 7610 7841 7840 +874 7608 7609 7840 7839 +875 7607 7608 7839 7838 +876 7606 7607 7838 7837 +877 7605 7606 7837 7836 +878 7604 7605 7836 7835 +879 7603 7604 7835 7834 +880 7602 7603 7834 7833 +881 7601 7602 7833 7832 +882 7600 7601 7832 7831 +883 7599 7600 7831 7830 +884 7598 7599 7830 7829 +885 7597 7598 7829 7736 +886 7563 7564 7783 7828 +887 7562 7563 7828 7827 +888 7561 7562 7827 7826 +889 7560 7561 7826 7825 +890 7559 7560 7825 7824 +891 7558 7559 7824 7823 +892 7557 7558 7823 7822 +893 7556 7557 7822 7821 +894 7555 7556 7821 7820 +895 7554 7555 7820 7819 +896 7553 7554 7819 7818 +897 7552 7553 7818 7817 +898 7551 7552 7817 7816 +899 7550 7551 7816 7815 +900 7549 7550 7815 7814 +901 7548 7549 7814 7813 +902 7547 7548 7813 7812 +903 7546 7547 7812 7811 +904 7545 7546 7811 7810 +905 7544 7545 7810 7809 +906 7543 7544 7809 7808 +907 7542 7543 7808 7807 +908 7541 7542 7807 7654 +909 7540 7541 7654 7653 +910 7539 7540 7653 7655 +911 7538 7539 7655 7806 +912 7371 7372 7805 7804 +913 7370 7371 7804 7803 +914 7369 7370 7803 7802 +915 7368 7369 7802 7801 +916 7367 7368 7801 7800 +917 7366 7367 7800 7799 +918 7365 7366 7799 7798 +919 7364 7365 7798 7797 +920 7363 7364 7797 7796 +921 7362 7363 7796 7795 +922 7361 7362 7795 7794 +923 7360 7361 7794 7793 +924 7359 7360 7793 7792 +925 7358 7359 7792 7791 +926 7357 7358 7791 7790 +927 7356 7357 7790 7789 +928 7355 7356 7789 7788 +929 7354 7355 7788 7787 +930 7353 7354 7787 7786 +931 7352 7353 7786 7785 +932 7351 7352 7785 7784 +933 7350 7351 7784 7783 +934 7349 7350 7783 7564 +935 7317 7318 7319 7411 +936 7456 7457 7642 7782 +937 7454 7456 7782 7781 +938 7455 7454 7781 7779 +939 7455 7779 7780 7778 +940 7453 7455 7778 7674 +941 7316 7317 7411 7412 +942 7154 6260 6878 7777 +943 7153 7154 7777 7776 +944 7152 7153 7776 7451 +945 7315 7316 7412 7413 +946 7402 7403 7443 7775 +947 7400 7401 7774 7773 +948 7399 7400 7773 7772 +949 7398 7399 7772 7771 +950 7397 7398 7771 7770 +951 7396 7397 7770 7769 +952 7395 7396 7769 7768 +953 7394 7395 7768 7767 +954 7393 7394 7767 7766 +955 7392 7393 7766 7765 +956 7391 7392 7765 7764 +957 7390 7391 7764 7763 +958 7389 7390 7763 7762 +959 7388 7389 7762 7761 +960 7387 7388 7761 7760 +961 7386 7387 7760 7759 +962 7385 7386 7759 7758 +963 7384 7385 7758 7757 +964 7383 7384 7757 7756 +965 7382 7383 7756 7755 +966 7381 7382 7755 7754 +967 7380 7381 7754 7753 +968 7379 7380 7753 7752 +969 7314 7315 7413 7414 +970 7442 7378 7379 7752 +971 7441 7442 7752 7751 +972 7440 7441 7751 7750 +973 7439 7440 7750 7749 +974 7438 7439 7749 7748 +975 7437 7438 7748 7747 +976 7436 7437 7747 7746 +977 7435 7436 7746 7745 +978 7434 7435 7745 7744 +979 7433 7434 7744 7743 +980 7432 7433 7743 7742 +981 7431 7432 7742 7741 +982 7430 7431 7741 7740 +983 7429 7430 7740 7739 +984 7428 7429 7739 7738 +985 7427 7428 7738 7737 +986 7426 7427 7737 7681 +987 7313 7314 7414 7415 +988 7425 7426 7681 7680 +989 7706 7596 7597 7736 +990 7705 7706 7736 7735 +991 7704 7705 7735 7734 +992 7703 7704 7734 7733 +993 7702 7703 7733 7732 +994 7701 7702 7732 7731 +995 7700 7701 7731 7730 +996 7699 7700 7730 7729 +997 7698 7699 7729 7728 +998 7697 7698 7728 7727 +999 7339 7697 7727 7726 +1000 7337 7339 7726 7725 +1001 7338 7337 7725 7723 +1002 7338 7723 7724 7722 +1003 7336 7338 7722 7696 +1004 7312 7313 7415 7416 +1005 7515 7516 7684 7686 +1006 7514 7515 7686 7721 +1007 7513 7514 7721 7720 +1008 7512 7513 7720 7719 +1009 7511 7512 7719 7718 +1010 7510 7511 7718 7717 +1011 7509 7510 7717 7716 +1012 7508 7509 7716 7715 +1013 7507 7508 7715 7714 +1014 7506 7507 7714 7713 +1015 7505 7506 7713 7712 +1016 7504 7505 7712 7711 +1017 7503 7504 7711 7710 +1018 7502 7503 7710 7709 +1019 7501 7502 7709 7708 +1020 7500 7501 7708 7612 +1021 7311 7312 7416 7417 +1022 6309 6310 7244 7707 +1023 7405 7406 6309 7707 +1024 7246 7405 7707 7247 +1025 7310 7311 7417 7418 +1026 7309 7310 7418 7419 +1027 7282 7283 7596 7706 +1028 7281 7282 7706 7705 +1029 7280 7281 7705 7704 +1030 7279 7280 7704 7703 +1031 7278 7279 7703 7702 +1032 7277 7278 7702 7701 +1033 7276 7277 7701 7700 +1034 7275 7276 7700 7699 +1035 7274 7275 7699 7698 +1036 7273 7274 7698 7697 +1037 7272 7273 7697 7339 +1038 7242 7243 7336 7696 +1039 7241 7242 7696 7695 +1040 7240 7241 7695 7694 +1041 7239 7240 7694 7693 +1042 7238 7239 7693 7692 +1043 7237 7238 7692 7691 +1044 7236 7237 7691 7690 +1045 7235 7236 7690 7689 +1046 7234 7235 7689 7688 +1047 7233 7234 7688 7687 +1048 7231 7233 7687 7686 +1049 7232 7231 7686 7684 +1050 7232 7684 7685 7683 +1051 7230 7232 7683 7229 +1052 7228 7229 7683 7682 +1053 7520 7228 7682 7519 +1054 7308 7309 7419 7420 +1055 7227 7228 7520 7521 +1056 7307 7308 7420 7421 +1057 7226 7227 7521 7522 +1058 7306 7307 7421 7422 +1059 7305 7306 7422 7423 +1060 7302 7304 7680 7303 +1061 7303 7680 7681 7679 +1062 7301 7303 7679 7678 +1063 7300 7301 7678 7677 +1064 7299 7300 7677 7676 +1065 7298 7299 7676 7675 +1066 6274 7298 7675 6273 +1067 7225 7226 7522 7523 +1068 7270 7271 7453 7674 +1069 7269 7270 7674 7673 +1070 7268 7269 7673 7672 +1071 7267 7268 7672 7265 +1072 7266 7265 7672 7670 +1073 7266 7670 7671 7669 +1074 7264 7266 7669 7668 +1075 7263 7264 7668 7667 +1076 7262 7263 7667 7666 +1077 7261 7262 7666 7665 +1078 7260 7261 7665 7664 +1079 7259 7260 7664 7663 +1080 7258 7259 7663 7662 +1081 7257 7258 7662 7256 +1082 7255 7256 7662 7661 +1083 7254 7255 7661 7660 +1084 7253 7254 7660 7659 +1085 7252 7253 7659 7658 +1086 7251 7252 7658 7657 +1087 7250 7251 7657 7656 +1088 7249 7250 7656 7374 +1089 7224 7225 7523 7524 +1090 6964 6965 6966 7655 +1091 6963 6964 7655 7653 +1092 6962 6963 7653 7654 +1093 6957 6959 7652 7651 +1094 6958 6957 7651 7649 +1095 6958 7649 7650 7648 +1096 6956 6958 7648 7647 +1097 6955 6956 7647 7646 +1098 6954 6955 7646 7645 +1099 6953 6954 7645 7644 +1100 6952 6953 7644 7643 +1101 6951 6952 7643 7642 +1102 6950 6951 7642 7457 +1103 7525 6718 7224 7524 +1104 7209 7210 7613 7641 +1105 7208 7209 7641 7640 +1106 7206 7208 7640 7639 +1107 7207 7206 7639 7637 +1108 7207 7637 7638 7636 +1109 7205 7207 7636 7635 +1110 7204 7205 7635 7634 +1111 7203 7204 7634 7633 +1112 7202 7203 7633 7632 +1113 7201 7202 7632 7631 +1114 7200 7201 7631 7630 +1115 7199 7200 7630 7629 +1116 7198 7199 7629 7628 +1117 7197 7198 7628 7627 +1118 7196 7197 7627 7626 +1119 7194 7196 7626 7624 +1120 7195 7194 7624 7625 +1121 7108 7109 7467 7623 +1122 7107 7108 7623 7622 +1123 7105 7107 7622 7621 +1124 7106 7105 7621 7619 +1125 7106 7619 7620 7618 +1126 7104 7106 7618 7617 +1127 7103 7104 7617 7616 +1128 7102 7103 7616 7615 +1129 7101 7102 7615 7614 +1130 7100 7101 7614 7613 +1131 7099 7100 7613 7210 +1132 6779 6781 7535 7536 +1133 7536 7537 6780 6779 +1134 7191 7192 7500 7612 +1135 7190 7191 7612 7611 +1136 7189 7190 7611 7610 +1137 7188 7189 7610 7609 +1138 7187 7188 7609 7608 +1139 7186 7187 7608 7607 +1140 7185 7186 7607 7606 +1141 7184 7185 7606 7605 +1142 7183 7184 7605 7604 +1143 7182 7183 7604 7603 +1144 7181 7182 7603 7602 +1145 7180 7181 7602 7601 +1146 7179 7180 7601 7600 +1147 7178 7179 7600 7599 +1148 7177 7178 7599 7598 +1149 7176 7177 7598 7597 +1150 7175 7176 7597 7596 +1151 7174 7175 7596 7283 +1152 7173 7174 7283 7285 +1153 7531 7535 6781 7529 +1154 7172 7173 7285 7284 +1155 6875 7459 7458 6874 +1156 6873 6874 7458 7460 +1157 6872 6873 7460 7461 +1158 6871 6872 7461 7462 +1159 6870 6871 7462 7595 +1160 6869 6870 7595 7594 +1161 6868 6869 7594 7593 +1162 6867 6868 7593 7592 +1163 6866 6867 7592 7591 +1164 6865 6866 7591 7590 +1165 6864 6865 7590 7589 +1166 6863 6864 7589 7588 +1167 6862 6863 7588 7587 +1168 6861 6862 7587 7586 +1169 6860 6861 7586 7585 +1170 6859 6860 7585 7584 +1171 6858 6859 7584 7583 +1172 6857 6858 7583 7582 +1173 6856 6857 7582 7581 +1174 6855 6856 7581 7580 +1175 6854 6855 7580 7579 +1176 6853 6854 7579 7578 +1177 6852 6853 7578 7577 +1178 6851 6852 7577 7576 +1179 6850 6851 7576 7575 +1180 6849 6850 7575 7574 +1181 6848 6849 7574 7573 +1182 6847 6848 7573 7572 +1183 6846 6847 7572 7571 +1184 6845 6846 7571 7570 +1185 6844 6845 7570 7569 +1186 6843 6844 7569 7568 +1187 6842 6843 7568 7496 +1188 7171 7172 7284 7286 +1189 7057 7058 7128 7567 +1190 7056 7057 7567 7566 +1191 7055 7056 7566 7527 +1192 7054 7055 7527 7528 +1193 7053 7054 7528 7565 +1194 6948 6949 7349 7564 +1195 6947 6948 7564 7563 +1196 6946 6947 7563 7562 +1197 6945 6946 7562 7561 +1198 6944 6945 7561 7560 +1199 6943 6944 7560 7559 +1200 6942 6943 7559 7558 +1201 6941 6942 7558 7557 +1202 6940 6941 7557 7556 +1203 6939 6940 7556 7555 +1204 6938 6939 7555 7554 +1205 6937 6938 7554 7553 +1206 6936 6937 7553 7552 +1207 6935 6936 7552 7551 +1208 6934 6935 7551 7550 +1209 6933 6934 7550 7549 +1210 6932 6933 7549 7548 +1211 6931 6932 7548 7547 +1212 6930 6931 7547 7546 +1213 6929 6930 7546 7545 +1214 6928 6929 7545 7544 +1215 6927 6928 7544 7543 +1216 6926 6927 7543 7542 +1217 6925 6926 7542 7541 +1218 6924 6925 7541 7540 +1219 6923 6924 7540 7539 +1220 6922 6923 7539 7538 +1221 6921 6922 7538 7410 +1222 7170 7171 7286 7287 +1223 7050 7051 6777 6776 +1224 7049 7050 6776 6778 +1225 7048 7049 6778 7537 +1226 7046 7047 7536 7535 +1227 7045 7046 7535 7531 +1228 7044 7045 7531 7499 +1229 7169 7170 7287 7288 +1230 7168 7169 7288 7289 +1231 7167 7168 7289 7290 +1232 7166 7167 7290 7534 +1233 7165 7166 7534 7532 +1234 7164 7165 7532 7533 +1235 7497 7499 7531 7529 +1236 7162 7163 7296 7295 +1237 7161 7162 7295 7294 +1238 7160 7161 7294 7375 +1239 7498 7497 7529 7530 +1240 7133 7134 7528 7527 +1241 7132 7133 7527 7526 +1242 7129 7132 7526 7130 +1243 7126 7127 7059 7060 +1244 7125 7126 7060 7061 +1245 7124 7125 7061 7062 +1246 7159 7160 7375 7376 +1247 7123 7124 7062 7063 +1248 7158 7159 7376 7377 +1249 7121 7123 7063 7064 +1250 6058 6060 6718 7525 +1251 6904 6905 7525 7524 +1252 6903 6904 7524 7523 +1253 6902 6903 7523 7522 +1254 6901 6902 7522 7521 +1255 6900 6901 7521 7520 +1256 6899 6900 7520 7519 +1257 6898 6899 7519 7518 +1258 6897 6898 7518 7517 +1259 6896 6897 7517 7516 +1260 6895 6896 7516 7515 +1261 6894 6895 7515 7514 +1262 6893 6894 7514 7513 +1263 6892 6893 7513 7512 +1264 6891 6892 7512 7511 +1265 6890 6891 7511 7510 +1266 6889 6890 7510 7509 +1267 6888 6889 7509 7508 +1268 6887 6888 7508 7507 +1269 6886 6887 7507 7506 +1270 6885 6886 7506 7505 +1271 6884 6885 7505 7504 +1272 6883 6884 7504 7503 +1273 6882 6883 7503 7502 +1274 6881 6882 7502 7501 +1275 6880 6881 7501 7500 +1276 6879 6880 7500 7192 +1277 7042 7044 7499 7497 +1278 7043 7042 7497 7498 +1279 7085 6841 6842 7496 +1280 7084 7085 7496 7495 +1281 7083 7084 7495 7494 +1282 7082 7083 7494 7493 +1283 7081 7082 7493 7492 +1284 7080 7081 7492 7491 +1285 7079 7080 7491 7490 +1286 7078 7079 7490 7489 +1287 7077 7078 7489 7488 +1288 7076 7077 7488 7487 +1289 7075 7076 7487 7486 +1290 7074 7075 7486 7485 +1291 7073 7074 7485 7484 +1292 7072 7073 7484 7483 +1293 7071 7072 7483 7482 +1294 7070 7071 7482 7481 +1295 7069 7070 7481 7480 +1296 7068 7069 7480 7479 +1297 7067 7068 7479 7478 +1298 7066 7067 7478 7477 +1299 7122 7121 7064 7065 +1300 7122 7065 7066 7477 +1301 7120 7122 7477 7476 +1302 7119 7120 7476 7475 +1303 7118 7119 7475 7474 +1304 7117 7118 7474 7473 +1305 7116 7117 7473 7472 +1306 7115 7116 7472 7471 +1307 7114 7115 7471 7470 +1308 7113 7114 7470 7469 +1309 7111 7113 7469 7468 +1310 7112 7111 7468 7467 +1311 7110 7112 7467 7109 +1312 6644 6645 7193 7466 +1313 6643 6644 7466 7465 +1314 6642 6643 7465 7464 +1315 6641 6642 7464 7463 +1316 6640 6641 7463 7462 +1317 6639 6640 7462 7461 +1318 6638 6639 7461 7460 +1319 6636 6638 7460 7458 +1320 6637 6636 7458 7459 +1321 6750 6751 6950 7457 +1322 6748 6750 7457 7456 +1323 6749 6748 7456 7454 +1324 6749 7454 7455 7453 +1325 6747 6749 7453 7271 +1326 7151 7150 7152 7451 +1327 7151 7451 7452 7450 +1328 7149 7151 7450 7449 +1329 7148 7149 7449 7448 +1330 7147 7148 7448 7446 +1331 7146 7147 7446 7447 +1332 7141 7142 7445 7444 +1333 7140 7141 7444 7443 +1334 7139 7140 7443 7403 +1335 7138 7139 7403 7404 +1336 7007 7008 7378 7442 +1337 7006 7007 7442 7441 +1338 7005 7006 7441 7440 +1339 7004 7005 7440 7439 +1340 7003 7004 7439 7438 +1341 7002 7003 7438 7437 +1342 7001 7002 7437 7436 +1343 7000 7001 7436 7435 +1344 6999 7000 7435 7434 +1345 6998 6999 7434 7433 +1346 6997 6998 7433 7432 +1347 6996 6997 7432 7431 +1348 6995 6996 7431 7430 +1349 6994 6995 7430 7429 +1350 6993 6994 7429 7428 +1351 6992 6993 7428 7427 +1352 6991 6992 7427 7426 +1353 6990 6991 7426 7425 +1354 6989 6990 7425 7424 +1355 6988 6989 7424 7423 +1356 6987 6988 7423 7422 +1357 6986 6987 7422 7421 +1358 6985 6986 7421 7420 +1359 6984 6985 7420 7419 +1360 6983 6984 7419 7418 +1361 6982 6983 7418 7417 +1362 6981 6982 7417 7416 +1363 6980 6981 7416 7415 +1364 6979 6980 7415 7414 +1365 6978 6979 7414 7413 +1366 6977 6978 7413 7412 +1367 6976 6977 7412 7411 +1368 6975 6976 7411 7319 +1369 6974 6975 7319 7320 +1370 6972 6974 7320 7321 +1371 6920 6921 7410 6969 +1372 6973 6972 7321 7322 +1373 6308 6309 7406 7407 +1374 6307 6308 7407 7408 +1375 6971 6973 7322 7323 +1376 6306 6307 7408 7409 +1377 6840 6305 6306 7409 +1378 6839 6840 7409 7408 +1379 6838 6839 7408 7407 +1380 6837 6838 7407 7406 +1381 6836 6837 7406 7405 +1382 6835 6836 7405 7246 +1383 7035 7036 7404 7403 +1384 7034 7035 7403 7402 +1385 7033 7034 7402 7401 +1386 7032 7033 7401 7400 +1387 7031 7032 7400 7399 +1388 7030 7031 7399 7398 +1389 7029 7030 7398 7397 +1390 7028 7029 7397 7396 +1391 7027 7028 7396 7395 +1392 7026 7027 7395 7394 +1393 7025 7026 7394 7393 +1394 7024 7025 7393 7392 +1395 7023 7024 7392 7391 +1396 7022 7023 7391 7390 +1397 7021 7022 7390 7389 +1398 7020 7021 7389 7388 +1399 7019 7020 7388 7387 +1400 7018 7019 7387 7386 +1401 7017 7018 7386 7385 +1402 7016 7017 7385 7384 +1403 7015 7016 7384 7383 +1404 7014 7015 7383 7382 +1405 7013 7014 7382 7381 +1406 7012 7013 7381 7380 +1407 7011 7012 7380 7379 +1408 7010 7011 7379 7378 +1409 7009 7010 7378 7008 +1410 6834 6835 7246 7245 +1411 7348 7157 7345 7346 +1412 7344 7345 7157 7156 +1413 7343 7344 7156 7158 +1414 7342 7343 7158 7377 +1415 7341 7342 7377 7376 +1416 7340 7341 7376 7375 +1417 7297 7340 7375 7294 +1418 6833 6834 7245 7248 +1419 6832 6833 7248 7249 +1420 6831 6832 7249 7374 +1421 6830 6831 7374 7373 +1422 6829 6830 7373 7372 +1423 6828 6829 7372 7371 +1424 6827 6828 7371 7370 +1425 6826 6827 7370 7369 +1426 6825 6826 7369 7368 +1427 6824 6825 7368 7367 +1428 6823 6824 7367 7366 +1429 6822 6823 7366 7365 +1430 6821 6822 7365 7364 +1431 6820 6821 7364 7363 +1432 6819 6820 7363 7362 +1433 6818 6819 7362 7361 +1434 6817 6818 7361 7360 +1435 6816 6817 7360 7359 +1436 6815 6816 7359 7358 +1437 6814 6815 7358 7357 +1438 6813 6814 7357 7356 +1439 6812 6813 7356 7355 +1440 6811 6812 7355 7354 +1441 6810 6811 7354 7353 +1442 6809 6810 7353 7352 +1443 6808 6809 7352 7351 +1444 6807 6808 7351 7350 +1445 6806 6807 7350 7349 +1446 6805 6806 7349 6949 +1447 6504 6505 7157 7348 +1448 6631 6632 7155 7347 +1449 6630 6631 7347 7346 +1450 6629 6630 7346 7345 +1451 6628 6629 7345 7344 +1452 6627 6628 7344 7343 +1453 6626 6627 7343 7342 +1454 6625 6626 7342 7341 +1455 6624 6625 7341 7340 +1456 6623 6624 7340 7297 +1457 6802 6804 7272 7339 +1458 6803 6802 7339 7337 +1459 6803 7337 7338 7336 +1460 6801 6803 7336 7243 +1461 7214 7215 7331 7330 +1462 6709 6710 7329 7335 +1463 7211 7212 7333 7334 +1464 6919 7211 7334 6918 +1465 7213 7332 7333 7212 +1466 6914 6915 7330 7331 +1467 6910 6911 7329 7328 +1468 6909 6910 7328 7327 +1469 6908 6909 7327 7326 +1470 6907 6908 7326 7325 +1471 6906 6907 7325 7324 +1472 6716 6906 7324 6715 +1473 6219 6220 6973 6971 +1474 6301 6302 7323 7322 +1475 6300 6301 7322 7321 +1476 6299 6300 7321 7320 +1477 6298 6299 7320 7319 +1478 6297 6298 7319 7318 +1479 6296 6297 7318 7317 +1480 6295 6296 7317 7316 +1481 6294 6295 7316 7315 +1482 6293 6294 7315 7314 +1483 6292 6293 7314 7313 +1484 6291 6292 7313 7312 +1485 6290 6291 7312 7311 +1486 6289 6290 7311 7310 +1487 6288 6289 7310 7309 +1488 6287 6288 7309 7308 +1489 6286 6287 7308 7307 +1490 6285 6286 7307 7306 +1491 6284 6285 7306 7305 +1492 6282 6284 7305 7304 +1493 6283 6282 7304 7302 +1494 6283 7302 7303 7301 +1495 6281 6283 7301 7300 +1496 6279 6281 7300 7299 +1497 6277 6279 7299 7298 +1498 6275 6277 7298 6274 +1499 6697 6622 6623 7297 +1500 6698 6697 7297 7294 +1501 6698 7294 7295 7296 +1502 6693 6694 7293 7292 +1503 6692 6693 7292 7291 +1504 6691 6692 7291 7290 +1505 6690 6691 7290 7289 +1506 6689 6690 7289 7288 +1507 6688 6689 7288 7287 +1508 6686 6688 7287 7286 +1509 6687 6686 7286 7284 +1510 6687 7284 7285 7283 +1511 6685 6687 7283 7282 +1512 6684 6685 7282 7281 +1513 6683 6684 7281 7280 +1514 6682 6683 7280 7279 +1515 6681 6682 7279 7278 +1516 6680 6681 7278 7277 +1517 6679 6680 7277 7276 +1518 6678 6679 7276 7275 +1519 6677 6678 7275 7274 +1520 6676 6677 7274 7273 +1521 6675 6676 7273 7272 +1522 6674 6675 7272 6804 +1523 6745 6746 6747 7271 +1524 6744 6745 7271 7270 +1525 6743 6744 7270 7269 +1526 6741 6743 7269 7268 +1527 6742 6741 7268 7267 +1528 6740 6739 7267 7265 +1529 6740 7265 7266 7264 +1530 6738 6740 7264 7263 +1531 6737 6738 7263 7262 +1532 6736 6737 7262 7261 +1533 6735 6736 7261 7260 +1534 6734 6735 7260 7259 +1535 6733 6734 7259 7258 +1536 6732 6733 7258 7257 +1537 6731 6732 7257 7256 +1538 6730 6731 7256 7255 +1539 6729 6730 7255 7254 +1540 6728 6729 7254 7253 +1541 6727 6728 7253 7252 +1542 6726 6727 7252 7251 +1543 6725 6726 7251 7250 +1544 6724 6725 7250 7249 +1545 6722 6724 7249 7248 +1546 6723 6722 7248 7245 +1547 6723 7245 7246 7247 +1548 6311 6720 7244 6310 +1549 6799 6800 6801 7243 +1550 6798 6799 7243 7242 +1551 6797 6798 7242 7241 +1552 6796 6797 7241 7240 +1553 6795 6796 7240 7239 +1554 6794 6795 7239 7238 +1555 6793 6794 7238 7237 +1556 6792 6793 7237 7236 +1557 6791 6792 7236 7235 +1558 6789 6791 7235 7234 +1559 6790 6789 7234 7233 +1560 7223 6790 7233 7231 +1561 7223 7231 7232 7230 +1562 7222 7223 7230 7229 +1563 7221 7222 7229 7228 +1564 7220 7221 7228 7227 +1565 7219 7220 7227 7226 +1566 7218 7219 7226 7225 +1567 7217 7218 7225 7224 +1568 6717 7217 7224 6718 +1569 6788 6790 7223 7222 +1570 6787 6788 7222 7221 +1571 6786 6787 7221 7220 +1572 6785 6786 7220 7219 +1573 6784 6785 7219 7218 +1574 6783 6784 7218 7217 +1575 6719 6783 7217 6717 +1576 6699 6700 6701 7216 +1577 6369 6370 7215 7214 +1578 6368 6369 7214 7213 +1579 6367 6368 7213 7212 +1580 6366 6367 7212 7211 +1581 6364 6366 7211 6919 +1582 7097 7098 7099 7210 +1583 7096 7097 7210 7209 +1584 7094 7096 7209 7208 +1585 7095 7094 7208 7206 +1586 7095 7206 7207 7205 +1587 7093 7095 7205 7204 +1588 7092 7093 7204 7203 +1589 7091 7092 7203 7090 +1590 7089 7090 7203 7202 +1591 7088 7089 7202 7201 +1592 7087 7088 7201 7200 +1593 7086 7087 7200 7199 +1594 6650 7086 7199 7198 +1595 6649 6650 7198 7197 +1596 6647 6649 7197 7196 +1597 6648 6647 7196 7194 +1598 6648 7194 7195 7193 +1599 6646 6648 7193 6645 +1600 6541 6542 6879 7192 +1601 6540 6541 7192 7191 +1602 6539 6540 7191 7190 +1603 6538 6539 7190 7189 +1604 6537 6538 7189 7188 +1605 6536 6537 7188 7187 +1606 6535 6536 7187 7186 +1607 6534 6535 7186 7185 +1608 6533 6534 7185 7184 +1609 6532 6533 7184 7183 +1610 6531 6532 7183 7182 +1611 6530 6531 7182 7181 +1612 6529 6530 7181 7180 +1613 6528 6529 7180 7179 +1614 6527 6528 7179 7178 +1615 6526 6527 7178 7177 +1616 6525 6526 7177 7176 +1617 6524 6525 7176 7175 +1618 6523 6524 7175 7174 +1619 6522 6523 7174 7173 +1620 6521 6522 7173 7172 +1621 6520 6521 7172 7171 +1622 6519 6520 7171 7170 +1623 6518 6519 7170 7169 +1624 6517 6518 7169 7168 +1625 6516 6517 7168 7167 +1626 6515 6516 7167 7166 +1627 6514 6515 7166 7165 +1628 6513 6514 7165 7164 +1629 6512 6513 7164 7163 +1630 6511 6512 7163 7162 +1631 6510 6511 7162 7161 +1632 6509 6510 7161 7160 +1633 6508 6509 7160 7159 +1634 6507 6508 7159 7158 +1635 6506 6507 7158 7156 +1636 6505 6506 7156 7157 +1637 6502 6503 7155 6632 +1638 5997 5998 6260 7154 +1639 5996 5997 7154 7153 +1640 5995 5996 7153 7152 +1641 5994 5995 7152 7150 +1642 5992 5994 7150 5993 +1643 5993 7150 7151 7149 +1644 5991 5993 7149 7148 +1645 5990 5991 7148 7147 +1646 5989 5990 7147 7146 +1647 5988 5989 7146 7145 +1648 5987 5988 7145 7144 +1649 5986 5987 7144 7143 +1650 5985 5986 7143 5984 +1651 5983 5984 7143 7142 +1652 5982 5983 7142 7141 +1653 5981 5982 7141 7140 +1654 5980 5981 7140 7139 +1655 5978 5980 7139 7138 +1656 5979 5978 7138 7137 +1657 7039 5979 7137 7038 +1658 6501 6502 6632 6633 +1659 5976 5979 7039 7040 +1660 6500 6501 6633 6635 +1661 5977 5976 7040 7041 +1662 5974 5975 7136 6782 +1663 6772 6774 7135 7134 +1664 6773 6772 7134 7133 +1665 7131 6773 7133 7132 +1666 6771 7131 7132 7129 +1667 6768 6769 7129 7130 +1668 6766 6767 7128 7127 +1669 6765 6766 7127 7126 +1670 6764 6765 7126 7125 +1671 6763 6764 7125 7124 +1672 6761 6763 7124 7123 +1673 6762 6761 7123 7121 +1674 6762 7121 7122 7120 +1675 6760 6762 7120 7119 +1676 6759 6760 7119 7118 +1677 6758 6759 7118 7117 +1678 6757 6758 7117 7116 +1679 6756 6757 7116 7115 +1680 6755 6756 7115 7114 +1681 6754 6755 7114 7113 +1682 6752 6754 7113 7111 +1683 6753 6752 7111 7112 +1684 6672 6673 7110 7109 +1685 6671 6672 7109 7108 +1686 6669 6671 7108 7107 +1687 6670 6669 7107 7105 +1688 6670 7105 7106 7104 +1689 6668 6670 7104 7103 +1690 6667 6668 7103 7102 +1691 6666 6667 7102 7101 +1692 6665 6666 7101 7100 +1693 6663 6665 7100 7099 +1694 6664 6663 7099 7098 +1695 6661 6662 7098 7097 +1696 6659 6661 7097 7096 +1697 6660 6659 7096 7094 +1698 6660 7094 7095 7093 +1699 6658 6660 7093 7092 +1700 6657 6658 7092 7091 +1701 6656 6657 7091 7090 +1702 6655 6656 7090 7089 +1703 6654 6655 7089 7088 +1704 6653 6654 7088 7087 +1705 6652 6653 7087 7086 +1706 6651 6652 7086 6650 +1707 6620 6621 6841 7085 +1708 6619 6620 7085 7084 +1709 6618 6619 7084 7083 +1710 6617 6618 7083 7082 +1711 6616 6617 7082 7081 +1712 6615 6616 7081 7080 +1713 6614 6615 7080 7079 +1714 6613 6614 7079 7078 +1715 6612 6613 7078 7077 +1716 6611 6612 7077 7076 +1717 6610 6611 7076 7075 +1718 6609 6610 7075 7074 +1719 6608 6609 7074 7073 +1720 6607 6608 7073 7072 +1721 6606 6607 7072 7071 +1722 6605 6606 7071 7070 +1723 6604 6605 7070 7069 +1724 6603 6604 7069 7068 +1725 6602 6603 7068 7067 +1726 6601 6602 7067 7066 +1727 6600 6601 7066 7065 +1728 6599 6600 7065 7064 +1729 6598 6599 7064 7063 +1730 6597 6598 7063 7062 +1731 6596 6597 7062 7061 +1732 6595 6596 7061 7060 +1733 6594 6595 7060 7059 +1734 6593 6594 7059 7058 +1735 6592 6593 7058 7057 +1736 6591 6592 7057 7056 +1737 6590 6591 7056 7055 +1738 6589 6590 7055 7054 +1739 6588 6589 7054 7053 +1740 6587 6588 7053 7052 +1741 6586 6587 7052 7051 +1742 6585 6586 7051 7050 +1743 6584 6585 7050 7049 +1744 6583 6584 7049 7048 +1745 6582 6583 7048 7047 +1746 6581 6582 7047 7046 +1747 6580 6581 7046 7045 +1748 6579 6580 7045 7044 +1749 6578 6579 7044 7042 +1750 6577 6578 7042 7043 +1751 6574 6575 7041 7040 +1752 6573 6574 7040 7039 +1753 6572 6573 7039 7038 +1754 6571 6572 7038 7037 +1755 6570 6571 7037 7036 +1756 6569 6570 7036 7035 +1757 6568 6569 7035 7034 +1758 6567 6568 7034 7033 +1759 6566 6567 7033 7032 +1760 6565 6566 7032 7031 +1761 6564 6565 7031 7030 +1762 6563 6564 7030 7029 +1763 6562 6563 7029 7028 +1764 6561 6562 7028 7027 +1765 6560 6561 7027 7026 +1766 6559 6560 7026 7025 +1767 6558 6559 7025 7024 +1768 6557 6558 7024 7023 +1769 6556 6557 7023 7022 +1770 6555 6556 7022 7021 +1771 6554 6555 7021 7020 +1772 6553 6554 7020 7019 +1773 6552 6553 7019 7018 +1774 6551 6552 7018 7017 +1775 6550 6551 7017 7016 +1776 6549 6550 7016 7015 +1777 6548 6549 7015 7014 +1778 6547 6548 7014 7013 +1779 6546 6547 7013 7012 +1780 6545 6546 7012 7011 +1781 6544 6545 7011 7010 +1782 6543 6544 7010 7009 +1783 6257 6258 6543 7009 +1784 6256 6257 7009 7008 +1785 6255 6256 7008 7007 +1786 6254 6255 7007 7006 +1787 6253 6254 7006 7005 +1788 6252 6253 7005 7004 +1789 6251 6252 7004 7003 +1790 6250 6251 7003 7002 +1791 6249 6250 7002 7001 +1792 6248 6249 7001 7000 +1793 6247 6248 7000 6999 +1794 6246 6247 6999 6998 +1795 6245 6246 6998 6997 +1796 6244 6245 6997 6996 +1797 6243 6244 6996 6995 +1798 6242 6243 6995 6994 +1799 6241 6242 6994 6993 +1800 6240 6241 6993 6992 +1801 6239 6240 6992 6991 +1802 6238 6239 6991 6990 +1803 6237 6238 6990 6989 +1804 6236 6237 6989 6988 +1805 6235 6236 6988 6987 +1806 6234 6235 6987 6986 +1807 6233 6234 6986 6985 +1808 6232 6233 6985 6984 +1809 6231 6232 6984 6983 +1810 6230 6231 6983 6982 +1811 6229 6230 6982 6981 +1812 6228 6229 6981 6980 +1813 6227 6228 6980 6979 +1814 6226 6227 6979 6978 +1815 6225 6226 6978 6977 +1816 6224 6225 6977 6976 +1817 6223 6224 6976 6975 +1818 6222 6223 6975 6974 +1819 6221 6222 6974 6972 +1820 6220 6221 6972 6973 +1821 6218 6219 6971 6970 +1822 6217 6218 6970 6304 +1823 6363 6365 6920 6969 +1824 6362 6363 6969 6968 +1825 6361 6362 6968 6967 +1826 6360 6361 6967 6966 +1827 6359 6360 6966 6965 +1828 6358 6359 6965 6357 +1829 6356 6357 6965 6964 +1830 6355 6356 6964 6963 +1831 6354 6355 6963 6962 +1832 6353 6354 6962 6961 +1833 6352 6353 6961 6960 +1834 6350 6352 6960 6959 +1835 6351 6350 6959 6957 +1836 6351 6957 6958 6956 +1837 6349 6351 6956 6955 +1838 6348 6349 6955 6954 +1839 6347 6348 6954 6953 +1840 6346 6347 6953 6952 +1841 6345 6346 6952 6951 +1842 6344 6345 6951 6950 +1843 6343 6344 6950 6751 +1844 6461 6462 6805 6949 +1845 6460 6461 6949 6948 +1846 6459 6460 6948 6947 +1847 6458 6459 6947 6946 +1848 6457 6458 6946 6945 +1849 6456 6457 6945 6944 +1850 6455 6456 6944 6943 +1851 6454 6455 6943 6942 +1852 6453 6454 6942 6941 +1853 6452 6453 6941 6940 +1854 6451 6452 6940 6939 +1855 6450 6451 6939 6938 +1856 6449 6450 6938 6937 +1857 6448 6449 6937 6936 +1858 6447 6448 6936 6935 +1859 6446 6447 6935 6934 +1860 6445 6446 6934 6933 +1861 6444 6445 6933 6932 +1862 6443 6444 6932 6931 +1863 6442 6443 6931 6930 +1864 6441 6442 6930 6929 +1865 6440 6441 6929 6928 +1866 6439 6440 6928 6927 +1867 6438 6439 6927 6926 +1868 6437 6438 6926 6925 +1869 6436 6437 6925 6924 +1870 6435 6436 6924 6923 +1871 6434 6435 6923 6922 +1872 6433 6434 6922 6921 +1873 6432 6433 6921 6920 +1874 6431 6432 6920 6365 +1875 6430 6431 6365 6364 +1876 6429 6430 6364 6919 +1877 6428 6429 6919 6918 +1878 6427 6428 6918 6917 +1879 6426 6427 6917 6916 +1880 6425 6426 6916 6915 +1881 6424 6425 6915 6914 +1882 6423 6424 6914 6913 +1883 6422 6423 6913 6704 +1884 6421 6422 6704 6703 +1885 6420 6421 6703 6706 +1886 6419 6420 6706 6912 +1887 6418 6419 6912 6911 +1888 6417 6418 6911 6910 +1889 6416 6417 6910 6909 +1890 6415 6416 6909 6908 +1891 6414 6415 6908 6907 +1892 6413 6414 6907 6906 +1893 6412 6413 6906 6716 +1894 6411 6412 6716 6059 +1895 6410 6411 6059 6905 +1896 6409 6410 6905 6904 +1897 6408 6409 6904 6903 +1898 6407 6408 6903 6902 +1899 6406 6407 6902 6901 +1900 6405 6406 6901 6900 +1901 6404 6405 6900 6899 +1902 6403 6404 6899 6898 +1903 6402 6403 6898 6897 +1904 6401 6402 6897 6896 +1905 6400 6401 6896 6895 +1906 6399 6400 6895 6894 +1907 6398 6399 6894 6893 +1908 6397 6398 6893 6892 +1909 6396 6397 6892 6891 +1910 6395 6396 6891 6890 +1911 6394 6395 6890 6889 +1912 6393 6394 6889 6888 +1913 6392 6393 6888 6887 +1914 6391 6392 6887 6886 +1915 6390 6391 6886 6885 +1916 6389 6390 6885 6884 +1917 6388 6389 6884 6883 +1918 6387 6388 6883 6882 +1919 6386 6387 6882 6881 +1920 6385 6386 6881 6880 +1921 6384 6385 6880 6879 +1922 6383 6384 6879 6542 +1923 6260 6259 6877 6878 +1924 5500 5501 6782 6876 +1925 6499 6500 6635 6634 +1926 6497 6498 6875 6874 +1927 6496 6497 6874 6873 +1928 6495 6496 6873 6872 +1929 6494 6495 6872 6871 +1930 6493 6494 6871 6870 +1931 6492 6493 6870 6869 +1932 6491 6492 6869 6868 +1933 6490 6491 6868 6867 +1934 6489 6490 6867 6866 +1935 6488 6489 6866 6865 +1936 6487 6488 6865 6864 +1937 6486 6487 6864 6863 +1938 6485 6486 6863 6862 +1939 6484 6485 6862 6861 +1940 6483 6484 6861 6860 +1941 6482 6483 6860 6859 +1942 6481 6482 6859 6858 +1943 6480 6481 6858 6857 +1944 6479 6480 6857 6856 +1945 6478 6479 6856 6855 +1946 6477 6478 6855 6854 +1947 6476 6477 6854 6853 +1948 6475 6476 6853 6852 +1949 6474 6475 6852 6851 +1950 6473 6474 6851 6850 +1951 6472 6473 6850 6849 +1952 6471 6472 6849 6848 +1953 6470 6471 6848 6847 +1954 6469 6470 6847 6846 +1955 6468 6469 6846 6845 +1956 6467 6468 6845 6844 +1957 6466 6467 6844 6843 +1958 6465 6466 6843 6842 +1959 6464 6465 6842 6841 +1960 6463 6464 6841 6621 +1961 6214 6215 6305 6840 +1962 6213 6214 6840 6839 +1963 6212 6213 6839 6838 +1964 6211 6212 6838 6837 +1965 6210 6211 6837 6836 +1966 6209 6210 6836 6835 +1967 6208 6209 6835 6834 +1968 6207 6208 6834 6833 +1969 6206 6207 6833 6832 +1970 6205 6206 6832 6831 +1971 6204 6205 6831 6830 +1972 6203 6204 6830 6829 +1973 6202 6203 6829 6828 +1974 6201 6202 6828 6827 +1975 6200 6201 6827 6826 +1976 6199 6200 6826 6825 +1977 6198 6199 6825 6824 +1978 6197 6198 6824 6823 +1979 6196 6197 6823 6822 +1980 6195 6196 6822 6821 +1981 6194 6195 6821 6820 +1982 6193 6194 6820 6819 +1983 6192 6193 6819 6818 +1984 6191 6192 6818 6817 +1985 6190 6191 6817 6816 +1986 6189 6190 6816 6815 +1987 6188 6189 6815 6814 +1988 6187 6188 6814 6813 +1989 6186 6187 6813 6812 +1990 6185 6186 6812 6811 +1991 6184 6185 6811 6810 +1992 6183 6184 6810 6809 +1993 6182 6183 6809 6808 +1994 6181 6182 6808 6807 +1995 6180 6181 6807 6806 +1996 6179 6180 6806 6805 +1997 6178 6179 6805 6462 +1998 6085 6087 6674 6804 +1999 6086 6085 6804 6802 +2000 6086 6802 6803 6801 +2001 6084 6086 6801 6800 +2002 6083 6084 6800 6082 +2003 6081 6082 6800 6799 +2004 6080 6081 6799 6798 +2005 6079 6080 6798 6797 +2006 6078 6079 6797 6796 +2007 6077 6078 6796 6795 +2008 6076 6077 6795 6794 +2009 6075 6076 6794 6793 +2010 6074 6075 6793 6792 +2011 6072 6074 6792 6791 +2012 6073 6072 6791 6789 +2013 6073 6789 6790 6788 +2014 6071 6073 6788 6070 +2015 6069 6070 6788 6787 +2016 6068 6069 6787 6786 +2017 6067 6068 6786 6785 +2018 6066 6067 6785 6784 +2019 6065 6066 6784 6783 +2020 6064 6065 6783 6719 +2021 5501 5502 5974 6782 +2022 5498 5499 6781 6779 +2023 5497 5498 6779 6780 +2024 5973 5972 6778 6776 +2025 5973 6776 6777 6775 +2026 5971 5973 6775 6774 +2027 5970 5971 6774 6772 +2028 5969 5970 6772 6773 +2029 5964 5965 6771 6770 +2030 5963 5964 6770 6769 +2031 5962 5963 6769 6768 +2032 5961 5962 6768 6767 +2033 5960 5961 6767 6766 +2034 5959 5960 6766 6765 +2035 5958 5959 6765 6764 +2036 5956 5958 6764 6763 +2037 5957 5956 6763 6761 +2038 5957 6761 6762 6760 +2039 5955 5957 6760 6759 +2040 5954 5955 6759 6758 +2041 5953 5954 6758 6757 +2042 5952 5953 6757 6756 +2043 5951 5952 6756 6755 +2044 5950 5951 6755 6754 +2045 5949 5950 6754 6752 +2046 5948 5949 6752 6753 +2047 6341 6342 6343 6751 +2048 6339 6341 6751 6750 +2049 6340 6339 6750 6748 +2050 6340 6748 6749 6747 +2051 6338 6340 6747 6746 +2052 6336 6337 6338 6746 +2053 6335 6336 6746 6745 +2054 6334 6335 6745 6744 +2055 6333 6334 6744 6743 +2056 6332 6333 6743 6741 +2057 6331 6332 6741 6742 +2058 6330 6739 6740 6738 +2059 6328 6330 6738 6737 +2060 6327 6328 6737 6736 +2061 6326 6327 6736 6735 +2062 6325 6326 6735 6734 +2063 6324 6325 6734 6733 +2064 6323 6324 6733 6732 +2065 6322 6323 6732 6731 +2066 6321 6322 6731 6730 +2067 6320 6321 6730 6729 +2068 6319 6320 6729 6728 +2069 6318 6319 6728 6727 +2070 6317 6318 6727 6726 +2071 6316 6317 6726 6725 +2072 6314 6316 6725 6724 +2073 6315 6314 6724 6722 +2074 6315 6722 6723 6721 +2075 6313 6315 6721 6720 +2076 6312 6313 6720 6311 +2077 6062 6063 6064 6719 +2078 6061 6062 6719 6717 +2079 6060 6061 6717 6718 +2080 6057 6059 6716 6715 +2081 6056 6057 6715 6714 +2082 6055 6056 6714 6713 +2083 6054 6055 6713 6712 +2084 6053 6054 6712 6711 +2085 6052 6053 6711 6710 +2086 6051 6052 6710 6709 +2087 6382 6051 6709 6708 +2088 6381 6382 6708 6707 +2089 6379 6381 6707 6706 +2090 6380 6379 6706 6703 +2091 6380 6703 6704 6705 +2092 6375 6376 6702 6701 +2093 6374 6375 6701 6700 +2094 6373 6374 6700 6699 +2095 6371 6373 6699 6372 +2096 6110 6109 6622 6697 +2097 6110 6697 6698 6696 +2098 6108 6110 6696 6695 +2099 6107 6108 6695 6694 +2100 6106 6107 6694 6693 +2101 6105 6106 6693 6692 +2102 6104 6105 6692 6691 +2103 6103 6104 6691 6690 +2104 6102 6103 6690 6689 +2105 6100 6102 6689 6688 +2106 6101 6100 6688 6686 +2107 6101 6686 6687 6685 +2108 6099 6101 6685 6684 +2109 6098 6099 6684 6683 +2110 6097 6098 6683 6682 +2111 6096 6097 6682 6681 +2112 6095 6096 6681 6680 +2113 6094 6095 6680 6679 +2114 6093 6094 6679 6678 +2115 6092 6093 6678 6677 +2116 6091 6092 6677 6676 +2117 6090 6091 6676 6675 +2118 6089 6090 6675 6674 +2119 6088 6089 6674 6087 +2120 5944 5945 6673 6672 +2121 5942 5944 6672 6671 +2122 5943 5942 6671 6669 +2123 5943 6669 6670 6668 +2124 5941 5943 6668 6667 +2125 5940 5941 6667 5939 +2126 5938 5939 6667 6666 +2127 5937 5938 6666 6665 +2128 5936 5937 6665 6663 +2129 5935 5936 6663 6664 +2130 5931 5933 6662 6661 +2131 5932 5931 6661 6659 +2132 5932 6659 6660 6658 +2133 5930 5932 6658 6657 +2134 5929 5930 6657 6656 +2135 5928 5929 6656 6655 +2136 5927 5928 6655 6654 +2137 5926 5927 6654 6653 +2138 5925 5926 6653 6652 +2139 5924 5925 6652 6651 +2140 5923 5924 6651 5922 +2141 5921 5922 6651 6650 +2142 5919 5921 6650 6649 +2143 5920 5919 6649 6647 +2144 5920 6647 6648 6646 +2145 5918 5920 6646 5917 +2146 5916 5917 6646 6645 +2147 5915 5916 6645 6644 +2148 5914 5915 6644 6643 +2149 5913 5914 6643 6642 +2150 5912 5913 6642 6641 +2151 5911 5912 6641 6640 +2152 5910 5911 6640 6639 +2153 5909 5910 6639 6638 +2154 5908 5909 6638 6636 +2155 5907 5908 6636 6637 +2156 5905 6634 6635 6633 +2157 5903 5905 6633 6632 +2158 5902 5903 6632 6631 +2159 5901 5902 6631 6630 +2160 5900 5901 6630 6629 +2161 5899 5900 6629 6628 +2162 5898 5899 6628 6627 +2163 5897 5898 6627 6626 +2164 5896 5897 6626 6625 +2165 5895 5896 6625 6624 +2166 5894 5895 6624 6623 +2167 5893 5894 6623 6622 +2168 5892 5893 6622 6109 +2169 5890 5891 6463 6621 +2170 5889 5890 6621 6620 +2171 5888 5889 6620 6619 +2172 5887 5888 6619 6618 +2173 5886 5887 6618 6617 +2174 5885 5886 6617 6616 +2175 5884 5885 6616 6615 +2176 5883 5884 6615 6614 +2177 5882 5883 6614 6613 +2178 5881 5882 6613 6612 +2179 5880 5881 6612 6611 +2180 5879 5880 6611 6610 +2181 5878 5879 6610 6609 +2182 5877 5878 6609 6608 +2183 5876 5877 6608 6607 +2184 5875 5876 6607 6606 +2185 5874 5875 6606 6605 +2186 5873 5874 6605 6604 +2187 5872 5873 6604 6603 +2188 5871 5872 6603 6602 +2189 5870 5871 6602 6601 +2190 5869 5870 6601 6600 +2191 5868 5869 6600 6599 +2192 5867 5868 6599 6598 +2193 5866 5867 6598 6597 +2194 5865 5866 6597 6596 +2195 5864 5865 6596 6595 +2196 5863 5864 6595 6594 +2197 5862 5863 6594 6593 +2198 5861 5862 6593 6592 +2199 5860 5861 6592 6591 +2200 5859 5860 6591 6590 +2201 5858 5859 6590 6589 +2202 5857 5858 6589 6588 +2203 5856 5857 6588 6587 +2204 5855 5856 6587 6586 +2205 5854 5855 6586 6585 +2206 5853 5854 6585 6584 +2207 5852 5853 6584 6583 +2208 5851 5852 6583 6582 +2209 5850 5851 6582 6581 +2210 5849 5850 6581 6580 +2211 5848 5849 6580 6579 +2212 5847 5848 6579 6578 +2213 5846 5847 6578 6577 +2214 5845 5846 6577 6576 +2215 5844 5845 6576 6575 +2216 5843 5844 6575 6574 +2217 5842 5843 6574 6573 +2218 5841 5842 6573 6572 +2219 5840 5841 6572 6571 +2220 5839 5840 6571 6570 +2221 5838 5839 6570 6569 +2222 5837 5838 6569 6568 +2223 5836 5837 6568 6567 +2224 5835 5836 6567 6566 +2225 5834 5835 6566 6565 +2226 5833 5834 6565 6564 +2227 5832 5833 6564 6563 +2228 5831 5832 6563 6562 +2229 5830 5831 6562 6561 +2230 5829 5830 6561 6560 +2231 5828 5829 6560 6559 +2232 5827 5828 6559 6558 +2233 5826 5827 6558 6557 +2234 5825 5826 6557 6556 +2235 5824 5825 6556 6555 +2236 5823 5824 6555 6554 +2237 5822 5823 6554 6553 +2238 5821 5822 6553 6552 +2239 5820 5821 6552 6551 +2240 5819 5820 6551 6550 +2241 5818 5819 6550 6549 +2242 5817 5818 6549 6548 +2243 5816 5817 6548 6547 +2244 5815 5816 6547 6546 +2245 5814 5815 6546 6545 +2246 5813 5814 6545 6544 +2247 5812 5813 6544 6543 +2248 5811 5812 6543 6258 +2249 5809 5810 6383 6542 +2250 5808 5809 6542 6541 +2251 5807 5808 6541 6540 +2252 5806 5807 6540 6539 +2253 5805 5806 6539 6538 +2254 5804 5805 6538 6537 +2255 5803 5804 6537 6536 +2256 5802 5803 6536 6535 +2257 5801 5802 6535 6534 +2258 5800 5801 6534 6533 +2259 5799 5800 6533 6532 +2260 5798 5799 6532 6531 +2261 5797 5798 6531 6530 +2262 5796 5797 6530 6529 +2263 5795 5796 6529 6528 +2264 5794 5795 6528 6527 +2265 5793 5794 6527 6526 +2266 5792 5793 6526 6525 +2267 5791 5792 6525 6524 +2268 5790 5791 6524 6523 +2269 5789 5790 6523 6522 +2270 5788 5789 6522 6521 +2271 5787 5788 6521 6520 +2272 5786 5787 6520 6519 +2273 5785 5786 6519 6518 +2274 5784 5785 6518 6517 +2275 5783 5784 6517 6516 +2276 5782 5783 6516 6515 +2277 5781 5782 6515 6514 +2278 5780 5781 6514 6513 +2279 5779 5780 6513 6512 +2280 5778 5779 6512 6511 +2281 5777 5778 6511 6510 +2282 5776 5777 6510 6509 +2283 5775 5776 6509 6508 +2284 5774 5775 6508 6507 +2285 5773 5774 6507 6506 +2286 5772 5773 6506 6505 +2287 5771 5772 6505 6504 +2288 5770 5771 6504 6503 +2289 5769 5770 6503 6502 +2290 5768 5769 6502 6501 +2291 5767 5768 6501 6500 +2292 5766 5767 6500 6499 +2293 5765 5766 6499 6498 +2294 5764 5765 6498 6497 +2295 5763 5764 6497 6496 +2296 5762 5763 6496 6495 +2297 5761 5762 6495 6494 +2298 5760 5761 6494 6493 +2299 5759 5760 6493 6492 +2300 5758 5759 6492 6491 +2301 5757 5758 6491 6490 +2302 5756 5757 6490 6489 +2303 5755 5756 6489 6488 +2304 5754 5755 6488 6487 +2305 5753 5754 6487 6486 +2306 5752 5753 6486 6485 +2307 5751 5752 6485 6484 +2308 5750 5751 6484 6483 +2309 5749 5750 6483 6482 +2310 5748 5749 6482 6481 +2311 5747 5748 6481 6480 +2312 5746 5747 6480 6479 +2313 5745 5746 6479 6478 +2314 5744 5745 6478 6477 +2315 5743 5744 6477 6476 +2316 5742 5743 6476 6475 +2317 5741 5742 6475 6474 +2318 5740 5741 6474 6473 +2319 5739 5740 6473 6472 +2320 5738 5739 6472 6471 +2321 5737 5738 6471 6470 +2322 5736 5737 6470 6469 +2323 5735 5736 6469 6468 +2324 5734 5735 6468 6467 +2325 5733 5734 6467 6466 +2326 5732 5733 6466 6465 +2327 5731 5732 6465 6464 +2328 5730 5731 6464 6463 +2329 5729 5730 6463 5891 +2330 5727 5728 6178 6462 +2331 5726 5727 6462 6461 +2332 5725 5726 6461 6460 +2333 5724 5725 6460 6459 +2334 5723 5724 6459 6458 +2335 5722 5723 6458 6457 +2336 5721 5722 6457 6456 +2337 5720 5721 6456 6455 +2338 5719 5720 6455 6454 +2339 5718 5719 6454 6453 +2340 5717 5718 6453 6452 +2341 5716 5717 6452 6451 +2342 5715 5716 6451 6450 +2343 5714 5715 6450 6449 +2344 5713 5714 6449 6448 +2345 5712 5713 6448 6447 +2346 5711 5712 6447 6446 +2347 5710 5711 6446 6445 +2348 5709 5710 6445 6444 +2349 5708 5709 6444 6443 +2350 5707 5708 6443 6442 +2351 5706 5707 6442 6441 +2352 5705 5706 6441 6440 +2353 5704 5705 6440 6439 +2354 5703 5704 6439 6438 +2355 5702 5703 6438 6437 +2356 5701 5702 6437 6436 +2357 5700 5701 6436 6435 +2358 5699 5700 6435 6434 +2359 5698 5699 6434 6433 +2360 5697 5698 6433 6432 +2361 5696 5697 6432 6431 +2362 5695 5696 6431 6430 +2363 5694 5695 6430 6429 +2364 5693 5694 6429 6428 +2365 5692 5693 6428 6427 +2366 5691 5692 6427 6426 +2367 5690 5691 6426 6425 +2368 5689 5690 6425 6424 +2369 5688 5689 6424 6423 +2370 5687 5688 6423 6422 +2371 5686 5687 6422 6421 +2372 5685 5686 6421 6420 +2373 5684 5685 6420 6419 +2374 5683 5684 6419 6418 +2375 5682 5683 6418 6417 +2376 5681 5682 6417 6416 +2377 5680 5681 6416 6415 +2378 5679 5680 6415 6414 +2379 5678 5679 6414 6413 +2380 5677 5678 6413 6412 +2381 5676 5677 6412 6411 +2382 5675 5676 6411 6410 +2383 5674 5675 6410 6409 +2384 5673 5674 6409 6408 +2385 5672 5673 6408 6407 +2386 5671 5672 6407 6406 +2387 5670 5671 6406 6405 +2388 5669 5670 6405 6404 +2389 5668 5669 6404 6403 +2390 5667 5668 6403 6402 +2391 5666 5667 6402 6401 +2392 5665 5666 6401 6400 +2393 5664 5665 6400 6399 +2394 5663 5664 6399 6398 +2395 5662 5663 6398 6397 +2396 5661 5662 6397 6396 +2397 5660 5661 6396 6395 +2398 5659 5660 6395 6394 +2399 5658 5659 6394 6393 +2400 5657 5658 6393 6392 +2401 5656 5657 6392 6391 +2402 5655 5656 6391 6390 +2403 5654 5655 6390 6389 +2404 5653 5654 6389 6388 +2405 5652 5653 6388 6387 +2406 5651 5652 6387 6386 +2407 5650 5651 6386 6385 +2408 5649 5650 6385 6384 +2409 5648 5649 6384 6383 +2410 5647 5648 6383 5810 +2411 4811 4812 6051 6382 +2412 4809 4811 6382 6381 +2413 4810 4809 6381 6379 +2414 4810 6379 6380 6378 +2415 4808 4810 6378 6377 +2416 4807 4808 6377 6376 +2417 4806 4807 6376 6375 +2418 4805 4806 6375 6374 +2419 4804 4805 6374 6373 +2420 4803 4804 6373 6371 +2421 6135 4802 4803 6371 +2422 6135 6371 6372 6370 +2423 6134 6135 6370 6369 +2424 6133 6134 6369 6368 +2425 6132 6133 6368 6367 +2426 6130 6132 6367 6366 +2427 6131 6130 6366 6364 +2428 6131 6364 6365 6363 +2429 6129 6131 6363 6362 +2430 6128 6129 6362 6361 +2431 6127 6128 6361 6360 +2432 6126 6127 6360 6359 +2433 6125 6126 6359 6358 +2434 6124 6125 6358 6123 +2435 6122 6123 6358 6357 +2436 6121 6122 6357 6356 +2437 6120 6121 6356 6355 +2438 6119 6120 6355 6354 +2439 6118 6119 6354 6353 +2440 6116 6118 6353 6352 +2441 6117 6116 6352 6350 +2442 6117 6350 6351 6349 +2443 6115 6117 6349 6348 +2444 6114 6115 6348 6347 +2445 6113 6114 6347 6346 +2446 6112 6113 6346 6345 +2447 6111 6112 6345 6344 +2448 5488 6111 6344 6343 +2449 5489 5488 6343 6342 +2450 6162 5489 6342 6341 +2451 6163 6162 6341 6339 +2452 6163 6339 6340 6338 +2453 5487 6163 6338 6337 +2454 5486 5487 6337 6336 +2455 5485 5486 6336 6335 +2456 5484 5485 6335 6334 +2457 5030 5484 6334 6333 +2458 5029 5030 6333 6332 +2459 5027 5029 6332 6331 +2460 5028 5027 6331 6329 +2461 5028 6329 6330 6328 +2462 5026 5028 6328 6327 +2463 5025 5026 6327 6326 +2464 5024 5025 6326 6325 +2465 5023 5024 6325 6324 +2466 5022 5023 6324 6323 +2467 5021 5022 6323 6322 +2468 5020 5021 6322 6321 +2469 5019 5020 6321 6320 +2470 5017 5019 6320 6319 +2471 5018 5017 6319 6318 +2472 6050 5018 6318 6317 +2473 6048 6050 6317 6316 +2474 6049 6048 6316 6314 +2475 6049 6314 6315 6313 +2476 4681 6049 6313 6312 +2477 6046 6047 6312 6311 +2478 6045 6046 6311 6310 +2479 6044 6045 6310 6309 +2480 6043 6044 6309 6308 +2481 6042 6043 6308 6307 +2482 6041 6042 6307 6306 +2483 6040 6041 6306 6305 +2484 6038 6040 6305 6215 +2485 6039 6038 6215 6216 +2486 6039 6216 6217 6304 +2487 6037 6039 6304 6303 +2488 6036 6037 6303 6302 +2489 6035 6036 6302 6301 +2490 6034 6035 6301 6300 +2491 6033 6034 6300 6299 +2492 6032 6033 6299 6298 +2493 6031 6032 6298 6297 +2494 6030 6031 6297 6296 +2495 6029 6030 6296 6295 +2496 6028 6029 6295 6294 +2497 6027 6028 6294 6293 +2498 6026 6027 6293 6292 +2499 6025 6026 6292 6291 +2500 6024 6025 6291 6290 +2501 6023 6024 6290 6289 +2502 6022 6023 6289 6288 +2503 6021 6022 6288 6287 +2504 6020 6021 6287 6286 +2505 6018 6020 6286 6285 +2506 6019 6018 6285 6284 +2507 6280 6019 6284 6282 +2508 6280 6282 6283 6281 +2509 6278 6280 6281 6279 +2510 6161 6278 6279 6277 +2511 6160 6161 6277 6275 +2512 6165 6164 6262 6276 +2513 6177 6159 6160 6275 +2514 6176 6177 6275 6274 +2515 6175 6176 6274 6273 +2516 6174 6175 6273 6272 +2517 6173 6174 6272 6271 +2518 6172 6173 6271 6270 +2519 6171 6172 6270 6269 +2520 6169 6171 6269 6268 +2521 6170 6169 6268 6266 +2522 6170 6266 6267 6265 +2523 6168 6170 6265 6264 +2524 6167 6168 6264 6263 +2525 6166 6167 6263 6261 +2526 6164 6166 6261 6262 +2527 5999 6259 6260 5998 +2528 5645 5646 5811 6258 +2529 5644 5645 6258 6257 +2530 5643 5644 6257 6256 +2531 5642 5643 6256 6255 +2532 5641 5642 6255 6254 +2533 5640 5641 6254 6253 +2534 5639 5640 6253 6252 +2535 5638 5639 6252 6251 +2536 5637 5638 6251 6250 +2537 5636 5637 6250 6249 +2538 5635 5636 6249 6248 +2539 5634 5635 6248 6247 +2540 5633 5634 6247 6246 +2541 5632 5633 6246 6245 +2542 5631 5632 6245 6244 +2543 5630 5631 6244 6243 +2544 5629 5630 6243 6242 +2545 5628 5629 6242 6241 +2546 5627 5628 6241 6240 +2547 5626 5627 6240 6239 +2548 5625 5626 6239 6238 +2549 5624 5625 6238 6237 +2550 5623 5624 6237 6236 +2551 5622 5623 6236 6235 +2552 5621 5622 6235 6234 +2553 5620 5621 6234 6233 +2554 5619 5620 6233 6232 +2555 5618 5619 6232 6231 +2556 5617 5618 6231 6230 +2557 5616 5617 6230 6229 +2558 5615 5616 6229 6228 +2559 5614 5615 6228 6227 +2560 5613 5614 6227 6226 +2561 5612 5613 6226 6225 +2562 5611 5612 6225 6224 +2563 5610 5611 6224 6223 +2564 5609 5610 6223 6222 +2565 5608 5609 6222 6221 +2566 5607 5608 6221 6220 +2567 5606 5607 6220 6219 +2568 5605 5606 6219 6218 +2569 5604 5605 6218 6217 +2570 5603 5604 6217 6216 +2571 5602 5603 6216 6215 +2572 5601 5602 6215 6214 +2573 5600 5601 6214 6213 +2574 5599 5600 6213 6212 +2575 5598 5599 6212 6211 +2576 5597 5598 6211 6210 +2577 5596 5597 6210 6209 +2578 5595 5596 6209 6208 +2579 5594 5595 6208 6207 +2580 5593 5594 6207 6206 +2581 5592 5593 6206 6205 +2582 5591 5592 6205 6204 +2583 5590 5591 6204 6203 +2584 5589 5590 6203 6202 +2585 5588 5589 6202 6201 +2586 5587 5588 6201 6200 +2587 5586 5587 6200 6199 +2588 5585 5586 6199 6198 +2589 5584 5585 6198 6197 +2590 5583 5584 6197 6196 +2591 5582 5583 6196 6195 +2592 5581 5582 6195 6194 +2593 5580 5581 6194 6193 +2594 5579 5580 6193 6192 +2595 5578 5579 6192 6191 +2596 5577 5578 6191 6190 +2597 5576 5577 6190 6189 +2598 5575 5576 6189 6188 +2599 5574 5575 6188 6187 +2600 5573 5574 6187 6186 +2601 5572 5573 6186 6185 +2602 5571 5572 6185 6184 +2603 5570 5571 6184 6183 +2604 5569 5570 6183 6182 +2605 5568 5569 6182 6181 +2606 5567 5568 6181 6180 +2607 5566 5567 6180 6179 +2608 5565 5566 6179 6178 +2609 5564 5565 6178 5728 +2610 6158 6159 6177 6157 +2611 6156 6157 6177 6176 +2612 6155 6156 6176 6175 +2613 6154 6155 6175 6174 +2614 6153 6154 6174 6173 +2615 6152 6153 6173 6172 +2616 6150 6152 6172 6171 +2617 6151 6150 6171 6169 +2618 6151 6169 6170 6168 +2619 6149 6151 6168 6167 +2620 6148 6149 6167 6166 +2621 6147 6148 6166 6164 +2622 6146 6147 6164 6165 +2623 5487 4700 6162 6163 +2624 4700 4701 5489 6162 +2625 6015 6016 6161 6160 +2626 6014 6015 6160 6159 +2627 6013 6014 6159 6158 +2628 6012 6013 6158 6157 +2629 6011 6012 6157 6156 +2630 6144 6011 6156 6155 +2631 6143 6144 6155 6154 +2632 6142 6143 6154 6153 +2633 6140 6142 6153 6152 +2634 6141 6140 6152 6150 +2635 6141 6150 6151 6149 +2636 6139 6141 6149 6148 +2637 6138 6139 6148 6147 +2638 6137 6138 6147 6146 +2639 6136 6137 6146 6145 +2640 6001 6136 6145 6000 +2641 6009 6010 6011 6144 +2642 6008 6009 6144 6143 +2643 6006 6008 6143 6142 +2644 6007 6006 6142 6140 +2645 6007 6140 6141 6139 +2646 6005 6007 6139 6138 +2647 6004 6005 6138 6137 +2648 6003 6004 6137 6136 +2649 6002 6003 6136 6001 +2650 4801 4802 6135 6134 +2651 4800 4801 6134 6133 +2652 4798 4800 6133 6132 +2653 4799 4798 6132 6130 +2654 4799 6130 6131 6129 +2655 4797 4799 6129 6128 +2656 4796 4797 6128 6127 +2657 4795 4796 6127 4794 +2658 4793 4794 6127 6126 +2659 4792 4793 6126 6125 +2660 4791 4792 6125 6124 +2661 4790 4791 6124 6123 +2662 4789 4790 6123 6122 +2663 4788 4789 6122 6121 +2664 4787 4788 6121 6120 +2665 4786 4787 6120 6119 +2666 4784 4786 6119 6118 +2667 4785 4784 6118 6116 +2668 4785 6116 6117 6115 +2669 4783 4785 6115 6114 +2670 4782 4783 6114 6113 +2671 4781 4782 6113 6112 +2672 4780 4781 6112 6111 +2673 4779 4780 6111 5488 +2674 5482 5481 5892 6109 +2675 5482 6109 6110 6108 +2676 5480 5482 6108 6107 +2677 5479 5480 6107 6106 +2678 5478 5479 6106 6105 +2679 5477 5478 6105 6104 +2680 5476 5477 6104 6103 +2681 5475 5476 6103 6102 +2682 5474 5475 6102 5472 +2683 5473 5472 6102 6100 +2684 5473 6100 6101 6099 +2685 5471 5473 6099 6098 +2686 5470 5471 6098 6097 +2687 5469 5470 6097 6096 +2688 5468 5469 6096 6095 +2689 5467 5468 6095 6094 +2690 5466 5467 6094 6093 +2691 5465 5466 6093 6092 +2692 5464 5465 6092 6091 +2693 5463 5464 6091 6090 +2694 5462 5463 6090 6089 +2695 5461 5462 6089 6088 +2696 5459 5461 6088 6087 +2697 5460 5459 6087 6085 +2698 5460 6085 6086 6084 +2699 5458 5460 6084 6083 +2700 5457 5458 6083 6082 +2701 5456 5457 6082 6081 +2702 5455 5456 6081 5454 +2703 5453 5454 6081 6080 +2704 5452 5453 6080 6079 +2705 5451 5452 6079 6078 +2706 5450 5451 6078 6077 +2707 5449 5450 6077 6076 +2708 5448 5449 6076 6075 +2709 5446 5448 6075 6074 +2710 5447 5446 6074 6072 +2711 5447 6072 6073 6071 +2712 5445 5447 6071 6070 +2713 5444 5445 6070 6069 +2714 5443 5444 6069 6068 +2715 5442 5443 6068 6067 +2716 5441 5442 6067 6066 +2717 5440 5441 6066 6065 +2718 5439 5440 6065 6064 +2719 5438 5439 6064 6063 +2720 5437 5438 6063 5436 +2721 5435 5436 6063 6062 +2722 5434 5435 6062 6061 +2723 5432 5434 6061 6060 +2724 5433 5432 6060 6058 +2725 5433 6058 6059 6057 +2726 5431 5433 6057 6056 +2727 5430 5431 6056 5429 +2728 5428 5429 6056 6055 +2729 5427 5428 6055 6054 +2730 5426 5427 6054 6053 +2731 5425 5426 6053 6052 +2732 5424 5425 6052 6051 +2733 4813 5424 6051 4812 +2734 4014 4013 5018 6050 +2735 4682 4014 6050 6048 +2736 4682 6048 6049 4681 +2737 4679 4680 6047 6046 +2738 4678 4679 6046 6045 +2739 4677 4678 6045 6044 +2740 4676 4677 6044 6043 +2741 4675 4676 6043 6042 +2742 4674 4675 6042 6041 +2743 4672 4674 6041 6040 +2744 4673 4672 6040 6038 +2745 4673 6038 6039 6037 +2746 4671 4673 6037 6036 +2747 4670 4671 6036 6035 +2748 4669 4670 6035 6034 +2749 4668 4669 6034 6033 +2750 4667 4668 6033 6032 +2751 5561 4667 6032 6031 +2752 5560 5561 6031 6030 +2753 5559 5560 6030 6029 +2754 5557 5559 6029 6028 +2755 5558 5557 6028 6027 +2756 5556 5558 6027 6026 +2757 5555 5556 6026 6025 +2758 5554 5555 6025 6024 +2759 5553 5554 6024 6023 +2760 5552 5553 6023 6022 +2761 5551 5552 6022 6021 +2762 5549 5551 6021 6020 +2763 5550 5549 6020 6018 +2764 5550 6018 6019 6017 +2765 5548 5550 6017 5547 +2766 5543 5544 6016 6015 +2767 5542 5543 6015 6014 +2768 5541 5542 6014 6013 +2769 5540 5541 6013 6012 +2770 5539 5540 6012 6011 +2771 5538 5539 6011 6010 +2772 5536 5537 5538 6010 +2773 5535 5536 6010 6009 +2774 5533 5535 6009 6008 +2775 5534 5533 6008 6006 +2776 5534 6006 6007 6005 +2777 5532 5534 6005 6004 +2778 5531 5532 6004 6003 +2779 5530 5531 6003 6002 +2780 5529 5530 6002 5528 +2781 5527 5528 6002 6001 +2782 5526 5527 6001 6000 +2783 5525 5526 6000 5999 +2784 5524 5525 5999 5998 +2785 5523 5524 5998 5997 +2786 5521 5523 5997 5996 +2787 5522 5521 5996 5995 +2788 5562 5522 5995 5994 +2789 5563 5562 5994 5992 +2790 5563 5992 5993 5991 +2791 5520 5563 5991 5990 +2792 5519 5520 5990 5989 +2793 5518 5519 5989 5988 +2794 5517 5518 5988 5987 +2795 5516 5517 5987 5986 +2796 5515 5516 5986 5985 +2797 5514 5515 5985 5984 +2798 5513 5514 5984 5983 +2799 5512 5513 5983 5982 +2800 5511 5512 5982 5981 +2801 5510 5511 5981 5980 +2802 5509 5510 5980 5507 +2803 5508 5507 5980 5978 +2804 5508 5978 5979 5976 +2805 5506 5508 5976 5977 +2806 5504 5505 5975 5974 +2807 5503 5504 5974 5502 +2808 4992 4991 5496 5972 +2809 4992 5972 5973 5971 +2810 4990 4992 5971 5970 +2811 4989 4990 5970 5969 +2812 4988 4989 5969 5968 +2813 4987 4988 5968 5967 +2814 4986 4987 5967 5966 +2815 4985 4986 5966 4984 +2816 4983 4984 5966 5965 +2817 4982 4983 5965 5964 +2818 4981 4982 5964 5963 +2819 4980 4981 5963 5962 +2820 4979 4980 5962 5961 +2821 4978 4979 5961 5960 +2822 4977 4978 5960 5959 +2823 4975 4977 5959 5958 +2824 4976 4975 5958 5956 +2825 4976 5956 5957 5955 +2826 4974 4976 5955 5954 +2827 4973 4974 5954 5953 +2828 4972 4973 5953 5952 +2829 4971 4972 5952 5951 +2830 4969 4971 5951 5950 +2831 4970 4969 5950 5949 +2832 4968 4970 5949 5948 +2833 4967 4968 5948 5947 +2834 4964 4965 5947 5946 +2835 4963 4964 5946 5945 +2836 4961 4963 5945 5944 +2837 4962 4961 5944 5942 +2838 4962 5942 5943 5941 +2839 4960 4962 5941 5940 +2840 4959 4960 5940 5939 +2841 4958 4959 5939 5938 +2842 4957 4958 5938 5937 +2843 4956 4957 5937 5936 +2844 4954 4956 5936 5935 +2845 4955 4954 5935 5934 +2846 5015 4955 5934 5933 +2847 5016 5015 5933 5931 +2848 5016 5931 5932 5930 +2849 4953 5016 5930 5929 +2850 4952 4953 5929 5928 +2851 4951 4952 5928 5927 +2852 4950 4951 5927 5926 +2853 4949 4950 5926 5925 +2854 4948 4949 5925 5924 +2855 4947 4948 5924 5923 +2856 4946 4947 5923 5922 +2857 4944 4946 5922 5921 +2858 4945 4944 5921 5919 +2859 4945 5919 5920 5918 +2860 4943 4945 5918 5917 +2861 4942 4943 5917 5916 +2862 4941 4942 5916 5915 +2863 4940 4941 5915 5914 +2864 4939 4940 5914 5913 +2865 4938 4939 5913 5912 +2866 4937 4938 5912 5911 +2867 4936 4937 5911 5910 +2868 4935 4936 5910 5909 +2869 4934 4935 5909 5908 +2870 4933 4934 5908 5907 +2871 4931 4933 5907 5906 +2872 4932 4931 5906 5904 +2873 4932 5904 5905 5903 +2874 4930 4932 5903 5902 +2875 4929 4930 5902 5901 +2876 4928 4929 5901 5900 +2877 4927 4928 5900 5899 +2878 4926 4927 5899 5898 +2879 5495 4926 5898 5897 +2880 5494 5495 5897 5896 +2881 5493 5494 5896 5895 +2882 5492 5493 5895 5894 +2883 5491 5492 5894 5893 +2884 5490 5491 5893 5892 +2885 5483 5490 5892 5481 +2886 5422 5423 5729 5891 +2887 5421 5422 5891 5890 +2888 5420 5421 5890 5889 +2889 5419 5420 5889 5888 +2890 5418 5419 5888 5887 +2891 5417 5418 5887 5886 +2892 5416 5417 5886 5885 +2893 5415 5416 5885 5884 +2894 5414 5415 5884 5883 +2895 5413 5414 5883 5882 +2896 5412 5413 5882 5881 +2897 5411 5412 5881 5880 +2898 5410 5411 5880 5879 +2899 5409 5410 5879 5878 +2900 5408 5409 5878 5877 +2901 5407 5408 5877 5876 +2902 5406 5407 5876 5875 +2903 5405 5406 5875 5874 +2904 5404 5405 5874 5873 +2905 5403 5404 5873 5872 +2906 5402 5403 5872 5871 +2907 5401 5402 5871 5870 +2908 5400 5401 5870 5869 +2909 5399 5400 5869 5868 +2910 5398 5399 5868 5867 +2911 5397 5398 5867 5866 +2912 5396 5397 5866 5865 +2913 5395 5396 5865 5864 +2914 5394 5395 5864 5863 +2915 5393 5394 5863 5862 +2916 5392 5393 5862 5861 +2917 5391 5392 5861 5860 +2918 5390 5391 5860 5859 +2919 5389 5390 5859 5858 +2920 5388 5389 5858 5857 +2921 5387 5388 5857 5856 +2922 5386 5387 5856 5855 +2923 5385 5386 5855 5854 +2924 5384 5385 5854 5853 +2925 5383 5384 5853 5852 +2926 5382 5383 5852 5851 +2927 5381 5382 5851 5850 +2928 5380 5381 5850 5849 +2929 5379 5380 5849 5848 +2930 5378 5379 5848 5847 +2931 5377 5378 5847 5846 +2932 5376 5377 5846 5845 +2933 5375 5376 5845 5844 +2934 5374 5375 5844 5843 +2935 5373 5374 5843 5842 +2936 5372 5373 5842 5841 +2937 5371 5372 5841 5840 +2938 5370 5371 5840 5839 +2939 5369 5370 5839 5838 +2940 5368 5369 5838 5837 +2941 5367 5368 5837 5836 +2942 5366 5367 5836 5835 +2943 5365 5366 5835 5834 +2944 5364 5365 5834 5833 +2945 5363 5364 5833 5832 +2946 5362 5363 5832 5831 +2947 5361 5362 5831 5830 +2948 5360 5361 5830 5829 +2949 5359 5360 5829 5828 +2950 5358 5359 5828 5827 +2951 5357 5358 5827 5826 +2952 5356 5357 5826 5825 +2953 5355 5356 5825 5824 +2954 5354 5355 5824 5823 +2955 5353 5354 5823 5822 +2956 5352 5353 5822 5821 +2957 5351 5352 5821 5820 +2958 5350 5351 5820 5819 +2959 5349 5350 5819 5818 +2960 5348 5349 5818 5817 +2961 5347 5348 5817 5816 +2962 5346 5347 5816 5815 +2963 5345 5346 5815 5814 +2964 5344 5345 5814 5813 +2965 5343 5344 5813 5812 +2966 5342 5343 5812 5811 +2967 5341 5342 5811 5646 +2968 5339 5340 5647 5810 +2969 5338 5339 5810 5809 +2970 5337 5338 5809 5808 +2971 5336 5337 5808 5807 +2972 5335 5336 5807 5806 +2973 5334 5335 5806 5805 +2974 5333 5334 5805 5804 +2975 5332 5333 5804 5803 +2976 5331 5332 5803 5802 +2977 5330 5331 5802 5801 +2978 5329 5330 5801 5800 +2979 5328 5329 5800 5799 +2980 5327 5328 5799 5798 +2981 5326 5327 5798 5797 +2982 5325 5326 5797 5796 +2983 5324 5325 5796 5795 +2984 5323 5324 5795 5794 +2985 5322 5323 5794 5793 +2986 5321 5322 5793 5792 +2987 5320 5321 5792 5791 +2988 5319 5320 5791 5790 +2989 5318 5319 5790 5789 +2990 5317 5318 5789 5788 +2991 5316 5317 5788 5787 +2992 5315 5316 5787 5786 +2993 5314 5315 5786 5785 +2994 5313 5314 5785 5784 +2995 5312 5313 5784 5783 +2996 5311 5312 5783 5782 +2997 5310 5311 5782 5781 +2998 5309 5310 5781 5780 +2999 5308 5309 5780 5779 +3000 5307 5308 5779 5778 +3001 5306 5307 5778 5777 +3002 5305 5306 5777 5776 +3003 5304 5305 5776 5775 +3004 5303 5304 5775 5774 +3005 5302 5303 5774 5773 +3006 5301 5302 5773 5772 +3007 5300 5301 5772 5771 +3008 5299 5300 5771 5770 +3009 5298 5299 5770 5769 +3010 5297 5298 5769 5768 +3011 5296 5297 5768 5767 +3012 5295 5296 5767 5766 +3013 5294 5295 5766 5765 +3014 5293 5294 5765 5764 +3015 5292 5293 5764 5763 +3016 5291 5292 5763 5762 +3017 5290 5291 5762 5761 +3018 5289 5290 5761 5760 +3019 5288 5289 5760 5759 +3020 5287 5288 5759 5758 +3021 5286 5287 5758 5757 +3022 5285 5286 5757 5756 +3023 5284 5285 5756 5755 +3024 5283 5284 5755 5754 +3025 5282 5283 5754 5753 +3026 5281 5282 5753 5752 +3027 5280 5281 5752 5751 +3028 5279 5280 5751 5750 +3029 5278 5279 5750 5749 +3030 5277 5278 5749 5748 +3031 5276 5277 5748 5747 +3032 5275 5276 5747 5746 +3033 5274 5275 5746 5745 +3034 5273 5274 5745 5744 +3035 5272 5273 5744 5743 +3036 5271 5272 5743 5742 +3037 5270 5271 5742 5741 +3038 5269 5270 5741 5740 +3039 5268 5269 5740 5739 +3040 5267 5268 5739 5738 +3041 5266 5267 5738 5737 +3042 5265 5266 5737 5736 +3043 5264 5265 5736 5735 +3044 5263 5264 5735 5734 +3045 5262 5263 5734 5733 +3046 5261 5262 5733 5732 +3047 5260 5261 5732 5731 +3048 5259 5260 5731 5730 +3049 5258 5259 5730 5729 +3050 5257 5258 5729 5423 +3051 5255 5256 5564 5728 +3052 5254 5255 5728 5727 +3053 5253 5254 5727 5726 +3054 5252 5253 5726 5725 +3055 5251 5252 5725 5724 +3056 5250 5251 5724 5723 +3057 5249 5250 5723 5722 +3058 5248 5249 5722 5721 +3059 5247 5248 5721 5720 +3060 5246 5247 5720 5719 +3061 5245 5246 5719 5718 +3062 5244 5245 5718 5717 +3063 5243 5244 5717 5716 +3064 5242 5243 5716 5715 +3065 5241 5242 5715 5714 +3066 5240 5241 5714 5713 +3067 5239 5240 5713 5712 +3068 5238 5239 5712 5711 +3069 5237 5238 5711 5710 +3070 5236 5237 5710 5709 +3071 5235 5236 5709 5708 +3072 5234 5235 5708 5707 +3073 5233 5234 5707 5706 +3074 5232 5233 5706 5705 +3075 5231 5232 5705 5704 +3076 5230 5231 5704 5703 +3077 5229 5230 5703 5702 +3078 5228 5229 5702 5701 +3079 5227 5228 5701 5700 +3080 5226 5227 5700 5699 +3081 5225 5226 5699 5698 +3082 5224 5225 5698 5697 +3083 5223 5224 5697 5696 +3084 5222 5223 5696 5695 +3085 5221 5222 5695 5694 +3086 5220 5221 5694 5693 +3087 5219 5220 5693 5692 +3088 5218 5219 5692 5691 +3089 5217 5218 5691 5690 +3090 5216 5217 5690 5689 +3091 5215 5216 5689 5688 +3092 5214 5215 5688 5687 +3093 5213 5214 5687 5686 +3094 5212 5213 5686 5685 +3095 5211 5212 5685 5684 +3096 5210 5211 5684 5683 +3097 5209 5210 5683 5682 +3098 5208 5209 5682 5681 +3099 5207 5208 5681 5680 +3100 5206 5207 5680 5679 +3101 5205 5206 5679 5678 +3102 5204 5205 5678 5677 +3103 5203 5204 5677 5676 +3104 5202 5203 5676 5675 +3105 5201 5202 5675 5674 +3106 5200 5201 5674 5673 +3107 5199 5200 5673 5672 +3108 5198 5199 5672 5671 +3109 5197 5198 5671 5670 +3110 5196 5197 5670 5669 +3111 5195 5196 5669 5668 +3112 5194 5195 5668 5667 +3113 5193 5194 5667 5666 +3114 5192 5193 5666 5665 +3115 5191 5192 5665 5664 +3116 5190 5191 5664 5663 +3117 5189 5190 5663 5662 +3118 5188 5189 5662 5661 +3119 5187 5188 5661 5660 +3120 5186 5187 5660 5659 +3121 5185 5186 5659 5658 +3122 5184 5185 5658 5657 +3123 5183 5184 5657 5656 +3124 5182 5183 5656 5655 +3125 5181 5182 5655 5654 +3126 5180 5181 5654 5653 +3127 5179 5180 5653 5652 +3128 5178 5179 5652 5651 +3129 5177 5178 5651 5650 +3130 5176 5177 5650 5649 +3131 5175 5176 5649 5648 +3132 5174 5175 5648 5647 +3133 5173 5174 5647 5340 +3134 5114 5115 5341 5646 +3135 5113 5114 5646 5645 +3136 5112 5113 5645 5644 +3137 5111 5112 5644 5643 +3138 5110 5111 5643 5642 +3139 5109 5110 5642 5641 +3140 5108 5109 5641 5640 +3141 5107 5108 5640 5639 +3142 5106 5107 5639 5638 +3143 5105 5106 5638 5637 +3144 5104 5105 5637 5636 +3145 5103 5104 5636 5635 +3146 5102 5103 5635 5634 +3147 5101 5102 5634 5633 +3148 5100 5101 5633 5632 +3149 5099 5100 5632 5631 +3150 5098 5099 5631 5630 +3151 5097 5098 5630 5629 +3152 5096 5097 5629 5628 +3153 5095 5096 5628 5627 +3154 5094 5095 5627 5626 +3155 5093 5094 5626 5625 +3156 5092 5093 5625 5624 +3157 5091 5092 5624 5623 +3158 5090 5091 5623 5622 +3159 5089 5090 5622 5621 +3160 5088 5089 5621 5620 +3161 5087 5088 5620 5619 +3162 5086 5087 5619 5618 +3163 5085 5086 5618 5617 +3164 5084 5085 5617 5616 +3165 5083 5084 5616 5615 +3166 5082 5083 5615 5614 +3167 5081 5082 5614 5613 +3168 5080 5081 5613 5612 +3169 5079 5080 5612 5611 +3170 5078 5079 5611 5610 +3171 5077 5078 5610 5609 +3172 5076 5077 5609 5608 +3173 5075 5076 5608 5607 +3174 5074 5075 5607 5606 +3175 5073 5074 5606 5605 +3176 5072 5073 5605 5604 +3177 5071 5072 5604 5603 +3178 5070 5071 5603 5602 +3179 5069 5070 5602 5601 +3180 5068 5069 5601 5600 +3181 5067 5068 5600 5599 +3182 5066 5067 5599 5598 +3183 5065 5066 5598 5597 +3184 5064 5065 5597 5596 +3185 5063 5064 5596 5595 +3186 5062 5063 5595 5594 +3187 5061 5062 5594 5593 +3188 5060 5061 5593 5592 +3189 5059 5060 5592 5591 +3190 5058 5059 5591 5590 +3191 5057 5058 5590 5589 +3192 5056 5057 5589 5588 +3193 5055 5056 5588 5587 +3194 5054 5055 5587 5586 +3195 5053 5054 5586 5585 +3196 5052 5053 5585 5584 +3197 5051 5052 5584 5583 +3198 5050 5051 5583 5582 +3199 5049 5050 5582 5581 +3200 5048 5049 5581 5580 +3201 5047 5048 5580 5579 +3202 5046 5047 5579 5578 +3203 5045 5046 5578 5577 +3204 5044 5045 5577 5576 +3205 5043 5044 5576 5575 +3206 5042 5043 5575 5574 +3207 5041 5042 5574 5573 +3208 5040 5041 5573 5572 +3209 5039 5040 5572 5571 +3210 5038 5039 5571 5570 +3211 5037 5038 5570 5569 +3212 5036 5037 5569 5568 +3213 5035 5036 5568 5567 +3214 5034 5035 5567 5566 +3215 5033 5034 5566 5565 +3216 5032 5033 5565 5564 +3217 5031 5032 5564 5256 +3218 5520 5140 5562 5563 +3219 5140 5141 5522 5562 +3220 4925 4666 4667 5561 +3221 4924 4925 5561 5560 +3222 4923 4924 5560 5559 +3223 4922 4923 5559 5557 +3224 4921 4922 5557 5558 +3225 5171 5172 5556 5555 +3226 5170 5171 5555 5554 +3227 5169 5170 5554 5553 +3228 5168 5169 5553 5552 +3229 5166 5168 5552 5551 +3230 5167 5166 5551 5549 +3231 5167 5549 5550 5548 +3232 5165 5167 5548 5547 +3233 5164 5165 5547 5546 +3234 5163 5164 5546 5545 +3235 5162 5163 5545 5544 +3236 5161 5162 5544 5543 +3237 5160 5161 5543 5542 +3238 5159 5160 5542 5541 +3239 5158 5159 5541 5540 +3240 5157 5158 5540 5539 +3241 5156 5157 5539 5538 +3242 5155 5156 5538 5537 +3243 5154 5155 5537 5536 +3244 5152 5154 5536 5535 +3245 5153 5152 5535 5533 +3246 5153 5533 5534 5532 +3247 5151 5153 5532 5531 +3248 5150 5151 5531 5530 +3249 5149 5150 5530 5529 +3250 5148 5149 5529 5528 +3251 5147 5148 5528 5527 +3252 5146 5147 5527 5526 +3253 5145 5146 5526 5525 +3254 5144 5145 5525 5524 +3255 5143 5144 5524 5523 +3256 5142 5143 5523 5521 +3257 5141 5142 5521 5522 +3258 5139 5140 5520 5519 +3259 5138 5139 5519 5518 +3260 5137 5138 5518 5517 +3261 5136 5137 5517 5516 +3262 5135 5136 5516 5515 +3263 5134 5135 5515 5514 +3264 5133 5134 5514 5513 +3265 5132 5133 5513 5512 +3266 5131 5132 5512 5511 +3267 5130 5131 5511 5510 +3268 5128 5130 5510 5509 +3269 5129 5128 5509 5507 +3270 5129 5507 5508 5506 +3271 5127 5129 5506 5505 +3272 5126 5127 5505 5504 +3273 5125 5126 5504 5503 +3274 5124 5125 5503 5123 +3275 5122 5123 5503 5502 +3276 5121 5122 5502 5501 +3277 5120 5121 5501 5500 +3278 5119 5120 5500 5499 +3279 5118 5119 5499 5498 +3280 5117 5118 5498 5497 +3281 5116 5117 5497 5496 +3282 4993 5116 5496 4991 +3283 4915 4916 4926 5495 +3284 4914 4915 5495 5494 +3285 4913 4914 5494 5493 +3286 4912 4913 5493 5492 +3287 4911 4912 5492 5491 +3288 4910 4911 5491 5490 +3289 4909 4910 5490 5483 +3290 4702 4703 4779 5488 +3291 4701 4702 5488 5489 +3292 4699 4700 5487 5486 +3293 4698 4699 5486 5485 +3294 4697 4698 5485 5484 +3295 4696 4697 5484 5030 +3296 4906 4908 4909 5483 +3297 4907 4906 5483 5481 +3298 4907 5481 5482 5480 +3299 4905 4907 5480 5479 +3300 4904 4905 5479 5478 +3301 4903 4904 5478 5477 +3302 4902 4903 5477 5476 +3303 4901 4902 5476 5475 +3304 4899 4901 5475 5474 +3305 4900 4899 5474 5472 +3306 4900 5472 5473 5471 +3307 4898 4900 5471 5470 +3308 4897 4898 5470 5469 +3309 4896 4897 5469 5468 +3310 4895 4896 5468 5467 +3311 4894 4895 5467 5466 +3312 4893 4894 5466 5465 +3313 4892 4893 5465 5464 +3314 4890 4892 5464 5463 +3315 4891 4890 5463 5462 +3316 4917 4891 5462 5461 +3317 4918 4917 5461 5459 +3318 4918 5459 5460 5458 +3319 4889 4918 5458 5457 +3320 4888 4889 5457 5456 +3321 4887 4888 5456 5455 +3322 4886 4887 5455 5454 +3323 4885 4886 5454 5453 +3324 4884 4885 5453 5452 +3325 4883 4884 5452 5451 +3326 4882 4883 5451 5450 +3327 4881 4882 5450 5449 +3328 4879 4881 5449 5448 +3329 4880 4879 5448 5446 +3330 4880 5446 5447 5445 +3331 4878 4880 5445 5444 +3332 4877 4878 5444 5443 +3333 4876 4877 5443 5442 +3334 4875 4876 5442 5441 +3335 4874 4875 5441 5440 +3336 4873 4874 5440 5439 +3337 4872 4873 5439 5438 +3338 4871 4872 5438 5437 +3339 4870 4871 5437 5436 +3340 4869 4870 5436 5435 +3341 4867 4869 5435 5434 +3342 4868 4867 5434 5432 +3343 4868 5432 5433 5431 +3344 4866 4868 5431 5430 +3345 4865 4866 5430 5429 +3346 4864 4865 5429 5428 +3347 4863 4864 5428 5427 +3348 4862 4863 5427 5426 +3349 4861 4862 5426 5425 +3350 4860 4861 5425 5424 +3351 4814 4860 5424 4813 +3352 4664 4665 5257 5423 +3353 4663 4664 5423 5422 +3354 4662 4663 5422 5421 +3355 4661 4662 5421 5420 +3356 4660 4661 5420 5419 +3357 4659 4660 5419 5418 +3358 4658 4659 5418 5417 +3359 4657 4658 5417 5416 +3360 4656 4657 5416 5415 +3361 4655 4656 5415 5414 +3362 4654 4655 5414 5413 +3363 4653 4654 5413 5412 +3364 4652 4653 5412 5411 +3365 4651 4652 5411 5410 +3366 4650 4651 5410 5409 +3367 4649 4650 5409 5408 +3368 4648 4649 5408 5407 +3369 4647 4648 5407 5406 +3370 4646 4647 5406 5405 +3371 4645 4646 5405 5404 +3372 4644 4645 5404 5403 +3373 4643 4644 5403 5402 +3374 4642 4643 5402 5401 +3375 4641 4642 5401 5400 +3376 4640 4641 5400 5399 +3377 4639 4640 5399 5398 +3378 4638 4639 5398 5397 +3379 4637 4638 5397 5396 +3380 4636 4637 5396 5395 +3381 4635 4636 5395 5394 +3382 4634 4635 5394 5393 +3383 4633 4634 5393 5392 +3384 4632 4633 5392 5391 +3385 4631 4632 5391 5390 +3386 4630 4631 5390 5389 +3387 4629 4630 5389 5388 +3388 4628 4629 5388 5387 +3389 4627 4628 5387 5386 +3390 4626 4627 5386 5385 +3391 4625 4626 5385 5384 +3392 4624 4625 5384 5383 +3393 4623 4624 5383 5382 +3394 4622 4623 5382 5381 +3395 4621 4622 5381 5380 +3396 4620 4621 5380 5379 +3397 4619 4620 5379 5378 +3398 4618 4619 5378 5377 +3399 4617 4618 5377 5376 +3400 4616 4617 5376 5375 +3401 4615 4616 5375 5374 +3402 4614 4615 5374 5373 +3403 4613 4614 5373 5372 +3404 4612 4613 5372 5371 +3405 4611 4612 5371 5370 +3406 4610 4611 5370 5369 +3407 4609 4610 5369 5368 +3408 4608 4609 5368 5367 +3409 4607 4608 5367 5366 +3410 4606 4607 5366 5365 +3411 4605 4606 5365 5364 +3412 4604 4605 5364 5363 +3413 4603 4604 5363 5362 +3414 4602 4603 5362 5361 +3415 4601 4602 5361 5360 +3416 4600 4601 5360 5359 +3417 4599 4600 5359 5358 +3418 4598 4599 5358 5357 +3419 4597 4598 5357 5356 +3420 4596 4597 5356 5355 +3421 4595 4596 5355 5354 +3422 4594 4595 5354 5353 +3423 4593 4594 5353 5352 +3424 4592 4593 5352 5351 +3425 4591 4592 5351 5350 +3426 4590 4591 5350 5349 +3427 4589 4590 5349 5348 +3428 4588 4589 5348 5347 +3429 4587 4588 5347 5346 +3430 4586 4587 5346 5345 +3431 4585 4586 5345 5344 +3432 4584 4585 5344 5343 +3433 4583 4584 5343 5342 +3434 4582 4583 5342 5341 +3435 4581 4582 5341 5115 +3436 4579 4580 5173 5340 +3437 4578 4579 5340 5339 +3438 4577 4578 5339 5338 +3439 4576 4577 5338 5337 +3440 4575 4576 5337 5336 +3441 4574 4575 5336 5335 +3442 4573 4574 5335 5334 +3443 4572 4573 5334 5333 +3444 4571 4572 5333 5332 +3445 4570 4571 5332 5331 +3446 4569 4570 5331 5330 +3447 4568 4569 5330 5329 +3448 4567 4568 5329 5328 +3449 4566 4567 5328 5327 +3450 4565 4566 5327 5326 +3451 4564 4565 5326 5325 +3452 4563 4564 5325 5324 +3453 4562 4563 5324 5323 +3454 4561 4562 5323 5322 +3455 4560 4561 5322 5321 +3456 4559 4560 5321 5320 +3457 4558 4559 5320 5319 +3458 4557 4558 5319 5318 +3459 4556 4557 5318 5317 +3460 4555 4556 5317 5316 +3461 4554 4555 5316 5315 +3462 4553 4554 5315 5314 +3463 4552 4553 5314 5313 +3464 4551 4552 5313 5312 +3465 4550 4551 5312 5311 +3466 4549 4550 5311 5310 +3467 4548 4549 5310 5309 +3468 4547 4548 5309 5308 +3469 4546 4547 5308 5307 +3470 4545 4546 5307 5306 +3471 4544 4545 5306 5305 +3472 4543 4544 5305 5304 +3473 4542 4543 5304 5303 +3474 4541 4542 5303 5302 +3475 4540 4541 5302 5301 +3476 4539 4540 5301 5300 +3477 4538 4539 5300 5299 +3478 4537 4538 5299 5298 +3479 4536 4537 5298 5297 +3480 4535 4536 5297 5296 +3481 4534 4535 5296 5295 +3482 4533 4534 5295 5294 +3483 4532 4533 5294 5293 +3484 4531 4532 5293 5292 +3485 4530 4531 5292 5291 +3486 4529 4530 5291 5290 +3487 4528 4529 5290 5289 +3488 4527 4528 5289 5288 +3489 4526 4527 5288 5287 +3490 4525 4526 5287 5286 +3491 4524 4525 5286 5285 +3492 4523 4524 5285 5284 +3493 4522 4523 5284 5283 +3494 4521 4522 5283 5282 +3495 4520 4521 5282 5281 +3496 4519 4520 5281 5280 +3497 4518 4519 5280 5279 +3498 4517 4518 5279 5278 +3499 4516 4517 5278 5277 +3500 4515 4516 5277 5276 +3501 4514 4515 5276 5275 +3502 4513 4514 5275 5274 +3503 4512 4513 5274 5273 +3504 4511 4512 5273 5272 +3505 4510 4511 5272 5271 +3506 4509 4510 5271 5270 +3507 4508 4509 5270 5269 +3508 4507 4508 5269 5268 +3509 4506 4507 5268 5267 +3510 4505 4506 5267 5266 +3511 4504 4505 5266 5265 +3512 4503 4504 5265 5264 +3513 4502 4503 5264 5263 +3514 4501 4502 5263 5262 +3515 4500 4501 5262 5261 +3516 4499 4500 5261 5260 +3517 4498 4499 5260 5259 +3518 4497 4498 5259 5258 +3519 4496 4497 5258 5257 +3520 4495 4496 5257 4665 +3521 4261 4262 5031 5256 +3522 4260 4261 5256 5255 +3523 4259 4260 5255 5254 +3524 4258 4259 5254 5253 +3525 4257 4258 5253 5252 +3526 4256 4257 5252 5251 +3527 4255 4256 5251 5250 +3528 4254 4255 5250 5249 +3529 4253 4254 5249 5248 +3530 4252 4253 5248 5247 +3531 4251 4252 5247 5246 +3532 4250 4251 5246 5245 +3533 4249 4250 5245 5244 +3534 4248 4249 5244 5243 +3535 4247 4248 5243 5242 +3536 4246 4247 5242 5241 +3537 4245 4246 5241 5240 +3538 4244 4245 5240 5239 +3539 4243 4244 5239 5238 +3540 4242 4243 5238 5237 +3541 4241 4242 5237 5236 +3542 4240 4241 5236 5235 +3543 4239 4240 5235 5234 +3544 4238 4239 5234 5233 +3545 4237 4238 5233 5232 +3546 4236 4237 5232 5231 +3547 4235 4236 5231 5230 +3548 4234 4235 5230 5229 +3549 4233 4234 5229 5228 +3550 4232 4233 5228 5227 +3551 4231 4232 5227 5226 +3552 4230 4231 5226 5225 +3553 4229 4230 5225 5224 +3554 4228 4229 5224 5223 +3555 4227 4228 5223 5222 +3556 4226 4227 5222 5221 +3557 4225 4226 5221 5220 +3558 4224 4225 5220 5219 +3559 4223 4224 5219 5218 +3560 4222 4223 5218 5217 +3561 4221 4222 5217 5216 +3562 4220 4221 5216 5215 +3563 4219 4220 5215 5214 +3564 4218 4219 5214 5213 +3565 4217 4218 5213 5212 +3566 4216 4217 5212 5211 +3567 4215 4216 5211 5210 +3568 4214 4215 5210 5209 +3569 4213 4214 5209 5208 +3570 4212 4213 5208 5207 +3571 4211 4212 5207 5206 +3572 4210 4211 5206 5205 +3573 4209 4210 5205 5204 +3574 4208 4209 5204 5203 +3575 4207 4208 5203 5202 +3576 4206 4207 5202 5201 +3577 4205 4206 5201 5200 +3578 4204 4205 5200 5199 +3579 4203 4204 5199 5198 +3580 4202 4203 5198 5197 +3581 4201 4202 5197 5196 +3582 4200 4201 5196 5195 +3583 4199 4200 5195 5194 +3584 4198 4199 5194 5193 +3585 4197 4198 5193 5192 +3586 4196 4197 5192 5191 +3587 4195 4196 5191 5190 +3588 4194 4195 5190 5189 +3589 4193 4194 5189 5188 +3590 4192 4193 5188 5187 +3591 4191 4192 5187 5186 +3592 4190 4191 5186 5185 +3593 4189 4190 5185 5184 +3594 4188 4189 5184 5183 +3595 4187 4188 5183 5182 +3596 4186 4187 5182 5181 +3597 4185 4186 5181 5180 +3598 4184 4185 5180 5179 +3599 4183 4184 5179 5178 +3600 4182 4183 5178 5177 +3601 4181 4182 5177 5176 +3602 4180 4181 5176 5175 +3603 4179 4180 5175 5174 +3604 4178 4179 5174 5173 +3605 4177 4178 5173 4580 +3606 4487 4488 5172 5171 +3607 4486 4487 5171 5170 +3608 4485 4486 5170 5169 +3609 4483 4485 5169 5168 +3610 4484 4483 5168 5166 +3611 4484 5166 5167 5165 +3612 4482 4484 5165 5164 +3613 4481 4482 5164 5163 +3614 4480 4481 5163 5162 +3615 4479 4480 5162 5161 +3616 4478 4479 5161 5160 +3617 4477 4478 5160 5159 +3618 4476 4477 5159 5158 +3619 4475 4476 5158 5157 +3620 4474 4475 5157 5156 +3621 4473 4474 5156 5155 +3622 4471 4473 5155 5154 +3623 4472 4471 5154 5152 +3624 4472 5152 5153 5151 +3625 4470 4472 5151 5150 +3626 4469 4470 5150 5149 +3627 4468 4469 5149 5148 +3628 4467 4468 5148 5147 +3629 4466 4467 5147 5146 +3630 4465 4466 5146 5145 +3631 4464 4465 5145 5144 +3632 4463 4464 5144 5143 +3633 4462 4463 5143 5142 +3634 4461 4462 5142 5141 +3635 4460 4461 5141 5140 +3636 4459 4460 5140 5139 +3637 4458 4459 5139 5138 +3638 5014 4458 5138 5137 +3639 5013 5014 5137 5136 +3640 5012 5013 5136 5135 +3641 5011 5012 5135 5134 +3642 5010 5011 5134 5133 +3643 5009 5010 5133 5132 +3644 5008 5009 5132 5131 +3645 5006 5008 5131 5130 +3646 5007 5006 5130 5128 +3647 5007 5128 5129 5127 +3648 5005 5007 5127 5126 +3649 5004 5005 5126 5125 +3650 5003 5004 5125 5124 +3651 5002 5003 5124 5123 +3652 5001 5002 5123 5122 +3653 5000 5001 5122 5121 +3654 4999 5000 5121 5120 +3655 4998 4999 5120 5119 +3656 4997 4998 5119 5118 +3657 4996 4997 5118 5117 +3658 4995 4996 5117 5116 +3659 4994 4995 5116 4993 +3660 4456 4457 4581 5115 +3661 4455 4456 5115 5114 +3662 4454 4455 5114 5113 +3663 4453 4454 5113 5112 +3664 4452 4453 5112 5111 +3665 4451 4452 5111 5110 +3666 4450 4451 5110 5109 +3667 4449 4450 5109 5108 +3668 4448 4449 5108 5107 +3669 4447 4448 5107 5106 +3670 4446 4447 5106 5105 +3671 4445 4446 5105 5104 +3672 4444 4445 5104 5103 +3673 4443 4444 5103 5102 +3674 4442 4443 5102 5101 +3675 4441 4442 5101 5100 +3676 4440 4441 5100 5099 +3677 4439 4440 5099 5098 +3678 4438 4439 5098 5097 +3679 4437 4438 5097 5096 +3680 4436 4437 5096 5095 +3681 4435 4436 5095 5094 +3682 4434 4435 5094 5093 +3683 4433 4434 5093 5092 +3684 4432 4433 5092 5091 +3685 4431 4432 5091 5090 +3686 4430 4431 5090 5089 +3687 4429 4430 5089 5088 +3688 4428 4429 5088 5087 +3689 4427 4428 5087 5086 +3690 4426 4427 5086 5085 +3691 4425 4426 5085 5084 +3692 4424 4425 5084 5083 +3693 4423 4424 5083 5082 +3694 4422 4423 5082 5081 +3695 4421 4422 5081 5080 +3696 4420 4421 5080 5079 +3697 4419 4420 5079 5078 +3698 4418 4419 5078 5077 +3699 4417 4418 5077 5076 +3700 4416 4417 5076 5075 +3701 4415 4416 5075 5074 +3702 4414 4415 5074 5073 +3703 4413 4414 5073 5072 +3704 4412 4413 5072 5071 +3705 4411 4412 5071 5070 +3706 4410 4411 5070 5069 +3707 4409 4410 5069 5068 +3708 4408 4409 5068 5067 +3709 4407 4408 5067 5066 +3710 4406 4407 5066 5065 +3711 4405 4406 5065 5064 +3712 4404 4405 5064 5063 +3713 4403 4404 5063 5062 +3714 4402 4403 5062 5061 +3715 4401 4402 5061 5060 +3716 4400 4401 5060 5059 +3717 4399 4400 5059 5058 +3718 4398 4399 5058 5057 +3719 4397 4398 5057 5056 +3720 4396 4397 5056 5055 +3721 4395 4396 5055 5054 +3722 4394 4395 5054 5053 +3723 4393 4394 5053 5052 +3724 4392 4393 5052 5051 +3725 4391 4392 5051 5050 +3726 4390 4391 5050 5049 +3727 4389 4390 5049 5048 +3728 4388 4389 5048 5047 +3729 4387 4388 5047 5046 +3730 4386 4387 5046 5045 +3731 4385 4386 5045 5044 +3732 4384 4385 5044 5043 +3733 4383 4384 5043 5042 +3734 4382 4383 5042 5041 +3735 4381 4382 5041 5040 +3736 4380 4381 5040 5039 +3737 4379 4380 5039 5038 +3738 4378 4379 5038 5037 +3739 4377 4378 5037 5036 +3740 4376 4377 5036 5035 +3741 4375 4376 5035 5034 +3742 4374 4375 5034 5033 +3743 4373 4374 5033 5032 +3744 4372 4373 5032 5031 +3745 4263 4372 5031 4262 +3746 4694 4695 4696 5030 +3747 4692 4694 5030 5029 +3748 4693 4692 5029 5027 +3749 4693 5027 5028 5026 +3750 4691 4693 5026 5025 +3751 4690 4691 5025 5024 +3752 4689 4690 5024 5023 +3753 4688 4689 5023 5022 +3754 4687 4688 5022 5021 +3755 4686 4687 5021 5020 +3756 4685 4686 5020 5019 +3757 4683 4685 5019 5017 +3758 4684 4683 5017 5018 +3759 4953 4765 5015 5016 +3760 4765 4766 4955 5015 +3761 4370 4371 4458 5014 +3762 4369 4370 5014 5013 +3763 4368 4369 5013 5012 +3764 4367 4368 5012 5011 +3765 4366 4367 5011 5010 +3766 4365 4366 5010 5009 +3767 4363 4365 5009 5008 +3768 4364 4363 5008 5006 +3769 4364 5006 5007 5005 +3770 4362 4364 5005 5004 +3771 4361 4362 5004 5003 +3772 4360 4361 5003 5002 +3773 4359 4360 5002 5001 +3774 4358 4359 5001 5000 +3775 4357 4358 5000 4999 +3776 4356 4357 4999 4998 +3777 4355 4356 4998 4997 +3778 4354 4355 4997 4996 +3779 4353 4354 4996 4995 +3780 4352 4353 4995 4994 +3781 4350 4352 4994 4993 +3782 4351 4350 4993 4991 +3783 4351 4991 4992 4990 +3784 4349 4351 4990 4989 +3785 4348 4349 4989 4988 +3786 4347 4348 4988 4987 +3787 4346 4347 4987 4986 +3788 4345 4346 4986 4985 +3789 4344 4345 4985 4984 +3790 4343 4344 4984 4983 +3791 4342 4343 4983 4982 +3792 4341 4342 4982 4981 +3793 4340 4341 4981 4980 +3794 4339 4340 4980 4979 +3795 4338 4339 4979 4978 +3796 4336 4338 4978 4977 +3797 4337 4336 4977 4975 +3798 4337 4975 4976 4974 +3799 4335 4337 4974 4973 +3800 4334 4335 4973 4972 +3801 4333 4334 4972 4971 +3802 4331 4333 4971 4969 +3803 4332 4331 4969 4970 +3804 4777 4778 4968 4967 +3805 4776 4777 4967 4966 +3806 4775 4776 4966 4965 +3807 4774 4775 4965 4964 +3808 4772 4774 4964 4963 +3809 4773 4772 4963 4961 +3810 4773 4961 4962 4960 +3811 4771 4773 4960 4959 +3812 4770 4771 4959 4958 +3813 4769 4770 4958 4957 +3814 4768 4769 4957 4956 +3815 4767 4768 4956 4954 +3816 4766 4767 4954 4955 +3817 4764 4765 4953 4952 +3818 4763 4764 4952 4951 +3819 4762 4763 4951 4950 +3820 4761 4762 4950 4949 +3821 4760 4761 4949 4948 +3822 4759 4760 4948 4947 +3823 4757 4759 4947 4946 +3824 4758 4757 4946 4944 +3825 4758 4944 4945 4943 +3826 4756 4758 4943 4942 +3827 4755 4756 4942 4941 +3828 4849 4755 4941 4940 +3829 4848 4849 4940 4939 +3830 4847 4848 4939 4938 +3831 4846 4847 4938 4937 +3832 4845 4846 4937 4936 +3833 4844 4845 4936 4935 +3834 4843 4844 4935 4934 +3835 4841 4843 4934 4933 +3836 4842 4841 4933 4931 +3837 4842 4931 4932 4930 +3838 4840 4842 4930 4929 +3839 4839 4840 4929 4928 +3840 4838 4839 4928 4927 +3841 4836 4838 4927 4926 +3842 4837 4836 4926 4916 +3843 3824 3825 4666 4925 +3844 3823 3824 4925 4924 +3845 3822 3823 4924 4923 +3846 3821 3822 4923 4922 +3847 3820 3821 4922 4921 +3848 3819 3820 4921 4919 +3849 3818 3819 4919 4920 +3850 4889 3972 4917 4918 +3851 3972 3973 4891 4917 +3852 3993 3994 4837 4916 +3853 3992 3993 4916 4915 +3854 3991 3992 4915 4914 +3855 3990 3991 4914 4913 +3856 3989 3990 4913 4912 +3857 3988 3989 4912 4911 +3858 3987 3988 4911 4910 +3859 4175 3987 4910 4909 +3860 4176 4175 4909 4908 +3861 4859 4176 4908 4906 +3862 4859 4906 4907 4905 +3863 4858 4859 4905 4904 +3864 4857 4858 4904 4903 +3865 4856 4857 4903 4902 +3866 4854 4856 4902 4901 +3867 4855 4854 4901 4899 +3868 4855 4899 4900 4898 +3869 4853 4855 4898 4897 +3870 4852 4853 4897 4896 +3871 4851 4852 4896 4895 +3872 4850 4851 4895 4894 +3873 3976 4850 4894 4893 +3874 3975 3976 4893 4892 +3875 3974 3975 4892 4890 +3876 3973 3974 4890 4891 +3877 3971 3972 4889 4888 +3878 3970 3971 4888 4887 +3879 3969 3970 4887 4886 +3880 3968 3969 4886 4885 +3881 3967 3968 4885 4884 +3882 4835 3967 4884 4883 +3883 4834 4835 4883 4882 +3884 4832 4834 4882 4881 +3885 4833 4832 4881 4879 +3886 4833 4879 4880 4878 +3887 4831 4833 4878 4877 +3888 4830 4831 4877 4876 +3889 4829 4830 4876 4875 +3890 4828 4829 4875 4874 +3891 4827 4828 4874 4873 +3892 4826 4827 4873 4872 +3893 4825 4826 4872 4871 +3894 4824 4825 4871 4870 +3895 4822 4824 4870 4869 +3896 4823 4822 4869 4867 +3897 4823 4867 4868 4866 +3898 4821 4823 4866 4865 +3899 4820 4821 4865 4864 +3900 4819 4820 4864 4863 +3901 4818 4819 4863 4862 +3902 4817 4818 4862 4861 +3903 4816 4817 4861 4860 +3904 4815 4816 4860 4814 +3905 4173 4176 4859 4858 +3906 4172 4173 4858 4857 +3907 4170 4172 4857 4856 +3908 4171 4170 4856 4854 +3909 4171 4854 4855 4853 +3910 4169 4171 4853 4852 +3911 4168 4169 4852 4851 +3912 4167 4168 4851 4850 +3913 3977 4167 4850 3976 +3914 4753 4754 4755 4849 +3915 4752 4753 4849 4848 +3916 4751 4752 4848 4847 +3917 4750 4751 4847 4846 +3918 4749 4750 4846 4845 +3919 4270 4749 4845 4844 +3920 4268 4270 4844 4843 +3921 4269 4268 4843 4841 +3922 4269 4841 4842 4840 +3923 4267 4269 4840 4839 +3924 4266 4267 4839 4838 +3925 4265 4266 4838 4836 +3926 4264 4265 4836 4837 +3927 4494 3966 3967 4835 +3928 4492 4494 4835 4834 +3929 4493 4492 4834 4832 +3930 4493 4832 4833 4831 +3931 4491 4493 4831 4830 +3932 4490 4491 4830 4829 +3933 4489 4490 4829 4828 +3934 4746 4489 4828 4827 +3935 4744 4746 4827 4826 +3936 4745 4744 4826 4825 +3937 4747 4745 4825 4824 +3938 4748 4747 4824 4822 +3939 4748 4822 4823 4821 +3940 4743 4748 4821 4820 +3941 4742 4743 4820 4819 +3942 4741 4742 4819 4818 +3943 4740 4741 4818 4817 +3944 4738 4740 4817 4816 +3945 4739 4738 4816 4815 +3946 4736 4737 4815 4814 +3947 4735 4736 4814 4813 +3948 4734 4735 4813 4812 +3949 4732 4734 4812 4811 +3950 4733 4732 4811 4809 +3951 4733 4809 4810 4808 +3952 4731 4733 4808 4807 +3953 4730 4731 4807 4806 +3954 4729 4730 4806 4805 +3955 4728 4729 4805 4804 +3956 4727 4728 4804 4803 +3957 4726 4727 4803 4802 +3958 4725 4726 4802 4801 +3959 4724 4725 4801 4723 +3960 4721 4723 4801 4800 +3961 4722 4721 4800 4798 +3962 4722 4798 4799 4797 +3963 4720 4722 4797 4796 +3964 4719 4720 4796 4795 +3965 4718 4719 4795 4794 +3966 4717 4718 4794 4793 +3967 4716 4717 4793 4792 +3968 4715 4716 4792 4791 +3969 4714 4715 4791 4790 +3970 4713 4714 4790 4789 +3971 4712 4713 4789 4788 +3972 4711 4712 4788 4787 +3973 4709 4711 4787 4786 +3974 4710 4709 4786 4784 +3975 4710 4784 4785 4783 +3976 4708 4710 4783 4782 +3977 4707 4708 4782 4781 +3978 4706 4707 4781 4780 +3979 4705 4706 4780 4779 +3980 4704 4705 4779 4703 +3981 4061 4062 4778 4777 +3982 4059 4061 4777 4776 +3983 4060 4059 4776 4775 +3984 4067 4060 4775 4774 +3985 4068 4067 4774 4772 +3986 4068 4772 4773 4771 +3987 4058 4068 4771 4770 +3988 4057 4058 4770 4769 +3989 4056 4057 4769 4768 +3990 4055 4056 4768 4767 +3991 4054 4055 4767 4766 +3992 4053 4054 4766 4765 +3993 4052 4053 4765 4764 +3994 4051 4052 4764 4763 +3995 4050 4051 4763 4762 +3996 4048 4050 4762 4761 +3997 4049 4048 4761 4760 +3998 4069 4049 4760 4759 +3999 4070 4069 4759 4757 +4000 4070 4757 4758 4756 +4001 4047 4070 4756 4755 +4002 4046 4047 4755 4754 +4003 4045 4046 4754 4753 +4004 4044 4045 4753 4752 +4005 4043 4044 4752 4751 +4006 4042 4043 4751 4750 +4007 4041 4042 4750 4749 +4008 4040 4041 4749 4270 +4009 4743 3871 4747 4748 +4010 3871 3872 4745 4747 +4011 3874 3875 4489 4746 +4012 3873 3874 4746 4744 +4013 3872 3873 4744 4745 +4014 3870 3871 4743 4742 +4015 3869 3870 4742 4741 +4016 3868 3869 4741 4740 +4017 3867 3868 4740 4738 +4018 3866 3867 4738 4739 +4019 3863 3864 4737 4736 +4020 3862 3863 4736 4735 +4021 3860 3862 4735 4734 +4022 3861 3860 4734 4732 +4023 3861 4732 4733 4731 +4024 3859 3861 4731 4730 +4025 3858 3859 4730 4729 +4026 4315 3858 4729 4728 +4027 4314 4315 4728 4727 +4028 4313 4314 4727 4726 +4029 4312 4313 4726 4725 +4030 4311 4312 4725 4724 +4031 4309 4311 4724 4723 +4032 4310 4309 4723 4721 +4033 4310 4721 4722 4720 +4034 4308 4310 4720 4719 +4035 4307 4308 4719 4718 +4036 4306 4307 4718 4717 +4037 4305 4306 4717 4716 +4038 4304 4305 4716 4715 +4039 4303 4304 4715 4714 +4040 4302 4303 4714 4713 +4041 4301 4302 4713 4712 +4042 4299 4301 4712 4711 +4043 4300 4299 4711 4709 +4044 4300 4709 4710 4708 +4045 4298 4300 4708 4707 +4046 4297 4298 4707 4706 +4047 4296 4297 4706 4705 +4048 4295 4296 4705 4704 +4049 4037 4038 4704 4703 +4050 4036 4037 4703 4702 +4051 4035 4036 4702 4701 +4052 4034 4035 4701 4700 +4053 4033 4034 4700 4699 +4054 4032 4033 4699 4698 +4055 4031 4032 4698 4697 +4056 4030 4031 4697 4696 +4057 4029 4030 4696 4695 +4058 4028 4029 4695 4027 +4059 4026 4027 4695 4694 +4060 4025 4026 4694 4692 +4061 4023 4025 4692 4024 +4062 4024 4692 4693 4691 +4063 4022 4024 4691 4690 +4064 4021 4022 4690 4689 +4065 4020 4021 4689 4688 +4066 4019 4020 4688 4687 +4067 4018 4019 4687 4686 +4068 4017 4018 4686 4685 +4069 4016 4017 4685 4683 +4070 4015 4016 4683 4684 +4071 4011 4012 4682 4681 +4072 4010 4011 4681 4680 +4073 4009 4010 4680 4679 +4074 4008 4009 4679 4678 +4075 4007 4008 4678 4677 +4076 4006 4007 4677 4005 +4077 4004 4005 4677 4676 +4078 4003 4004 4676 4675 +4079 4001 4003 4675 4674 +4080 4002 4001 4674 4672 +4081 4002 4672 4673 4671 +4082 4000 4002 4671 4670 +4083 3999 4000 4670 4669 +4084 3998 3999 4669 4668 +4085 3996 3998 4668 4667 +4086 3997 3996 4667 4666 +4087 3826 3997 4666 3825 +4088 4165 4166 4495 4665 +4089 4164 4165 4665 4664 +4090 4163 4164 4664 4663 +4091 4162 4163 4663 4662 +4092 4161 4162 4662 4661 +4093 4160 4161 4661 4660 +4094 4159 4160 4660 4659 +4095 4158 4159 4659 4658 +4096 4157 4158 4658 4657 +4097 4156 4157 4657 4656 +4098 4155 4156 4656 4655 +4099 4154 4155 4655 4654 +4100 4153 4154 4654 4653 +4101 4152 4153 4653 4652 +4102 4151 4152 4652 4651 +4103 4150 4151 4651 4650 +4104 4149 4150 4650 4649 +4105 4148 4149 4649 4648 +4106 4147 4148 4648 4647 +4107 4146 4147 4647 4646 +4108 4145 4146 4646 4645 +4109 4144 4145 4645 4644 +4110 4143 4144 4644 4643 +4111 4142 4143 4643 4642 +4112 4141 4142 4642 4641 +4113 4140 4141 4641 4640 +4114 4139 4140 4640 4639 +4115 4138 4139 4639 4638 +4116 4137 4138 4638 4637 +4117 4136 4137 4637 4636 +4118 4135 4136 4636 4635 +4119 4134 4135 4635 4634 +4120 4133 4134 4634 4633 +4121 4132 4133 4633 4632 +4122 4131 4132 4632 4631 +4123 4130 4131 4631 4630 +4124 4129 4130 4630 4629 +4125 4128 4129 4629 4628 +4126 4127 4128 4628 4627 +4127 4126 4127 4627 4626 +4128 4125 4126 4626 4625 +4129 4124 4125 4625 4624 +4130 4123 4124 4624 4623 +4131 4122 4123 4623 4622 +4132 4121 4122 4622 4621 +4133 4120 4121 4621 4620 +4134 4119 4120 4620 4619 +4135 4118 4119 4619 4618 +4136 4117 4118 4618 4617 +4137 4116 4117 4617 4616 +4138 4115 4116 4616 4615 +4139 4114 4115 4615 4614 +4140 4113 4114 4614 4613 +4141 4112 4113 4613 4612 +4142 4111 4112 4612 4611 +4143 4110 4111 4611 4610 +4144 4109 4110 4610 4609 +4145 4108 4109 4609 4608 +4146 4107 4108 4608 4607 +4147 4106 4107 4607 4606 +4148 4105 4106 4606 4605 +4149 4104 4105 4605 4604 +4150 4103 4104 4604 4603 +4151 4102 4103 4603 4602 +4152 4101 4102 4602 4601 +4153 4100 4101 4601 4600 +4154 4099 4100 4600 4599 +4155 4098 4099 4599 4598 +4156 4097 4098 4598 4597 +4157 4096 4097 4597 4596 +4158 4095 4096 4596 4595 +4159 4094 4095 4595 4594 +4160 4093 4094 4594 4593 +4161 4092 4093 4593 4592 +4162 4091 4092 4592 4591 +4163 4090 4091 4591 4590 +4164 4089 4090 4590 4589 +4165 4088 4089 4589 4588 +4166 4087 4088 4588 4587 +4167 4086 4087 4587 4586 +4168 4085 4086 4586 4585 +4169 4084 4085 4585 4584 +4170 4083 4084 4584 4583 +4171 4082 4083 4583 4582 +4172 4081 4082 4582 4581 +4173 4080 4081 4581 4457 +4174 3769 3770 4177 4580 +4175 3768 3769 4580 4579 +4176 3767 3768 4579 4578 +4177 3766 3767 4578 4577 +4178 3765 3766 4577 4576 +4179 3764 3765 4576 4575 +4180 3763 3764 4575 4574 +4181 3762 3763 4574 4573 +4182 3761 3762 4573 4572 +4183 3760 3761 4572 4571 +4184 3759 3760 4571 4570 +4185 3758 3759 4570 4569 +4186 3757 3758 4569 4568 +4187 3756 3757 4568 4567 +4188 3755 3756 4567 4566 +4189 3754 3755 4566 4565 +4190 3753 3754 4565 4564 +4191 3752 3753 4564 4563 +4192 3751 3752 4563 4562 +4193 3750 3751 4562 4561 +4194 3749 3750 4561 4560 +4195 3748 3749 4560 4559 +4196 3747 3748 4559 4558 +4197 3746 3747 4558 4557 +4198 3745 3746 4557 4556 +4199 3744 3745 4556 4555 +4200 3743 3744 4555 4554 +4201 3742 3743 4554 4553 +4202 3741 3742 4553 4552 +4203 3740 3741 4552 4551 +4204 3739 3740 4551 4550 +4205 3738 3739 4550 4549 +4206 3737 3738 4549 4548 +4207 3736 3737 4548 4547 +4208 3735 3736 4547 4546 +4209 3734 3735 4546 4545 +4210 3733 3734 4545 4544 +4211 3732 3733 4544 4543 +4212 3731 3732 4543 4542 +4213 3730 3731 4542 4541 +4214 3729 3730 4541 4540 +4215 3728 3729 4540 4539 +4216 3727 3728 4539 4538 +4217 3726 3727 4538 4537 +4218 3725 3726 4537 4536 +4219 3724 3725 4536 4535 +4220 3723 3724 4535 4534 +4221 3722 3723 4534 4533 +4222 3721 3722 4533 4532 +4223 3720 3721 4532 4531 +4224 3719 3720 4531 4530 +4225 3718 3719 4530 4529 +4226 3717 3718 4529 4528 +4227 3716 3717 4528 4527 +4228 3715 3716 4527 4526 +4229 3714 3715 4526 4525 +4230 3713 3714 4525 4524 +4231 3712 3713 4524 4523 +4232 3711 3712 4523 4522 +4233 3710 3711 4522 4521 +4234 3709 3710 4521 4520 +4235 3708 3709 4520 4519 +4236 3707 3708 4519 4518 +4237 3706 3707 4518 4517 +4238 3705 3706 4517 4516 +4239 3704 3705 4516 4515 +4240 3703 3704 4515 4514 +4241 3702 3703 4514 4513 +4242 3701 3702 4513 4512 +4243 3700 3701 4512 4511 +4244 3699 3700 4511 4510 +4245 3698 3699 4510 4509 +4246 3697 3698 4509 4508 +4247 3696 3697 4508 4507 +4248 3695 3696 4507 4506 +4249 3694 3695 4506 4505 +4250 3693 3694 4505 4504 +4251 3692 3693 4504 4503 +4252 3691 3692 4503 4502 +4253 3690 3691 4502 4501 +4254 3689 3690 4501 4500 +4255 3688 3689 4500 4499 +4256 3687 3688 4499 4498 +4257 3686 3687 4498 4497 +4258 3685 3686 4497 4496 +4259 3684 3685 4496 4495 +4260 3683 3684 4495 4166 +4261 3410 3412 3966 4494 +4262 3411 3410 4494 4492 +4263 3411 4492 4493 4491 +4264 3409 3411 4491 4490 +4265 3408 3409 4490 4489 +4266 3407 3408 4489 3875 +4267 3811 3812 4488 4487 +4268 3810 3811 4487 4486 +4269 3808 3810 4486 4485 +4270 3809 3808 4485 4483 +4271 3809 4483 4484 4482 +4272 3807 3809 4482 4481 +4273 3806 3807 4481 4480 +4274 3805 3806 4480 4479 +4275 3804 3805 4479 4478 +4276 3803 3804 4478 4477 +4277 3802 3803 4477 4476 +4278 3800 3802 4476 4475 +4279 3801 3800 4475 4474 +4280 3816 3801 4474 4473 +4281 3817 3816 4473 4471 +4282 3817 4471 4472 4470 +4283 3799 3817 4470 4469 +4284 3798 3799 4469 4468 +4285 3797 3798 4468 4467 +4286 3796 3797 4467 4466 +4287 3795 3796 4466 4465 +4288 3794 3795 4465 4464 +4289 3793 3794 4464 4463 +4290 3792 3793 4463 4462 +4291 3791 3792 4462 4461 +4292 3790 3791 4461 4460 +4293 3789 3790 4460 4459 +4294 3771 3789 4459 4458 +4295 3772 3771 4458 4371 +4296 3964 3965 4080 4457 +4297 3963 3964 4457 4456 +4298 3962 3963 4456 4455 +4299 3961 3962 4455 4454 +4300 3960 3961 4454 4453 +4301 3959 3960 4453 4452 +4302 3958 3959 4452 4451 +4303 3957 3958 4451 4450 +4304 3956 3957 4450 4449 +4305 3955 3956 4449 4448 +4306 3954 3955 4448 4447 +4307 3953 3954 4447 4446 +4308 3952 3953 4446 4445 +4309 3951 3952 4445 4444 +4310 3950 3951 4444 4443 +4311 3949 3950 4443 4442 +4312 3948 3949 4442 4441 +4313 3947 3948 4441 4440 +4314 3946 3947 4440 4439 +4315 3945 3946 4439 4438 +4316 3944 3945 4438 4437 +4317 3943 3944 4437 4436 +4318 3942 3943 4436 4435 +4319 3941 3942 4435 4434 +4320 3940 3941 4434 4433 +4321 3939 3940 4433 4432 +4322 3938 3939 4432 4431 +4323 3937 3938 4431 4430 +4324 3936 3937 4430 4429 +4325 3935 3936 4429 4428 +4326 3934 3935 4428 4427 +4327 3933 3934 4427 4426 +4328 3932 3933 4426 4425 +4329 3931 3932 4425 4424 +4330 3930 3931 4424 4423 +4331 3929 3930 4423 4422 +4332 3928 3929 4422 4421 +4333 3927 3928 4421 4420 +4334 3926 3927 4420 4419 +4335 3925 3926 4419 4418 +4336 3924 3925 4418 4417 +4337 3923 3924 4417 4416 +4338 3922 3923 4416 4415 +4339 3921 3922 4415 4414 +4340 3920 3921 4414 4413 +4341 3919 3920 4413 4412 +4342 3918 3919 4412 4411 +4343 3917 3918 4411 4410 +4344 3916 3917 4410 4409 +4345 3915 3916 4409 4408 +4346 3914 3915 4408 4407 +4347 3913 3914 4407 4406 +4348 3912 3913 4406 4405 +4349 3911 3912 4405 4404 +4350 3910 3911 4404 4403 +4351 3909 3910 4403 4402 +4352 3908 3909 4402 4401 +4353 3907 3908 4401 4400 +4354 3906 3907 4400 4399 +4355 3905 3906 4399 4398 +4356 3904 3905 4398 4397 +4357 3903 3904 4397 4396 +4358 3902 3903 4396 4395 +4359 3901 3902 4395 4394 +4360 3900 3901 4394 4393 +4361 3899 3900 4393 4392 +4362 3898 3899 4392 4391 +4363 3897 3898 4391 4390 +4364 3896 3897 4390 4389 +4365 3895 3896 4389 4388 +4366 3894 3895 4388 4387 +4367 3893 3894 4387 4386 +4368 3892 3893 4386 4385 +4369 3891 3892 4385 4384 +4370 3890 3891 4384 4383 +4371 3889 3890 4383 4382 +4372 3888 3889 4382 4381 +4373 3887 3888 4381 4380 +4374 3886 3887 4380 4379 +4375 3885 3886 4379 4378 +4376 3884 3885 4378 4377 +4377 3883 3884 4377 4376 +4378 3882 3883 4376 4375 +4379 3881 3882 4375 4374 +4380 3880 3881 4374 4373 +4381 3879 3880 4373 4372 +4382 3878 3879 4372 4263 +4383 4294 3011 3012 3772 +4384 4293 4294 3772 4371 +4385 4292 4293 4371 4370 +4386 4291 4292 4370 4369 +4387 4290 4291 4369 4368 +4388 4288 4290 4368 4367 +4389 4289 4288 4367 4366 +4390 4327 4289 4366 4365 +4391 4328 4327 4365 4363 +4392 4328 4363 4364 4362 +4393 4287 4328 4362 4361 +4394 4286 4287 4361 4360 +4395 4285 4286 4360 4359 +4396 4284 4285 4359 4358 +4397 4283 4284 4358 4357 +4398 4282 4283 4357 4356 +4399 4281 4282 4356 4355 +4400 4279 4281 4355 4354 +4401 4280 4279 4354 4353 +4402 4329 4280 4353 4352 +4403 4330 4329 4352 4350 +4404 4330 4350 4351 4349 +4405 4278 4330 4349 4348 +4406 4277 4278 4348 4347 +4407 4276 4277 4347 4346 +4408 4275 4276 4346 4345 +4409 4274 4275 4345 4344 +4410 4273 4274 4344 4343 +4411 4271 4273 4343 4342 +4412 4272 4271 4342 4341 +4413 4326 4272 4341 4340 +4414 4325 4326 4340 4324 +4415 4323 4324 4340 4339 +4416 4321 4323 4339 4338 +4417 4322 4321 4338 4336 +4418 4322 4336 4337 4335 +4419 4320 4322 4335 4334 +4420 4319 4320 4334 4333 +4421 4318 4319 4333 4331 +4422 4316 4318 4331 4332 +4423 3490 3491 3492 4079 +4424 4278 3499 4329 4330 +4425 3499 3500 4280 4329 +4426 4287 3508 4327 4328 +4427 3508 3509 4289 4327 +4428 4079 3492 4272 4326 +4429 4078 4079 4326 4325 +4430 4077 4078 4325 4324 +4431 4075 4077 4324 4323 +4432 4076 4075 4323 4321 +4433 4076 4321 4322 4320 +4434 4074 4076 4320 4319 +4435 4073 4074 4319 4318 +4436 4072 4073 4318 4316 +4437 4071 4072 4316 4317 +4438 3856 3857 3858 4315 +4439 3855 3856 4315 4314 +4440 3853 3855 4314 4313 +4441 3854 3853 4313 4312 +4442 3876 3854 4312 4311 +4443 3877 3876 4311 4309 +4444 3877 4309 4310 4308 +4445 3852 3877 4308 4307 +4446 3851 3852 4307 4306 +4447 3850 3851 4306 4305 +4448 3849 3850 4305 4304 +4449 3553 3849 4304 4303 +4450 3552 3553 4303 4302 +4451 3550 3552 4302 4301 +4452 3551 3550 4301 4299 +4453 3551 4299 4300 4298 +4454 3549 3551 4298 4297 +4455 3548 3549 4297 4296 +4456 3547 3548 4296 4295 +4457 3546 3547 4295 4039 +4458 3515 3008 3009 3010 +4459 3515 3010 3011 4294 +4460 3514 3515 4294 4293 +4461 3513 3514 4293 4292 +4462 3512 3513 4292 4291 +4463 3511 3512 4291 4290 +4464 3510 3511 4290 4288 +4465 3509 3510 4288 4289 +4466 3507 3508 4287 4286 +4467 3506 3507 4286 4285 +4468 3505 3506 4285 4284 +4469 3504 3505 4284 4283 +4470 3503 3504 4283 4282 +4471 3502 3503 4282 4281 +4472 3501 3502 4281 4279 +4473 3500 3501 4279 4280 +4474 3498 3499 4278 4277 +4475 3497 3498 4277 4276 +4476 3496 3497 4276 4275 +4477 3495 3496 4275 4274 +4478 3494 3495 4274 4273 +4479 3493 3494 4273 4271 +4480 3492 3493 4271 4272 +4481 3451 3453 4040 4270 +4482 3452 3451 4270 4268 +4483 3452 4268 4269 4267 +4484 3450 3452 4267 4266 +4485 3449 3450 4266 4265 +4486 3448 3449 4265 4264 +4487 3447 3448 4264 3995 +4488 3641 3642 3878 4263 +4489 3640 3641 4263 4262 +4490 3639 3640 4262 4261 +4491 3638 3639 4261 4260 +4492 3637 3638 4260 4259 +4493 3636 3637 4259 4258 +4494 3635 3636 4258 4257 +4495 3634 3635 4257 4256 +4496 3633 3634 4256 4255 +4497 3632 3633 4255 4254 +4498 3631 3632 4254 4253 +4499 3630 3631 4253 4252 +4500 3629 3630 4252 4251 +4501 3628 3629 4251 4250 +4502 3627 3628 4250 4249 +4503 3626 3627 4249 4248 +4504 3625 3626 4248 4247 +4505 3624 3625 4247 4246 +4506 3623 3624 4246 4245 +4507 3622 3623 4245 4244 +4508 3621 3622 4244 4243 +4509 3620 3621 4243 4242 +4510 3619 3620 4242 4241 +4511 3618 3619 4241 4240 +4512 3617 3618 4240 4239 +4513 3616 3617 4239 4238 +4514 3615 3616 4238 4237 +4515 3614 3615 4237 4236 +4516 3613 3614 4236 4235 +4517 3612 3613 4235 4234 +4518 3611 3612 4234 4233 +4519 3610 3611 4233 4232 +4520 3609 3610 4232 4231 +4521 3608 3609 4231 4230 +4522 3607 3608 4230 4229 +4523 3606 3607 4229 4228 +4524 3605 3606 4228 4227 +4525 3604 3605 4227 4226 +4526 3603 3604 4226 4225 +4527 3602 3603 4225 4224 +4528 3601 3602 4224 4223 +4529 3600 3601 4223 4222 +4530 3599 3600 4222 4221 +4531 3598 3599 4221 4220 +4532 3597 3598 4220 4219 +4533 3596 3597 4219 4218 +4534 3595 3596 4218 4217 +4535 3594 3595 4217 4216 +4536 3593 3594 4216 4215 +4537 3592 3593 4215 4214 +4538 3591 3592 4214 4213 +4539 3590 3591 4213 4212 +4540 3589 3590 4212 4211 +4541 3588 3589 4211 4210 +4542 3587 3588 4210 4209 +4543 3586 3587 4209 4208 +4544 3585 3586 4208 4207 +4545 3584 3585 4207 4206 +4546 3583 3584 4206 4205 +4547 3582 3583 4205 4204 +4548 3581 3582 4204 4203 +4549 3580 3581 4203 4202 +4550 3579 3580 4202 4201 +4551 3578 3579 4201 4200 +4552 3577 3578 4200 4199 +4553 3576 3577 4199 4198 +4554 3575 3576 4198 4197 +4555 3574 3575 4197 4196 +4556 3573 3574 4196 4195 +4557 3572 3573 4195 4194 +4558 3571 3572 4194 4193 +4559 3570 3571 4193 4192 +4560 3569 3570 4192 4191 +4561 3568 3569 4191 4190 +4562 3567 3568 4190 4189 +4563 3566 3567 4189 4188 +4564 3565 3566 4188 4187 +4565 3564 3565 4187 4186 +4566 3563 3564 4186 4185 +4567 3562 3563 4185 4184 +4568 3561 3562 4184 4183 +4569 3560 3561 4183 4182 +4570 3559 3560 4182 4181 +4571 3558 3559 4181 4180 +4572 3557 3558 4180 4179 +4573 3556 3557 4179 4178 +4574 3555 3556 4178 4177 +4575 3554 3555 4177 3770 +4576 4174 4175 4176 4173 +4577 3986 3987 4175 4174 +4578 3983 3984 4174 4173 +4579 3981 3983 4173 4172 +4580 3982 3981 4172 4170 +4581 3982 4170 4171 4169 +4582 3980 3982 4169 4168 +4583 3979 3980 4168 4167 +4584 3978 3979 4167 3977 +4585 3376 3377 3683 4166 +4586 3375 3376 4166 4165 +4587 3374 3375 4165 4164 +4588 3373 3374 4164 4163 +4589 3372 3373 4163 4162 +4590 3371 3372 4162 4161 +4591 3370 3371 4161 4160 +4592 3369 3370 4160 4159 +4593 3368 3369 4159 4158 +4594 3367 3368 4158 4157 +4595 3366 3367 4157 4156 +4596 3365 3366 4156 4155 +4597 3364 3365 4155 4154 +4598 3363 3364 4154 4153 +4599 3362 3363 4153 4152 +4600 3361 3362 4152 4151 +4601 3360 3361 4151 4150 +4602 3359 3360 4150 4149 +4603 3358 3359 4149 4148 +4604 3357 3358 4148 4147 +4605 3356 3357 4147 4146 +4606 3355 3356 4146 4145 +4607 3354 3355 4145 4144 +4608 3353 3354 4144 4143 +4609 3352 3353 4143 4142 +4610 3351 3352 4142 4141 +4611 3350 3351 4141 4140 +4612 3349 3350 4140 4139 +4613 3348 3349 4139 4138 +4614 3347 3348 4138 4137 +4615 3346 3347 4137 4136 +4616 3345 3346 4136 4135 +4617 3344 3345 4135 4134 +4618 3343 3344 4134 4133 +4619 3342 3343 4133 4132 +4620 3341 3342 4132 4131 +4621 3340 3341 4131 4130 +4622 3339 3340 4130 4129 +4623 3338 3339 4129 4128 +4624 3337 3338 4128 4127 +4625 3336 3337 4127 4126 +4626 3335 3336 4126 4125 +4627 3334 3335 4125 4124 +4628 3333 3334 4124 4123 +4629 3332 3333 4123 4122 +4630 3331 3332 4122 4121 +4631 3330 3331 4121 4120 +4632 3329 3330 4120 4119 +4633 3328 3329 4119 4118 +4634 3327 3328 4118 4117 +4635 3326 3327 4117 4116 +4636 3325 3326 4116 4115 +4637 3324 3325 4115 4114 +4638 3323 3324 4114 4113 +4639 3322 3323 4113 4112 +4640 3321 3322 4112 4111 +4641 3320 3321 4111 4110 +4642 3319 3320 4110 4109 +4643 3318 3319 4109 4108 +4644 3317 3318 4108 4107 +4645 3316 3317 4107 4106 +4646 3315 3316 4106 4105 +4647 3314 3315 4105 4104 +4648 3313 3314 4104 4103 +4649 3312 3313 4103 4102 +4650 3311 3312 4102 4101 +4651 3310 3311 4101 4100 +4652 3309 3310 4100 4099 +4653 3308 3309 4099 4098 +4654 3307 3308 4098 4097 +4655 3306 3307 4097 4096 +4656 3305 3306 4096 4095 +4657 3304 3305 4095 4094 +4658 3303 3304 4094 4093 +4659 3302 3303 4093 4092 +4660 3301 3302 4092 4091 +4661 3300 3301 4091 4090 +4662 3299 3300 4090 4089 +4663 3298 3299 4089 4088 +4664 3297 3298 4088 4087 +4665 3296 3297 4087 4086 +4666 3295 3296 4086 4085 +4667 3294 3295 4085 4084 +4668 3293 3294 4084 4083 +4669 3292 3293 4083 4082 +4670 3291 3292 4082 4081 +4671 3290 3291 4081 4080 +4672 3289 3290 4080 3965 +4673 3489 3490 4079 4078 +4674 3488 3489 4078 4077 +4675 3487 3488 4077 3485 +4676 3486 3485 4077 4075 +4677 3486 4075 4076 4074 +4678 3484 3486 4074 4073 +4679 3483 3484 4073 4072 +4680 3482 3483 4072 4071 +4681 3481 3482 4071 4066 +4682 4047 3462 4069 4070 +4683 3462 3463 4049 4069 +4684 4058 3473 4067 4068 +4685 3473 3474 4060 4067 +4686 3480 3481 4066 4065 +4687 3479 3480 4065 4064 +4688 3478 3479 4064 4063 +4689 3477 3478 4063 4062 +4690 3476 3477 4062 4061 +4691 3475 3476 4061 4059 +4692 3474 3475 4059 4060 +4693 3472 3473 4058 4057 +4694 3471 3472 4057 4056 +4695 3470 3471 4056 4055 +4696 3469 3470 4055 4054 +4697 3468 3469 4054 4053 +4698 3467 3468 4053 4052 +4699 3466 3467 4052 4051 +4700 3465 3466 4051 4050 +4701 3464 3465 4050 4048 +4702 3463 3464 4048 4049 +4703 3461 3462 4047 4046 +4704 3460 3461 4046 4045 +4705 3459 3460 4045 4044 +4706 3458 3459 4044 4043 +4707 3457 3458 4043 4042 +4708 3456 3457 4042 4041 +4709 3455 3456 4041 4040 +4710 3454 3455 4040 3453 +4711 3543 3544 4039 4038 +4712 3542 3543 4038 4037 +4713 3541 3542 4037 4036 +4714 3540 3541 4036 4035 +4715 3539 3540 4035 4034 +4716 3538 3539 4034 4033 +4717 3537 3538 4033 4032 +4718 3536 3537 4032 4031 +4719 3535 3536 4031 4030 +4720 3534 3535 4030 4029 +4721 3533 3534 4029 4028 +4722 3532 3533 4028 4027 +4723 3531 3532 4027 4026 +4724 3529 3531 4026 4025 +4725 3530 3529 4025 4023 +4726 3530 4023 4024 4022 +4727 3528 3530 4022 4021 +4728 3527 3528 4021 4020 +4729 3846 3527 4020 4019 +4730 3845 3846 4019 4018 +4731 3844 3845 4018 4017 +4732 3842 3844 4017 4016 +4733 3843 3842 4016 4015 +4734 3847 3843 4015 4013 +4735 3848 3847 4013 4014 +4736 3841 3848 4012 4011 +4737 3840 3841 4011 4010 +4738 3839 3840 4010 4009 +4739 3838 3839 4009 4008 +4740 3837 3838 4008 4007 +4741 3836 3837 4007 4006 +4742 3835 3836 4006 4005 +4743 3834 3835 4005 4004 +4744 3832 3834 4004 4003 +4745 3833 3832 4003 4001 +4746 3833 4001 4002 4000 +4747 3831 3833 4000 3999 +4748 3830 3831 3999 3998 +4749 3829 3830 3998 3996 +4750 3828 3829 3996 3997 +4751 3444 3445 3995 3994 +4752 3443 3444 3994 3993 +4753 3442 3443 3993 3992 +4754 3441 3442 3992 3991 +4755 3440 3441 3991 3990 +4756 3439 3440 3990 3989 +4757 3438 3439 3989 3988 +4758 3437 3438 3988 3987 +4759 3436 3437 3987 3986 +4760 3435 3436 3986 3985 +4761 3432 3433 3985 3984 +4762 3430 3432 3984 3983 +4763 3431 3430 3983 3981 +4764 3431 3981 3982 3980 +4765 3429 3431 3980 3979 +4766 3428 3429 3979 3978 +4767 3427 3428 3978 3426 +4768 3425 3426 3978 3977 +4769 3424 3425 3977 3976 +4770 3423 3424 3976 3975 +4771 3422 3423 3975 3974 +4772 3421 3422 3974 3973 +4773 3420 3421 3973 3972 +4774 3419 3420 3972 3971 +4775 3418 3419 3971 3970 +4776 3417 3418 3970 3969 +4777 3416 3417 3969 3968 +4778 3415 3416 3968 3967 +4779 3414 3415 3967 3966 +4780 3413 3414 3966 3412 +4781 3287 3288 3289 3965 +4782 3286 3287 3965 3964 +4783 3285 3286 3964 3963 +4784 3284 3285 3963 3962 +4785 3283 3284 3962 3961 +4786 3282 3283 3961 3960 +4787 3281 3282 3960 3959 +4788 3280 3281 3959 3958 +4789 3279 3280 3958 3957 +4790 3278 3279 3957 3956 +4791 3277 3278 3956 3955 +4792 3276 3277 3955 3954 +4793 3275 3276 3954 3953 +4794 3274 3275 3953 3952 +4795 3273 3274 3952 3951 +4796 3272 3273 3951 3950 +4797 3271 3272 3950 3949 +4798 3270 3271 3949 3948 +4799 3269 3270 3948 3947 +4800 3268 3269 3947 3946 +4801 3267 3268 3946 3945 +4802 3266 3267 3945 3944 +4803 3265 3266 3944 3943 +4804 3264 3265 3943 3942 +4805 3263 3264 3942 3941 +4806 3262 3263 3941 3940 +4807 3261 3262 3940 3939 +4808 3260 3261 3939 3938 +4809 3259 3260 3938 3937 +4810 3258 3259 3937 3936 +4811 3257 3258 3936 3935 +4812 3256 3257 3935 3934 +4813 3255 3256 3934 3933 +4814 3254 3255 3933 3932 +4815 3253 3254 3932 3931 +4816 3252 3253 3931 3930 +4817 3251 3252 3930 3929 +4818 3250 3251 3929 3928 +4819 3249 3250 3928 3927 +4820 3248 3249 3927 3926 +4821 3247 3248 3926 3925 +4822 3246 3247 3925 3924 +4823 3245 3246 3924 3923 +4824 3244 3245 3923 3922 +4825 3243 3244 3922 3921 +4826 3242 3243 3921 3920 +4827 3241 3242 3920 3919 +4828 3240 3241 3919 3918 +4829 3239 3240 3918 3917 +4830 3238 3239 3917 3916 +4831 3237 3238 3916 3915 +4832 3236 3237 3915 3914 +4833 3235 3236 3914 3913 +4834 3234 3235 3913 3912 +4835 3233 3234 3912 3911 +4836 3232 3233 3911 3910 +4837 3231 3232 3910 3909 +4838 3230 3231 3909 3908 +4839 3229 3230 3908 3907 +4840 3228 3229 3907 3906 +4841 3227 3228 3906 3905 +4842 3226 3227 3905 3904 +4843 3225 3226 3904 3903 +4844 3224 3225 3903 3902 +4845 3223 3224 3902 3901 +4846 3222 3223 3901 3900 +4847 3221 3222 3900 3899 +4848 3220 3221 3899 3898 +4849 3219 3220 3898 3897 +4850 3218 3219 3897 3896 +4851 3217 3218 3896 3895 +4852 3216 3217 3895 3894 +4853 3215 3216 3894 3893 +4854 3214 3215 3893 3892 +4855 3213 3214 3892 3891 +4856 3212 3213 3891 3890 +4857 3211 3212 3890 3889 +4858 3210 3211 3889 3888 +4859 3209 3210 3888 3887 +4860 3208 3209 3887 3886 +4861 3207 3208 3886 3885 +4862 3206 3207 3885 3884 +4863 3205 3206 3884 3883 +4864 3204 3205 3883 3882 +4865 3203 3204 3882 3881 +4866 3202 3203 3881 3880 +4867 3201 3202 3880 3879 +4868 3200 3201 3879 3878 +4869 3199 3200 3878 3642 +4870 3852 3382 3876 3877 +4871 3382 3383 3854 3876 +4872 3404 3405 3875 3874 +4873 3403 3404 3874 3873 +4874 3402 3403 3873 3872 +4875 3401 3402 3872 3871 +4876 3400 3401 3871 3870 +4877 3399 3400 3870 3869 +4878 3398 3399 3869 3868 +4879 3397 3398 3868 3867 +4880 3396 3397 3867 3866 +4881 3395 3396 3866 3865 +4882 3394 3395 3865 3864 +4883 3393 3394 3864 3863 +4884 3391 3393 3863 3862 +4885 3392 3391 3862 3860 +4886 3392 3860 3861 3859 +4887 3390 3392 3859 3858 +4888 3389 3390 3858 3857 +4889 3388 3389 3857 3387 +4890 3386 3387 3857 3856 +4891 3385 3386 3856 3855 +4892 3384 3385 3855 3853 +4893 3383 3384 3853 3854 +4894 3381 3382 3852 3851 +4895 3380 3381 3851 3850 +4896 3379 3380 3850 3849 +4897 3378 3379 3849 3553 +4898 3841 3520 3847 3848 +4899 3520 3521 3843 3847 +4900 3525 3526 3527 3846 +4901 3524 3525 3846 3845 +4902 3523 3524 3845 3844 +4903 3522 3523 3844 3842 +4904 3521 3522 3842 3843 +4905 3519 3520 3841 3840 +4906 3518 3519 3840 3839 +4907 3517 3518 3839 3838 +4908 3516 3517 3838 3837 +4909 3682 3516 3837 3836 +4910 3681 3682 3836 3835 +4911 3679 3681 3835 3834 +4912 3680 3679 3834 3832 +4913 3680 3832 3833 3831 +4914 3678 3680 3831 3830 +4915 3677 3678 3830 3829 +4916 3676 3677 3829 3828 +4917 3675 3676 3828 3827 +4918 3672 3673 3827 3826 +4919 3671 3672 3826 3825 +4920 3670 3671 3825 3824 +4921 3669 3670 3824 3823 +4922 3668 3669 3823 3822 +4923 3667 3668 3822 3821 +4924 3666 3667 3821 3820 +4925 3665 3666 3820 3819 +4926 3664 3665 3819 3818 +4927 3663 3664 3818 3815 +4928 3799 3783 3816 3817 +4929 3783 3784 3801 3816 +4930 3662 3663 3815 3814 +4931 3661 3662 3814 3813 +4932 3660 3661 3813 3812 +4933 3659 3660 3812 3811 +4934 3657 3659 3811 3810 +4935 3658 3657 3810 3808 +4936 3658 3808 3809 3807 +4937 3656 3658 3807 3806 +4938 3655 3656 3806 3805 +4939 3788 3655 3805 3804 +4940 3787 3788 3804 3803 +4941 3786 3787 3803 3802 +4942 3785 3786 3802 3800 +4943 3784 3785 3800 3801 +4944 3782 3783 3799 3798 +4945 3781 3782 3798 3797 +4946 3780 3781 3797 3796 +4947 3779 3780 3796 3795 +4948 3778 3779 3795 3794 +4949 3777 3778 3794 3793 +4950 3776 3777 3793 3792 +4951 3775 3776 3792 3791 +4952 3773 3775 3791 3790 +4953 3774 3773 3790 3789 +4954 3774 3789 3771 3014 +4955 3653 3654 3655 3788 +4956 3652 3653 3788 3787 +4957 3651 3652 3787 3786 +4958 3650 3651 3786 3785 +4959 3649 3650 3785 3784 +4960 3648 3649 3784 3783 +4961 3647 3648 3783 3782 +4962 3646 3647 3782 3781 +4963 3645 3646 3781 3780 +4964 3644 3645 3780 3779 +4965 3643 3644 3779 3778 +4966 3017 3643 3778 3777 +4967 3016 3017 3777 3776 +4968 3015 3016 3776 3775 +4969 3013 3015 3775 3773 +4970 3014 3013 3773 3774 +4971 3012 3014 3771 3772 +4972 3106 3107 3554 3770 +4973 3105 3106 3770 3769 +4974 3104 3105 3769 3768 +4975 3103 3104 3768 3767 +4976 3102 3103 3767 3766 +4977 3101 3102 3766 3765 +4978 3100 3101 3765 3764 +4979 3099 3100 3764 3763 +4980 3098 3099 3763 3762 +4981 3097 3098 3762 3761 +4982 3096 3097 3761 3760 +4983 3095 3096 3760 3759 +4984 3094 3095 3759 3758 +4985 3093 3094 3758 3757 +4986 3092 3093 3757 3756 +4987 3091 3092 3756 3755 +4988 3090 3091 3755 3754 +4989 3089 3090 3754 3753 +4990 3088 3089 3753 3752 +4991 3087 3088 3752 3751 +4992 3086 3087 3751 3750 +4993 3085 3086 3750 3749 +4994 3084 3085 3749 3748 +4995 3083 3084 3748 3747 +4996 3082 3083 3747 3746 +4997 3081 3082 3746 3745 +4998 3080 3081 3745 3744 +4999 3079 3080 3744 3743 +5000 3078 3079 3743 3742 +5001 3077 3078 3742 3741 +5002 3076 3077 3741 3740 +5003 3075 3076 3740 3739 +5004 3074 3075 3739 3738 +5005 3073 3074 3738 3737 +5006 3072 3073 3737 3736 +5007 3071 3072 3736 3735 +5008 3070 3071 3735 3734 +5009 3069 3070 3734 3733 +5010 3068 3069 3733 3732 +5011 3067 3068 3732 3731 +5012 3066 3067 3731 3730 +5013 3065 3066 3730 3729 +5014 3064 3065 3729 3728 +5015 3063 3064 3728 3727 +5016 3062 3063 3727 3726 +5017 3061 3062 3726 3725 +5018 3060 3061 3725 3724 +5019 3059 3060 3724 3723 +5020 3058 3059 3723 3722 +5021 3057 3058 3722 3721 +5022 3056 3057 3721 3720 +5023 3055 3056 3720 3719 +5024 3054 3055 3719 3718 +5025 3053 3054 3718 3717 +5026 3052 3053 3717 3716 +5027 3051 3052 3716 3715 +5028 3050 3051 3715 3714 +5029 3049 3050 3714 3713 +5030 3048 3049 3713 3712 +5031 3047 3048 3712 3711 +5032 3046 3047 3711 3710 +5033 3045 3046 3710 3709 +5034 3044 3045 3709 3708 +5035 3043 3044 3708 3707 +5036 3042 3043 3707 3706 +5037 3041 3042 3706 3705 +5038 3040 3041 3705 3704 +5039 3039 3040 3704 3703 +5040 3038 3039 3703 3702 +5041 3037 3038 3702 3701 +5042 3036 3037 3701 3700 +5043 3035 3036 3700 3699 +5044 3034 3035 3699 3698 +5045 3033 3034 3698 3697 +5046 3032 3033 3697 3696 +5047 3031 3032 3696 3695 +5048 3030 3031 3695 3694 +5049 3029 3030 3694 3693 +5050 3028 3029 3693 3692 +5051 3027 3028 3692 3691 +5052 3026 3027 3691 3690 +5053 3025 3026 3690 3689 +5054 3024 3025 3689 3688 +5055 3023 3024 3688 3687 +5056 3022 3023 3687 3686 +5057 3021 3022 3686 3685 +5058 3020 3021 3685 3684 +5059 3019 3020 3684 3683 +5060 3018 3019 3683 3377 +5061 2834 2835 3516 3682 +5062 2832 2834 3682 3681 +5063 2833 2832 3681 3679 +5064 2833 3679 3680 3678 +5065 2831 2833 3678 3677 +5066 2830 2831 3677 3676 +5067 2829 2830 3676 3675 +5068 2828 2829 3675 3674 +5069 2827 2828 3674 3673 +5070 2826 2827 3673 3672 +5071 2825 2826 3672 3671 +5072 2824 2825 3671 3670 +5073 2823 2824 3670 3669 +5074 2822 2823 3669 3668 +5075 2821 2822 3668 3667 +5076 2820 2821 3667 3666 +5077 2819 2820 3666 3665 +5078 2818 2819 3665 3664 +5079 2817 2818 3664 3663 +5080 2816 2817 3663 3662 +5081 2815 2816 3662 3661 +5082 2814 2815 3661 3660 +5083 2812 2814 3660 3659 +5084 2813 2812 3659 3657 +5085 2813 3657 3658 3656 +5086 2811 2813 3656 3655 +5087 2810 2811 3655 3654 +5088 2809 2810 3654 2808 +5089 2807 2808 3654 3653 +5090 2806 2807 3653 3652 +5091 2805 2806 3652 3651 +5092 2804 2805 3651 3650 +5093 2803 2804 3650 3649 +5094 2802 2803 3649 3648 +5095 2801 2802 3648 3647 +5096 2800 2801 3647 3646 +5097 2799 2800 3646 3645 +5098 2798 2799 3645 3644 +5099 2797 2798 3644 3643 +5100 2424 2797 3643 3017 +5101 3197 3198 3199 3642 +5102 3196 3197 3642 3641 +5103 3195 3196 3641 3640 +5104 3194 3195 3640 3639 +5105 3193 3194 3639 3638 +5106 3192 3193 3638 3637 +5107 3191 3192 3637 3636 +5108 3190 3191 3636 3635 +5109 3189 3190 3635 3634 +5110 3188 3189 3634 3633 +5111 3187 3188 3633 3632 +5112 3186 3187 3632 3631 +5113 3185 3186 3631 3630 +5114 3184 3185 3630 3629 +5115 3183 3184 3629 3628 +5116 3182 3183 3628 3627 +5117 3181 3182 3627 3626 +5118 3180 3181 3626 3625 +5119 3179 3180 3625 3624 +5120 3178 3179 3624 3623 +5121 3177 3178 3623 3622 +5122 3176 3177 3622 3621 +5123 3175 3176 3621 3620 +5124 3174 3175 3620 3619 +5125 3173 3174 3619 3618 +5126 3172 3173 3618 3617 +5127 3171 3172 3617 3616 +5128 3170 3171 3616 3615 +5129 3169 3170 3615 3614 +5130 3168 3169 3614 3613 +5131 3167 3168 3613 3612 +5132 3166 3167 3612 3611 +5133 3165 3166 3611 3610 +5134 3164 3165 3610 3609 +5135 3163 3164 3609 3608 +5136 3162 3163 3608 3607 +5137 3161 3162 3607 3606 +5138 3160 3161 3606 3605 +5139 3159 3160 3605 3604 +5140 3158 3159 3604 3603 +5141 3157 3158 3603 3602 +5142 3156 3157 3602 3601 +5143 3155 3156 3601 3600 +5144 3154 3155 3600 3599 +5145 3153 3154 3599 3598 +5146 3152 3153 3598 3597 +5147 3151 3152 3597 3596 +5148 3150 3151 3596 3595 +5149 3149 3150 3595 3594 +5150 3148 3149 3594 3593 +5151 3147 3148 3593 3592 +5152 3146 3147 3592 3591 +5153 3145 3146 3591 3590 +5154 3144 3145 3590 3589 +5155 3143 3144 3589 3588 +5156 3142 3143 3588 3587 +5157 3141 3142 3587 3586 +5158 3140 3141 3586 3585 +5159 3139 3140 3585 3584 +5160 3138 3139 3584 3583 +5161 3137 3138 3583 3582 +5162 3136 3137 3582 3581 +5163 3135 3136 3581 3580 +5164 3134 3135 3580 3579 +5165 3133 3134 3579 3578 +5166 3132 3133 3578 3577 +5167 3131 3132 3577 3576 +5168 3130 3131 3576 3575 +5169 3129 3130 3575 3574 +5170 3128 3129 3574 3573 +5171 3127 3128 3573 3572 +5172 3126 3127 3572 3571 +5173 3125 3126 3571 3570 +5174 3124 3125 3570 3569 +5175 3123 3124 3569 3568 +5176 3122 3123 3568 3567 +5177 3121 3122 3567 3566 +5178 3120 3121 3566 3565 +5179 3119 3120 3565 3564 +5180 3118 3119 3564 3563 +5181 3117 3118 3563 3562 +5182 3116 3117 3562 3561 +5183 3115 3116 3561 3560 +5184 3114 3115 3560 3559 +5185 3113 3114 3559 3558 +5186 3112 3113 3558 3557 +5187 3111 3112 3557 3556 +5188 3110 3111 3556 3555 +5189 3109 3110 3555 3554 +5190 3108 3109 3554 3107 +5191 2872 2873 3378 3553 +5192 2870 2872 3553 3552 +5193 2871 2870 3552 3550 +5194 2871 3550 3551 3549 +5195 2869 2871 3549 3548 +5196 2868 2869 3548 3547 +5197 2867 2868 3547 3546 +5198 2866 2867 3546 3545 +5199 2865 2866 3545 3544 +5200 2864 2865 3544 3543 +5201 2863 2864 3543 3542 +5202 2862 2863 3542 3541 +5203 2861 2862 3541 3540 +5204 2860 2861 3540 3539 +5205 2859 2860 3539 3538 +5206 2858 2859 3538 3537 +5207 2857 2858 3537 3536 +5208 2856 2857 3536 3535 +5209 2855 2856 3535 3534 +5210 2854 2855 3534 3533 +5211 2853 2854 3533 3532 +5212 2851 2853 3532 3531 +5213 2852 2851 3531 3529 +5214 2852 3529 3530 3528 +5215 2850 2852 3528 3527 +5216 2849 2850 3527 3526 +5217 2848 2849 3526 2847 +5218 2846 2847 3526 3525 +5219 2845 2846 3525 3524 +5220 2844 2845 3524 3523 +5221 2843 2844 3523 3522 +5222 2842 2843 3522 3521 +5223 2841 2842 3521 3520 +5224 2840 2841 3520 3519 +5225 2839 2840 3519 3518 +5226 2838 2839 3518 3517 +5227 2837 2838 3517 3516 +5228 2836 2837 3516 2835 +5229 3007 3008 3515 3514 +5230 3006 3007 3514 3513 +5231 3005 3006 3513 3512 +5232 3004 3005 3512 3511 +5233 3003 3004 3511 3510 +5234 3002 3003 3510 3509 +5235 3001 3002 3509 3508 +5236 3000 3001 3508 3507 +5237 2999 3000 3507 3506 +5238 2998 2999 3506 3505 +5239 2997 2998 3505 3504 +5240 2996 2997 3504 3503 +5241 2995 2996 3503 3502 +5242 2994 2995 3502 3501 +5243 2993 2994 3501 3500 +5244 2992 2993 3500 3499 +5245 2991 2992 3499 3498 +5246 2990 2991 3498 3497 +5247 2989 2990 3497 3496 +5248 2988 2989 3496 3495 +5249 2987 2988 3495 3494 +5250 2986 2987 3494 3493 +5251 2985 2986 3493 3492 +5252 2984 2985 3492 3491 +5253 2983 2984 3491 3490 +5254 2982 2983 3490 3489 +5255 2981 2982 3489 3488 +5256 2979 2981 3488 3487 +5257 2980 2979 3487 3485 +5258 2980 3485 3486 3484 +5259 2978 2980 3484 3483 +5260 2977 2978 3483 3482 +5261 2976 2977 3482 3481 +5262 2975 2976 3481 3480 +5263 2974 2975 3480 3479 +5264 2973 2974 3479 3478 +5265 2972 2973 3478 3477 +5266 2971 2972 3477 3476 +5267 2970 2971 3476 3475 +5268 2969 2970 3475 3474 +5269 2968 2969 3474 3473 +5270 2967 2968 3473 3472 +5271 2966 2967 3472 3471 +5272 2965 2966 3471 3470 +5273 2964 2965 3470 3469 +5274 2963 2964 3469 3468 +5275 2962 2963 3468 3467 +5276 2961 2962 3467 3466 +5277 2960 2961 3466 3465 +5278 2959 2960 3465 3464 +5279 2958 2959 3464 3463 +5280 2957 2958 3463 3462 +5281 2956 2957 3462 3461 +5282 2955 2956 3461 3460 +5283 2954 2955 3460 3459 +5284 2953 2954 3459 3458 +5285 2952 2953 3458 3457 +5286 2951 2952 3457 3456 +5287 2950 2951 3456 3455 +5288 2949 2950 3455 3454 +5289 2948 2949 3454 2947 +5290 2945 2947 3454 3453 +5291 2946 2945 3453 3451 +5292 2946 3451 3452 3450 +5293 2944 2946 3450 3449 +5294 2943 2944 3449 3448 +5295 2942 2943 3448 3447 +5296 2941 2942 3447 3446 +5297 2940 2941 3446 3445 +5298 2939 2940 3445 3444 +5299 2938 2939 3444 3443 +5300 2937 2938 3443 3442 +5301 2936 2937 3442 3441 +5302 2935 2936 3441 3440 +5303 2934 2935 3440 3439 +5304 2933 2934 3439 3438 +5305 2932 2933 3438 3437 +5306 2931 2932 3437 3436 +5307 2930 2931 3436 3435 +5308 2929 2930 3435 3434 +5309 2928 2929 3434 3433 +5310 2926 2928 3433 3432 +5311 2927 2926 3432 3430 +5312 2927 3430 3431 3429 +5313 2925 2927 3429 3428 +5314 2924 2925 3428 3427 +5315 2923 2924 3427 3426 +5316 2922 2923 3426 3425 +5317 2921 2922 3425 3424 +5318 2920 2921 3424 3423 +5319 2919 2920 3423 3422 +5320 2918 2919 3422 3421 +5321 2917 2918 3421 3420 +5322 2916 2917 3420 3419 +5323 2915 2916 3419 3418 +5324 2914 2915 3418 3417 +5325 2913 2914 3417 3416 +5326 2912 2913 3416 3415 +5327 2911 2912 3415 3414 +5328 2910 2911 3414 3413 +5329 2909 2910 3413 2908 +5330 2906 2908 3413 3412 +5331 2907 2906 3412 3410 +5332 2907 3410 3411 3409 +5333 2905 2907 3409 3408 +5334 2904 2905 3408 3407 +5335 2903 2904 3407 3406 +5336 2900 2901 3406 3405 +5337 2899 2900 3405 3404 +5338 2898 2899 3404 3403 +5339 2897 2898 3403 3402 +5340 2896 2897 3402 3401 +5341 2895 2896 3401 3400 +5342 2894 2895 3400 3399 +5343 2893 2894 3399 3398 +5344 2892 2893 3398 3397 +5345 2891 2892 3397 3396 +5346 2890 2891 3396 3395 +5347 2889 2890 3395 3394 +5348 2887 2889 3394 3393 +5349 2888 2887 3393 3391 +5350 2888 3391 3392 3390 +5351 2886 2888 3390 3389 +5352 2885 2886 3389 3388 +5353 2884 2885 3388 3387 +5354 2883 2884 3387 3386 +5355 2882 2883 3386 3385 +5356 2881 2882 3385 3384 +5357 2880 2881 3384 3383 +5358 2879 2880 3383 3382 +5359 2878 2879 3382 3381 +5360 2877 2878 3381 3380 +5361 2876 2877 3380 3379 +5362 2875 2876 3379 3378 +5363 2874 2875 3378 2873 +5364 2795 2796 3018 3377 +5365 2794 2795 3377 3376 +5366 2793 2794 3376 3375 +5367 2792 2793 3375 3374 +5368 2791 2792 3374 3373 +5369 2790 2791 3373 3372 +5370 2789 2790 3372 3371 +5371 2788 2789 3371 3370 +5372 2787 2788 3370 3369 +5373 2786 2787 3369 3368 +5374 2785 2786 3368 3367 +5375 2784 2785 3367 3366 +5376 2783 2784 3366 3365 +5377 2782 2783 3365 3364 +5378 2781 2782 3364 3363 +5379 2780 2781 3363 3362 +5380 2779 2780 3362 3361 +5381 2778 2779 3361 3360 +5382 2777 2778 3360 3359 +5383 2776 2777 3359 3358 +5384 2775 2776 3358 3357 +5385 2774 2775 3357 3356 +5386 2773 2774 3356 3355 +5387 2772 2773 3355 3354 +5388 2771 2772 3354 3353 +5389 2770 2771 3353 3352 +5390 2769 2770 3352 3351 +5391 2768 2769 3351 3350 +5392 2767 2768 3350 3349 +5393 2766 2767 3349 3348 +5394 2765 2766 3348 3347 +5395 2764 2765 3347 3346 +5396 2763 2764 3346 3345 +5397 2762 2763 3345 3344 +5398 2761 2762 3344 3343 +5399 2760 2761 3343 3342 +5400 2759 2760 3342 3341 +5401 2758 2759 3341 3340 +5402 2757 2758 3340 3339 +5403 2756 2757 3339 3338 +5404 2755 2756 3338 3337 +5405 2754 2755 3337 3336 +5406 2753 2754 3336 3335 +5407 2752 2753 3335 3334 +5408 2751 2752 3334 3333 +5409 2750 2751 3333 3332 +5410 2749 2750 3332 3331 +5411 2748 2749 3331 3330 +5412 2747 2748 3330 3329 +5413 2746 2747 3329 3328 +5414 2745 2746 3328 3327 +5415 2744 2745 3327 3326 +5416 2743 2744 3326 3325 +5417 2742 2743 3325 3324 +5418 2741 2742 3324 3323 +5419 2740 2741 3323 3322 +5420 2739 2740 3322 3321 +5421 2738 2739 3321 3320 +5422 2737 2738 3320 3319 +5423 2736 2737 3319 3318 +5424 2735 2736 3318 3317 +5425 2734 2735 3317 3316 +5426 2733 2734 3316 3315 +5427 2732 2733 3315 3314 +5428 2731 2732 3314 3313 +5429 2730 2731 3313 3312 +5430 2729 2730 3312 3311 +5431 2728 2729 3311 3310 +5432 2727 2728 3310 3309 +5433 2726 2727 3309 3308 +5434 2725 2726 3308 3307 +5435 2724 2725 3307 3306 +5436 2723 2724 3306 3305 +5437 2722 2723 3305 3304 +5438 2721 2722 3304 3303 +5439 2720 2721 3303 3302 +5440 2719 2720 3302 3301 +5441 2718 2719 3301 3300 +5442 2717 2718 3300 3299 +5443 2716 2717 3299 3298 +5444 2715 2716 3298 3297 +5445 2714 2715 3297 3296 +5446 2713 2714 3296 3295 +5447 2712 2713 3295 3294 +5448 2711 2712 3294 3293 +5449 2710 2711 3293 3292 +5450 2709 2710 3292 3291 +5451 2708 2709 3291 3290 +5452 2707 2708 3290 3289 +5453 2706 2707 3289 3288 +5454 2612 2613 2706 3288 +5455 2611 2612 3288 3287 +5456 2610 2611 3287 3286 +5457 2609 2610 3286 3285 +5458 2608 2609 3285 3284 +5459 2607 2608 3284 3283 +5460 2606 2607 3283 3282 +5461 2605 2606 3282 3281 +5462 2604 2605 3281 3280 +5463 2603 2604 3280 3279 +5464 2602 2603 3279 3278 +5465 2601 2602 3278 3277 +5466 2600 2601 3277 3276 +5467 2599 2600 3276 3275 +5468 2598 2599 3275 3274 +5469 2597 2598 3274 3273 +5470 2596 2597 3273 3272 +5471 2595 2596 3272 3271 +5472 2594 2595 3271 3270 +5473 2593 2594 3270 3269 +5474 2592 2593 3269 3268 +5475 2591 2592 3268 3267 +5476 2590 2591 3267 3266 +5477 2589 2590 3266 3265 +5478 2588 2589 3265 3264 +5479 2587 2588 3264 3263 +5480 2586 2587 3263 3262 +5481 2585 2586 3262 3261 +5482 2584 2585 3261 3260 +5483 2583 2584 3260 3259 +5484 2582 2583 3259 3258 +5485 2581 2582 3258 3257 +5486 2580 2581 3257 3256 +5487 2579 2580 3256 3255 +5488 2578 2579 3255 3254 +5489 2577 2578 3254 3253 +5490 2576 2577 3253 3252 +5491 2575 2576 3252 3251 +5492 2574 2575 3251 3250 +5493 2573 2574 3250 3249 +5494 2572 2573 3249 3248 +5495 2571 2572 3248 3247 +5496 2570 2571 3247 3246 +5497 2569 2570 3246 3245 +5498 2568 2569 3245 3244 +5499 2567 2568 3244 3243 +5500 2566 2567 3243 3242 +5501 2565 2566 3242 3241 +5502 2564 2565 3241 3240 +5503 2563 2564 3240 3239 +5504 2562 2563 3239 3238 +5505 2561 2562 3238 3237 +5506 2560 2561 3237 3236 +5507 2559 2560 3236 3235 +5508 2558 2559 3235 3234 +5509 2557 2558 3234 3233 +5510 2556 2557 3233 3232 +5511 2555 2556 3232 3231 +5512 2554 2555 3231 3230 +5513 2553 2554 3230 3229 +5514 2552 2553 3229 3228 +5515 2551 2552 3228 3227 +5516 2550 2551 3227 3226 +5517 2549 2550 3226 3225 +5518 2548 2549 3225 3224 +5519 2547 2548 3224 3223 +5520 2546 2547 3223 3222 +5521 2545 2546 3222 3221 +5522 2544 2545 3221 3220 +5523 2543 2544 3220 3219 +5524 2542 2543 3219 3218 +5525 2541 2542 3218 3217 +5526 2540 2541 3217 3216 +5527 2539 2540 3216 3215 +5528 2538 2539 3215 3214 +5529 2537 2538 3214 3213 +5530 2536 2537 3213 3212 +5531 2535 2536 3212 3211 +5532 2534 2535 3211 3210 +5533 2533 2534 3210 3209 +5534 2532 2533 3209 3208 +5535 2531 2532 3208 3207 +5536 2530 2531 3207 3206 +5537 2529 2530 3206 3205 +5538 2528 2529 3205 3204 +5539 2527 2528 3204 3203 +5540 2526 2527 3203 3202 +5541 2525 2526 3202 3201 +5542 2524 2525 3201 3200 +5543 2523 2524 3200 3199 +5544 2522 2523 3199 3198 +5545 2520 2521 2522 3198 +5546 2519 2520 3198 3197 +5547 2518 2519 3197 3196 +5548 2517 2518 3196 3195 +5549 2516 2517 3195 3194 +5550 2515 2516 3194 3193 +5551 2514 2515 3193 3192 +5552 2513 2514 3192 3191 +5553 2512 2513 3191 3190 +5554 2511 2512 3190 3189 +5555 2510 2511 3189 3188 +5556 2509 2510 3188 3187 +5557 2508 2509 3187 3186 +5558 2507 2508 3186 3185 +5559 2506 2507 3185 3184 +5560 2505 2506 3184 3183 +5561 2504 2505 3183 3182 +5562 2503 2504 3182 3181 +5563 2502 2503 3181 3180 +5564 2501 2502 3180 3179 +5565 2500 2501 3179 3178 +5566 2499 2500 3178 3177 +5567 2498 2499 3177 3176 +5568 2497 2498 3176 3175 +5569 2496 2497 3175 3174 +5570 2495 2496 3174 3173 +5571 2494 2495 3173 3172 +5572 2493 2494 3172 3171 +5573 2492 2493 3171 3170 +5574 2491 2492 3170 3169 +5575 2490 2491 3169 3168 +5576 2489 2490 3168 3167 +5577 2488 2489 3167 3166 +5578 2487 2488 3166 3165 +5579 2486 2487 3165 3164 +5580 2485 2486 3164 3163 +5581 2484 2485 3163 3162 +5582 2483 2484 3162 3161 +5583 2482 2483 3161 3160 +5584 2481 2482 3160 3159 +5585 2480 2481 3159 3158 +5586 2479 2480 3158 3157 +5587 2478 2479 3157 3156 +5588 2477 2478 3156 3155 +5589 2476 2477 3155 3154 +5590 2475 2476 3154 3153 +5591 2474 2475 3153 3152 +5592 2473 2474 3152 3151 +5593 2472 2473 3151 3150 +5594 2471 2472 3150 3149 +5595 2470 2471 3149 3148 +5596 2469 2470 3148 3147 +5597 2468 2469 3147 3146 +5598 2467 2468 3146 3145 +5599 2466 2467 3145 3144 +5600 2465 2466 3144 3143 +5601 2464 2465 3143 3142 +5602 2463 2464 3142 3141 +5603 2462 2463 3141 3140 +5604 2461 2462 3140 3139 +5605 2460 2461 3139 3138 +5606 2459 2460 3138 3137 +5607 2458 2459 3137 3136 +5608 2457 2458 3136 3135 +5609 2456 2457 3135 3134 +5610 2455 2456 3134 3133 +5611 2454 2455 3133 3132 +5612 2453 2454 3132 3131 +5613 2452 2453 3131 3130 +5614 2451 2452 3130 3129 +5615 2450 2451 3129 3128 +5616 2449 2450 3128 3127 +5617 2448 2449 3127 3126 +5618 2447 2448 3126 3125 +5619 2446 2447 3125 3124 +5620 2445 2446 3124 3123 +5621 2444 2445 3123 3122 +5622 2443 2444 3122 3121 +5623 2442 2443 3121 3120 +5624 2441 2442 3120 3119 +5625 2440 2441 3119 3118 +5626 2439 2440 3118 3117 +5627 2438 2439 3117 3116 +5628 2437 2438 3116 3115 +5629 2436 2437 3115 3114 +5630 2435 2436 3114 3113 +5631 2434 2435 3113 3112 +5632 2433 2434 3112 3111 +5633 2432 2433 3111 3110 +5634 2431 2432 3110 3109 +5635 2430 2431 3109 3108 +5636 2705 2429 2430 3108 +5637 2704 2705 3108 3107 +5638 2703 2704 3107 3106 +5639 2702 2703 3106 3105 +5640 2701 2702 3105 3104 +5641 2700 2701 3104 3103 +5642 2699 2700 3103 3102 +5643 2698 2699 3102 3101 +5644 2697 2698 3101 3100 +5645 2696 2697 3100 3099 +5646 2695 2696 3099 3098 +5647 2694 2695 3098 3097 +5648 2693 2694 3097 3096 +5649 2692 2693 3096 3095 +5650 2691 2692 3095 3094 +5651 2690 2691 3094 3093 +5652 2689 2690 3093 3092 +5653 2688 2689 3092 3091 +5654 2687 2688 3091 3090 +5655 2686 2687 3090 3089 +5656 2685 2686 3089 3088 +5657 2684 2685 3088 3087 +5658 2683 2684 3087 3086 +5659 2682 2683 3086 3085 +5660 2681 2682 3085 3084 +5661 2680 2681 3084 3083 +5662 2679 2680 3083 3082 +5663 2678 2679 3082 3081 +5664 2677 2678 3081 3080 +5665 2676 2677 3080 3079 +5666 2675 2676 3079 3078 +5667 2674 2675 3078 3077 +5668 2673 2674 3077 3076 +5669 2672 2673 3076 3075 +5670 2671 2672 3075 3074 +5671 2670 2671 3074 3073 +5672 2669 2670 3073 3072 +5673 2668 2669 3072 3071 +5674 2667 2668 3071 3070 +5675 2666 2667 3070 3069 +5676 2665 2666 3069 3068 +5677 2664 2665 3068 3067 +5678 2663 2664 3067 3066 +5679 2662 2663 3066 3065 +5680 2661 2662 3065 3064 +5681 2660 2661 3064 3063 +5682 2659 2660 3063 3062 +5683 2658 2659 3062 3061 +5684 2657 2658 3061 3060 +5685 2656 2657 3060 3059 +5686 2655 2656 3059 3058 +5687 2654 2655 3058 3057 +5688 2653 2654 3057 3056 +5689 2652 2653 3056 3055 +5690 2651 2652 3055 3054 +5691 2650 2651 3054 3053 +5692 2649 2650 3053 3052 +5693 2648 2649 3052 3051 +5694 2647 2648 3051 3050 +5695 2646 2647 3050 3049 +5696 2645 2646 3049 3048 +5697 2644 2645 3048 3047 +5698 2643 2644 3047 3046 +5699 2642 2643 3046 3045 +5700 2641 2642 3045 3044 +5701 2640 2641 3044 3043 +5702 2639 2640 3043 3042 +5703 2638 2639 3042 3041 +5704 2637 2638 3041 3040 +5705 2636 2637 3040 3039 +5706 2635 2636 3039 3038 +5707 2634 2635 3038 3037 +5708 2633 2634 3037 3036 +5709 2632 2633 3036 3035 +5710 2631 2632 3035 3034 +5711 2630 2631 3034 3033 +5712 2629 2630 3033 3032 +5713 2628 2629 3032 3031 +5714 2627 2628 3031 3030 +5715 2626 2627 3030 3029 +5716 2625 2626 3029 3028 +5717 2624 2625 3028 3027 +5718 2623 2624 3027 3026 +5719 2622 2623 3026 3025 +5720 2621 2622 3025 3024 +5721 2620 2621 3024 3023 +5722 2619 2620 3023 3022 +5723 2618 2619 3022 3021 +5724 2617 2618 3021 3020 +5725 2616 2617 3020 3019 +5726 2615 2616 3019 3018 +5727 2614 2615 3018 2796 +5728 2423 2424 3017 3016 +5729 2421 2423 3016 3015 +5730 2422 2421 3015 3013 +5731 2422 3013 3014 3012 +5732 2420 2422 3012 3011 +5733 2419 2420 3011 3010 +5734 2418 2419 3010 3009 +5735 2417 2418 3009 3008 +5736 2416 2417 3008 3007 +5737 2415 2416 3007 3006 +5738 2414 2415 3006 3005 +5739 2413 2414 3005 3004 +5740 2412 2413 3004 3003 +5741 2411 2412 3003 3002 +5742 2410 2411 3002 3001 +5743 2409 2410 3001 3000 +5744 2408 2409 3000 2999 +5745 2407 2408 2999 2998 +5746 2406 2407 2998 2997 +5747 2405 2406 2997 2996 +5748 2404 2405 2996 2995 +5749 2403 2404 2995 2994 +5750 2402 2403 2994 2993 +5751 2401 2402 2993 2992 +5752 2400 2401 2992 2991 +5753 2399 2400 2991 2990 +5754 2398 2399 2990 2989 +5755 2397 2398 2989 2988 +5756 2396 2397 2988 2987 +5757 2395 2396 2987 2986 +5758 2394 2395 2986 2985 +5759 2393 2394 2985 2984 +5760 2392 2393 2984 2983 +5761 2391 2392 2983 2982 +5762 2389 2391 2982 2981 +5763 2390 2389 2981 2979 +5764 2390 2979 2980 2978 +5765 2388 2390 2978 2977 +5766 2387 2388 2977 2976 +5767 2386 2387 2976 2975 +5768 2385 2386 2975 2974 +5769 2384 2385 2974 2973 +5770 2383 2384 2973 2972 +5771 2382 2383 2972 2971 +5772 2381 2382 2971 2970 +5773 2380 2381 2970 2969 +5774 2379 2380 2969 2968 +5775 2378 2379 2968 2967 +5776 2377 2378 2967 2966 +5777 2376 2377 2966 2965 +5778 2375 2376 2965 2964 +5779 2374 2375 2964 2963 +5780 2373 2374 2963 2962 +5781 2372 2373 2962 2961 +5782 2371 2372 2961 2960 +5783 2370 2371 2960 2959 +5784 2369 2370 2959 2958 +5785 2368 2369 2958 2957 +5786 2367 2368 2957 2956 +5787 2366 2367 2956 2955 +5788 2365 2366 2955 2954 +5789 2364 2365 2954 2953 +5790 2363 2364 2953 2952 +5791 2362 2363 2952 2951 +5792 2361 2362 2951 2950 +5793 2360 2361 2950 2949 +5794 2359 2360 2949 2948 +5795 2357 2359 2948 2947 +5796 2358 2357 2947 2945 +5797 2358 2945 2946 2944 +5798 2356 2358 2944 2943 +5799 2355 2356 2943 2942 +5800 2354 2355 2942 2941 +5801 2353 2354 2941 2940 +5802 2352 2353 2940 2939 +5803 2351 2352 2939 2938 +5804 2350 2351 2938 2937 +5805 2349 2350 2937 2936 +5806 2348 2349 2936 2935 +5807 2347 2348 2935 2934 +5808 2346 2347 2934 2933 +5809 2345 2346 2933 2932 +5810 2344 2345 2932 2931 +5811 2342 2344 2931 2930 +5812 2343 2342 2930 2929 +5813 2427 2343 2929 2928 +5814 2428 2427 2928 2926 +5815 2428 2926 2927 2925 +5816 2341 2428 2925 2924 +5817 2340 2341 2924 2923 +5818 2339 2340 2923 2922 +5819 2338 2339 2922 2921 +5820 2337 2338 2921 2920 +5821 2336 2337 2920 2919 +5822 2335 2336 2919 2918 +5823 2334 2335 2918 2917 +5824 2333 2334 2917 2916 +5825 2332 2333 2916 2915 +5826 2331 2332 2915 2914 +5827 2330 2331 2914 2913 +5828 2329 2330 2913 2912 +5829 2328 2329 2912 2911 +5830 2327 2328 2911 2910 +5831 2326 2327 2910 2909 +5832 2324 2326 2909 2908 +5833 2325 2324 2908 2906 +5834 2325 2906 2907 2905 +5835 2323 2325 2905 2904 +5836 2322 2323 2904 2903 +5837 2321 2322 2903 2902 +5838 2320 2321 2902 2901 +5839 2319 2320 2901 2900 +5840 2318 2319 2900 2899 +5841 2317 2318 2899 2898 +5842 2316 2317 2898 2897 +5843 2315 2316 2897 2896 +5844 2314 2315 2896 2895 +5845 2313 2314 2895 2894 +5846 2312 2313 2894 2893 +5847 2311 2312 2893 2892 +5848 2309 2311 2892 2891 +5849 2310 2309 2891 2890 +5850 2425 2310 2890 2889 +5851 2426 2425 2889 2887 +5852 2426 2887 2888 2886 +5853 2308 2426 2886 2885 +5854 2307 2308 2885 2884 +5855 2306 2307 2884 2883 +5856 2305 2306 2883 2882 +5857 2304 2305 2882 2881 +5858 2303 2304 2881 2880 +5859 2302 2303 2880 2879 +5860 2301 2302 2879 2878 +5861 2300 2301 2878 2877 +5862 2299 2300 2877 2876 +5863 2298 2299 2876 2875 +5864 2297 2298 2875 2874 +5865 2296 2297 2874 2295 +5866 2294 2295 2874 2873 +5867 2292 2294 2873 2872 +5868 2293 2292 2872 2870 +5869 2293 2870 2871 2869 +5870 2291 2293 2869 2868 +5871 2290 2291 2868 2867 +5872 2289 2290 2867 2866 +5873 2288 2289 2866 2865 +5874 2287 2288 2865 2864 +5875 2286 2287 2864 2863 +5876 2285 2286 2863 2862 +5877 2284 2285 2862 2861 +5878 2283 2284 2861 2860 +5879 2282 2283 2860 2859 +5880 2281 2282 2859 2858 +5881 2280 2281 2858 2857 +5882 2279 2280 2857 2856 +5883 2278 2279 2856 2855 +5884 2277 2278 2855 2854 +5885 2275 2277 2854 2853 +5886 2276 2275 2853 2851 +5887 2276 2851 2852 2850 +5888 2274 2276 2850 2849 +5889 2273 2274 2849 2848 +5890 2272 2273 2848 2847 +5891 2271 2272 2847 2846 +5892 2270 2271 2846 2845 +5893 2269 2270 2845 2844 +5894 2268 2269 2844 2843 +5895 2267 2268 2843 2842 +5896 2266 2267 2842 2841 +5897 2265 2266 2841 2840 +5898 2264 2265 2840 2839 +5899 2263 2264 2839 2838 +5900 2262 2263 2838 2837 +5901 2261 2262 2837 2836 +5902 2260 2261 2836 2259 +5903 2258 2259 2836 2835 +5904 2256 2258 2835 2834 +5905 2257 2256 2834 2832 +5906 2257 2832 2833 2831 +5907 2255 2257 2831 2830 +5908 2254 2255 2830 2829 +5909 2253 2254 2829 2828 +5910 2252 2253 2828 2827 +5911 2251 2252 2827 2826 +5912 2250 2251 2826 2825 +5913 2249 2250 2825 2824 +5914 2248 2249 2824 2823 +5915 2247 2248 2823 2822 +5916 2246 2247 2822 2821 +5917 2245 2246 2821 2820 +5918 2244 2245 2820 2819 +5919 2243 2244 2819 2818 +5920 2242 2243 2818 2817 +5921 2241 2242 2817 2816 +5922 2240 2241 2816 2815 +5923 2238 2240 2815 2814 +5924 2239 2238 2814 2812 +5925 2239 2812 2813 2811 +5926 2237 2239 2811 2810 +5927 2236 2237 2810 2809 +5928 2235 2236 2809 2808 +5929 2234 2235 2808 2807 +5930 2233 2234 2807 2806 +5931 2232 2233 2806 2805 +5932 2231 2232 2805 2804 +5933 2230 2231 2804 2803 +5934 2229 2230 2803 2802 +5935 2228 2229 2802 2801 +5936 2227 2228 2801 2800 +5937 2226 2227 2800 2799 +5938 2225 2226 2799 2798 +5939 2224 2225 2798 2797 +5940 1938 2224 2797 2424 +5941 2035 2036 2614 2796 +5942 2034 2035 2796 2795 +5943 2033 2034 2795 2794 +5944 2032 2033 2794 2793 +5945 2031 2032 2793 2792 +5946 2030 2031 2792 2791 +5947 2029 2030 2791 2790 +5948 2028 2029 2790 2789 +5949 2027 2028 2789 2788 +5950 2026 2027 2788 2787 +5951 2025 2026 2787 2786 +5952 2024 2025 2786 2785 +5953 2023 2024 2785 2784 +5954 2022 2023 2784 2783 +5955 2021 2022 2783 2782 +5956 2020 2021 2782 2781 +5957 2019 2020 2781 2780 +5958 2018 2019 2780 2779 +5959 2017 2018 2779 2778 +5960 2016 2017 2778 2777 +5961 2015 2016 2777 2776 +5962 2014 2015 2776 2775 +5963 2013 2014 2775 2774 +5964 2012 2013 2774 2773 +5965 2011 2012 2773 2772 +5966 2010 2011 2772 2771 +5967 2009 2010 2771 2770 +5968 2008 2009 2770 2769 +5969 2007 2008 2769 2768 +5970 2006 2007 2768 2767 +5971 2005 2006 2767 2766 +5972 2004 2005 2766 2765 +5973 2003 2004 2765 2764 +5974 2002 2003 2764 2763 +5975 2001 2002 2763 2762 +5976 2000 2001 2762 2761 +5977 1999 2000 2761 2760 +5978 1998 1999 2760 2759 +5979 1997 1998 2759 2758 +5980 1996 1997 2758 2757 +5981 1995 1996 2757 2756 +5982 1994 1995 2756 2755 +5983 1993 1994 2755 2754 +5984 1992 1993 2754 2753 +5985 1991 1992 2753 2752 +5986 1990 1991 2752 2751 +5987 1989 1990 2751 2750 +5988 1988 1989 2750 2749 +5989 1987 1988 2749 2748 +5990 1986 1987 2748 2747 +5991 1985 1986 2747 2746 +5992 1984 1985 2746 2745 +5993 1983 1984 2745 2744 +5994 1982 1983 2744 2743 +5995 1981 1982 2743 2742 +5996 1980 1981 2742 2741 +5997 1979 1980 2741 2740 +5998 1978 1979 2740 2739 +5999 1977 1978 2739 2738 +6000 1976 1977 2738 2737 +6001 1975 1976 2737 2736 +6002 1974 1975 2736 2735 +6003 1973 1974 2735 2734 +6004 1972 1973 2734 2733 +6005 1971 1972 2733 2732 +6006 1970 1971 2732 2731 +6007 1969 1970 2731 2730 +6008 1968 1969 2730 2729 +6009 1967 1968 2729 2728 +6010 1966 1967 2728 2727 +6011 1965 1966 2727 2726 +6012 1964 1965 2726 2725 +6013 1963 1964 2725 2724 +6014 1962 1963 2724 2723 +6015 1961 1962 2723 2722 +6016 1960 1961 2722 2721 +6017 1959 1960 2721 2720 +6018 1958 1959 2720 2719 +6019 1957 1958 2719 2718 +6020 1956 1957 2718 2717 +6021 1955 1956 2717 2716 +6022 1954 1955 2716 2715 +6023 1953 1954 2715 2714 +6024 1952 1953 2714 2713 +6025 1951 1952 2713 2712 +6026 1950 1951 2712 2711 +6027 1949 1950 2711 2710 +6028 1948 1949 2710 2709 +6029 1947 1948 2709 2708 +6030 1946 1947 2708 2707 +6031 1945 1946 2707 2706 +6032 1944 1945 2706 2613 +6033 2222 2223 2429 2705 +6034 2221 2222 2705 2704 +6035 2220 2221 2704 2703 +6036 2219 2220 2703 2702 +6037 2218 2219 2702 2701 +6038 2217 2218 2701 2700 +6039 2216 2217 2700 2699 +6040 2215 2216 2699 2698 +6041 2214 2215 2698 2697 +6042 2213 2214 2697 2696 +6043 2212 2213 2696 2695 +6044 2211 2212 2695 2694 +6045 2210 2211 2694 2693 +6046 2209 2210 2693 2692 +6047 2208 2209 2692 2691 +6048 2207 2208 2691 2690 +6049 2206 2207 2690 2689 +6050 2205 2206 2689 2688 +6051 2204 2205 2688 2687 +6052 2203 2204 2687 2686 +6053 2202 2203 2686 2685 +6054 2201 2202 2685 2684 +6055 2200 2201 2684 2683 +6056 2199 2200 2683 2682 +6057 2198 2199 2682 2681 +6058 2197 2198 2681 2680 +6059 2196 2197 2680 2679 +6060 2195 2196 2679 2678 +6061 2194 2195 2678 2677 +6062 2193 2194 2677 2676 +6063 2192 2193 2676 2675 +6064 2191 2192 2675 2674 +6065 2190 2191 2674 2673 +6066 2189 2190 2673 2672 +6067 2188 2189 2672 2671 +6068 2187 2188 2671 2670 +6069 2186 2187 2670 2669 +6070 2185 2186 2669 2668 +6071 2184 2185 2668 2667 +6072 2183 2184 2667 2666 +6073 2182 2183 2666 2665 +6074 2181 2182 2665 2664 +6075 2180 2181 2664 2663 +6076 2179 2180 2663 2662 +6077 2178 2179 2662 2661 +6078 2177 2178 2661 2660 +6079 2176 2177 2660 2659 +6080 2175 2176 2659 2658 +6081 2174 2175 2658 2657 +6082 2173 2174 2657 2656 +6083 2172 2173 2656 2655 +6084 2171 2172 2655 2654 +6085 2170 2171 2654 2653 +6086 2169 2170 2653 2652 +6087 2168 2169 2652 2651 +6088 2167 2168 2651 2650 +6089 2166 2167 2650 2649 +6090 2165 2166 2649 2648 +6091 2164 2165 2648 2647 +6092 2163 2164 2647 2646 +6093 2162 2163 2646 2645 +6094 2161 2162 2645 2644 +6095 2160 2161 2644 2643 +6096 2159 2160 2643 2642 +6097 2158 2159 2642 2641 +6098 2157 2158 2641 2640 +6099 2156 2157 2640 2639 +6100 2155 2156 2639 2638 +6101 2154 2155 2638 2637 +6102 2153 2154 2637 2636 +6103 2152 2153 2636 2635 +6104 2151 2152 2635 2634 +6105 2150 2151 2634 2633 +6106 2149 2150 2633 2632 +6107 2148 2149 2632 2631 +6108 2147 2148 2631 2630 +6109 2146 2147 2630 2629 +6110 2145 2146 2629 2628 +6111 2144 2145 2628 2627 +6112 2143 2144 2627 2626 +6113 2142 2143 2626 2625 +6114 2141 2142 2625 2624 +6115 2140 2141 2624 2623 +6116 2139 2140 2623 2622 +6117 2138 2139 2622 2621 +6118 2137 2138 2621 2620 +6119 2136 2137 2620 2619 +6120 2135 2136 2619 2618 +6121 2134 2135 2618 2617 +6122 2133 2134 2617 2616 +6123 2132 2133 2616 2615 +6124 2131 2132 2615 2614 +6125 2037 2131 2614 2036 +6126 2130 1943 1944 2613 +6127 2129 2130 2613 2612 +6128 2128 2129 2612 2611 +6129 2127 2128 2611 2610 +6130 2126 2127 2610 2609 +6131 2125 2126 2609 2608 +6132 2124 2125 2608 2607 +6133 2123 2124 2607 2606 +6134 2122 2123 2606 2605 +6135 2121 2122 2605 2604 +6136 2120 2121 2604 2603 +6137 2119 2120 2603 2602 +6138 2118 2119 2602 2601 +6139 2117 2118 2601 2600 +6140 2116 2117 2600 2599 +6141 2115 2116 2599 2598 +6142 2114 2115 2598 2597 +6143 2113 2114 2597 2596 +6144 2112 2113 2596 2595 +6145 2111 2112 2595 2594 +6146 2110 2111 2594 2593 +6147 2109 2110 2593 2592 +6148 2108 2109 2592 2591 +6149 2107 2108 2591 2590 +6150 2106 2107 2590 2589 +6151 2105 2106 2589 2588 +6152 2104 2105 2588 2587 +6153 2103 2104 2587 2586 +6154 2102 2103 2586 2585 +6155 2101 2102 2585 2584 +6156 2100 2101 2584 2583 +6157 2099 2100 2583 2582 +6158 2098 2099 2582 2581 +6159 2097 2098 2581 2580 +6160 2096 2097 2580 2579 +6161 2095 2096 2579 2578 +6162 2094 2095 2578 2577 +6163 2093 2094 2577 2576 +6164 2092 2093 2576 2575 +6165 2091 2092 2575 2574 +6166 2090 2091 2574 2573 +6167 2089 2090 2573 2572 +6168 2088 2089 2572 2571 +6169 2087 2088 2571 2570 +6170 2086 2087 2570 2569 +6171 2085 2086 2569 2568 +6172 2084 2085 2568 2567 +6173 2083 2084 2567 2566 +6174 2082 2083 2566 2565 +6175 2081 2082 2565 2564 +6176 2080 2081 2564 2563 +6177 2079 2080 2563 2562 +6178 2078 2079 2562 2561 +6179 2077 2078 2561 2560 +6180 2076 2077 2560 2559 +6181 2075 2076 2559 2558 +6182 2074 2075 2558 2557 +6183 2073 2074 2557 2556 +6184 2072 2073 2556 2555 +6185 2071 2072 2555 2554 +6186 2070 2071 2554 2553 +6187 2069 2070 2553 2552 +6188 2068 2069 2552 2551 +6189 2067 2068 2551 2550 +6190 2066 2067 2550 2549 +6191 2065 2066 2549 2548 +6192 2064 2065 2548 2547 +6193 2063 2064 2547 2546 +6194 2062 2063 2546 2545 +6195 2061 2062 2545 2544 +6196 2060 2061 2544 2543 +6197 2059 2060 2543 2542 +6198 2058 2059 2542 2541 +6199 2057 2058 2541 2540 +6200 2056 2057 2540 2539 +6201 2055 2056 2539 2538 +6202 2054 2055 2538 2537 +6203 2053 2054 2537 2536 +6204 2052 2053 2536 2535 +6205 2051 2052 2535 2534 +6206 2050 2051 2534 2533 +6207 2049 2050 2533 2532 +6208 2048 2049 2532 2531 +6209 2047 2048 2531 2530 +6210 2046 2047 2530 2529 +6211 2045 2046 2529 2528 +6212 2044 2045 2528 2527 +6213 2043 2044 2527 2526 +6214 2042 2043 2526 2525 +6215 2041 2042 2525 2524 +6216 2040 2041 2524 2523 +6217 2039 2040 2523 2522 +6218 2038 2039 2522 2521 +6219 1756 1757 2038 2521 +6220 1755 1756 2521 2520 +6221 1754 1755 2520 2519 +6222 1753 1754 2519 2518 +6223 1752 1753 2518 2517 +6224 1751 1752 2517 2516 +6225 1750 1751 2516 2515 +6226 1749 1750 2515 2514 +6227 1748 1749 2514 2513 +6228 1747 1748 2513 2512 +6229 1746 1747 2512 2511 +6230 1745 1746 2511 2510 +6231 1744 1745 2510 2509 +6232 1743 1744 2509 2508 +6233 1742 1743 2508 2507 +6234 1741 1742 2507 2506 +6235 1740 1741 2506 2505 +6236 1739 1740 2505 2504 +6237 1738 1739 2504 2503 +6238 1737 1738 2503 2502 +6239 1736 1737 2502 2501 +6240 1735 1736 2501 2500 +6241 1734 1735 2500 2499 +6242 1733 1734 2499 2498 +6243 1732 1733 2498 2497 +6244 1731 1732 2497 2496 +6245 1730 1731 2496 2495 +6246 1729 1730 2495 2494 +6247 1728 1729 2494 2493 +6248 1727 1728 2493 2492 +6249 1726 1727 2492 2491 +6250 1725 1726 2491 2490 +6251 1724 1725 2490 2489 +6252 1723 1724 2489 2488 +6253 1722 1723 2488 2487 +6254 1721 1722 2487 2486 +6255 1720 1721 2486 2485 +6256 1719 1720 2485 2484 +6257 1718 1719 2484 2483 +6258 1717 1718 2483 2482 +6259 1716 1717 2482 2481 +6260 1715 1716 2481 2480 +6261 1714 1715 2480 2479 +6262 1713 1714 2479 2478 +6263 1712 1713 2478 2477 +6264 1711 1712 2477 2476 +6265 1710 1711 2476 2475 +6266 1709 1710 2475 2474 +6267 1708 1709 2474 2473 +6268 1707 1708 2473 2472 +6269 1706 1707 2472 2471 +6270 1705 1706 2471 2470 +6271 1704 1705 2470 2469 +6272 1703 1704 2469 2468 +6273 1702 1703 2468 2467 +6274 1701 1702 2467 2466 +6275 1700 1701 2466 2465 +6276 1699 1700 2465 2464 +6277 1698 1699 2464 2463 +6278 1697 1698 2463 2462 +6279 1696 1697 2462 2461 +6280 1695 1696 2461 2460 +6281 1694 1695 2460 2459 +6282 1693 1694 2459 2458 +6283 1692 1693 2458 2457 +6284 1691 1692 2457 2456 +6285 1690 1691 2456 2455 +6286 1689 1690 2455 2454 +6287 1688 1689 2454 2453 +6288 1687 1688 2453 2452 +6289 1686 1687 2452 2451 +6290 1685 1686 2451 2450 +6291 1684 1685 2450 2449 +6292 1683 1684 2449 2448 +6293 1682 1683 2448 2447 +6294 1681 1682 2447 2446 +6295 1680 1681 2446 2445 +6296 1679 1680 2445 2444 +6297 1678 1679 2444 2443 +6298 1677 1678 2443 2442 +6299 1676 1677 2442 2441 +6300 1675 1676 2441 2440 +6301 1674 1675 2440 2439 +6302 1673 1674 2439 2438 +6303 1672 1673 2438 2437 +6304 1671 1672 2437 2436 +6305 1670 1671 2436 2435 +6306 1669 1670 2435 2434 +6307 1668 1669 2434 2433 +6308 1667 1668 2433 2432 +6309 1666 1667 2432 2431 +6310 1665 1666 2431 2430 +6311 1664 1665 2430 2429 +6312 1663 1664 2429 2223 +6313 2341 1861 2427 2428 +6314 1861 1862 2343 2427 +6315 2308 1830 2425 2426 +6316 1830 1831 2310 2425 +6317 1936 1938 2424 2423 +6318 1937 1936 2423 2421 +6319 1937 2421 2422 2420 +6320 1935 1937 2420 2419 +6321 1934 1935 2419 2418 +6322 1933 1934 2418 2417 +6323 1932 1933 2417 2416 +6324 1931 1932 2416 2415 +6325 1930 1931 2415 2414 +6326 1929 1930 2414 2413 +6327 1928 1929 2413 2412 +6328 1927 1928 2412 2411 +6329 1926 1927 2411 2410 +6330 1925 1926 2410 2409 +6331 1924 1925 2409 2408 +6332 1923 1924 2408 2407 +6333 1922 1923 2407 2406 +6334 1921 1922 2406 2405 +6335 1920 1921 2405 2404 +6336 1919 1920 2404 2403 +6337 1918 1919 2403 2402 +6338 1917 1918 2402 2401 +6339 1916 1917 2401 2400 +6340 1915 1916 2400 2399 +6341 1914 1915 2399 2398 +6342 1913 1914 2398 2397 +6343 1912 1913 2397 2396 +6344 1911 1912 2396 2395 +6345 1910 1911 2395 2394 +6346 1909 1910 2394 2393 +6347 1908 1909 2393 2392 +6348 1906 1908 2392 2391 +6349 1907 1906 2391 2389 +6350 1907 2389 2390 2388 +6351 1905 1907 2388 2387 +6352 1904 1905 2387 2386 +6353 1903 1904 2386 2385 +6354 1902 1903 2385 2384 +6355 1901 1902 2384 2383 +6356 1900 1901 2383 2382 +6357 1899 1900 2382 2381 +6358 1898 1899 2381 2380 +6359 1897 1898 2380 2379 +6360 1896 1897 2379 2378 +6361 1895 1896 2378 2377 +6362 1894 1895 2377 2376 +6363 1893 1894 2376 2375 +6364 1892 1893 2375 2374 +6365 1891 1892 2374 2373 +6366 1890 1891 2373 2372 +6367 1889 1890 2372 2371 +6368 1888 1889 2371 2370 +6369 1887 1888 2370 2369 +6370 1886 1887 2369 2368 +6371 1885 1886 2368 2367 +6372 1884 1885 2367 2366 +6373 1883 1884 2366 2365 +6374 1882 1883 2365 2364 +6375 1881 1882 2364 2363 +6376 1880 1881 2363 2362 +6377 1879 1880 2362 2361 +6378 1878 1879 2361 2360 +6379 1876 1878 2360 2359 +6380 1877 1876 2359 2357 +6381 1877 2357 2358 2356 +6382 1875 1877 2356 2355 +6383 1874 1875 2355 2354 +6384 1873 1874 2354 2353 +6385 1872 1873 2353 2352 +6386 1871 1872 2352 2351 +6387 1870 1871 2351 2350 +6388 1869 1870 2350 2349 +6389 1868 1869 2349 2348 +6390 1867 1868 2348 2347 +6391 1866 1867 2347 2346 +6392 1865 1866 2346 2345 +6393 1864 1865 2345 2344 +6394 1863 1864 2344 2342 +6395 1862 1863 2342 2343 +6396 1860 1861 2341 2340 +6397 1859 1860 2340 2339 +6398 1858 1859 2339 2338 +6399 1857 1858 2338 2337 +6400 1856 1857 2337 2336 +6401 1855 1856 2336 2335 +6402 1854 1855 2335 2334 +6403 1853 1854 2334 2333 +6404 1852 1853 2333 2332 +6405 1851 1852 2332 2331 +6406 1850 1851 2331 2330 +6407 1849 1850 2330 2329 +6408 1848 1849 2329 2328 +6409 1847 1848 2328 2327 +6410 1845 1847 2327 2326 +6411 1846 1845 2326 2324 +6412 1846 2324 2325 2323 +6413 1844 1846 2323 2322 +6414 1843 1844 2322 2321 +6415 1842 1843 2321 2320 +6416 1841 1842 2320 2319 +6417 1840 1841 2319 2318 +6418 1839 1840 2318 2317 +6419 1838 1839 2317 2316 +6420 1837 1838 2316 2315 +6421 1836 1837 2315 2314 +6422 1835 1836 2314 2313 +6423 1834 1835 2313 2312 +6424 1833 1834 2312 2311 +6425 1832 1833 2311 2309 +6426 1831 1832 2309 2310 +6427 1829 1830 2308 2307 +6428 1828 1829 2307 2306 +6429 1827 1828 2306 2305 +6430 1826 1827 2305 2304 +6431 1825 1826 2304 2303 +6432 1824 1825 2303 2302 +6433 1823 1824 2302 2301 +6434 1822 1823 2301 2300 +6435 1821 1822 2300 2299 +6436 1820 1821 2299 2298 +6437 1819 1820 2298 2297 +6438 1818 1819 2297 2296 +6439 1817 1818 2296 2295 +6440 1815 1817 2295 2294 +6441 1816 1815 2294 2292 +6442 1816 2292 2293 2291 +6443 1814 1816 2291 2290 +6444 1813 1814 2290 2289 +6445 1812 1813 2289 2288 +6446 1811 1812 2288 2287 +6447 1810 1811 2287 2286 +6448 1809 1810 2286 2285 +6449 1808 1809 2285 2284 +6450 1807 1808 2284 2283 +6451 1806 1807 2283 2282 +6452 1805 1806 2282 2281 +6453 1804 1805 2281 2280 +6454 1802 1804 2280 2279 +6455 1803 1802 2279 2278 +6456 1941 1803 2278 2277 +6457 1942 1941 2277 2275 +6458 1942 2275 2276 2274 +6459 1801 1942 2274 2273 +6460 1800 1801 2273 2272 +6461 1799 1800 2272 2271 +6462 1798 1799 2271 2270 +6463 1797 1798 2270 2269 +6464 1796 1797 2269 2268 +6465 1795 1796 2268 2267 +6466 1794 1795 2267 2266 +6467 1793 1794 2266 2265 +6468 1792 1793 2265 2264 +6469 1791 1792 2264 2263 +6470 1790 1791 2263 2262 +6471 1789 1790 2262 2261 +6472 1788 1789 2261 2260 +6473 1787 1788 2260 2259 +6474 1785 1787 2259 2258 +6475 1786 1785 2258 2256 +6476 1786 2256 2257 2255 +6477 1784 1786 2255 2254 +6478 1783 1784 2254 2253 +6479 1782 1783 2253 2252 +6480 1781 1782 2252 2251 +6481 1780 1781 2251 2250 +6482 1779 1780 2250 2249 +6483 1778 1779 2249 2248 +6484 1777 1778 2248 2247 +6485 1776 1777 2247 2246 +6486 1775 1776 2246 2245 +6487 1774 1775 2245 2244 +6488 1773 1774 2244 2243 +6489 1771 1773 2243 2242 +6490 1772 1771 2242 2241 +6491 1939 1772 2241 2240 +6492 1940 1939 2240 2238 +6493 1940 2238 2239 2237 +6494 1770 1940 2237 2236 +6495 1769 1770 2236 2235 +6496 1768 1769 2235 2234 +6497 1767 1768 2234 2233 +6498 1766 1767 2233 2232 +6499 1765 1766 2232 2231 +6500 1764 1765 2231 2230 +6501 1763 1764 2230 2229 +6502 1762 1763 2229 2228 +6503 1761 1762 2228 2227 +6504 1760 1761 2227 2226 +6505 1759 1760 2226 2225 +6506 1758 1759 2225 2224 +6507 1662 1758 2224 1938 +6508 1564 1565 1663 2223 +6509 1563 1564 2223 2222 +6510 1562 1563 2222 2221 +6511 1561 1562 2221 2220 +6512 1560 1561 2220 2219 +6513 1559 1560 2219 2218 +6514 1558 1559 2218 2217 +6515 1557 1558 2217 2216 +6516 1556 1557 2216 2215 +6517 1555 1556 2215 2214 +6518 1554 1555 2214 2213 +6519 1553 1554 2213 2212 +6520 1552 1553 2212 2211 +6521 1551 1552 2211 2210 +6522 1550 1551 2210 2209 +6523 1549 1550 2209 2208 +6524 1548 1549 2208 2207 +6525 1547 1548 2207 2206 +6526 1546 1547 2206 2205 +6527 1545 1546 2205 2204 +6528 1544 1545 2204 2203 +6529 1543 1544 2203 2202 +6530 1542 1543 2202 2201 +6531 1541 1542 2201 2200 +6532 1540 1541 2200 2199 +6533 1539 1540 2199 2198 +6534 1538 1539 2198 2197 +6535 1537 1538 2197 2196 +6536 1536 1537 2196 2195 +6537 1535 1536 2195 2194 +6538 1534 1535 2194 2193 +6539 1533 1534 2193 2192 +6540 1532 1533 2192 2191 +6541 1531 1532 2191 2190 +6542 1530 1531 2190 2189 +6543 1529 1530 2189 2188 +6544 1528 1529 2188 2187 +6545 1527 1528 2187 2186 +6546 1526 1527 2186 2185 +6547 1525 1526 2185 2184 +6548 1524 1525 2184 2183 +6549 1523 1524 2183 2182 +6550 1522 1523 2182 2181 +6551 1521 1522 2181 2180 +6552 1520 1521 2180 2179 +6553 1519 1520 2179 2178 +6554 1518 1519 2178 2177 +6555 1517 1518 2177 2176 +6556 1516 1517 2176 2175 +6557 1515 1516 2175 2174 +6558 1514 1515 2174 2173 +6559 1513 1514 2173 2172 +6560 1512 1513 2172 2171 +6561 1511 1512 2171 2170 +6562 1510 1511 2170 2169 +6563 1509 1510 2169 2168 +6564 1508 1509 2168 2167 +6565 1507 1508 2167 2166 +6566 1506 1507 2166 2165 +6567 1505 1506 2165 2164 +6568 1504 1505 2164 2163 +6569 1503 1504 2163 2162 +6570 1502 1503 2162 2161 +6571 1501 1502 2161 2160 +6572 1500 1501 2160 2159 +6573 1499 1500 2159 2158 +6574 1498 1499 2158 2157 +6575 1497 1498 2157 2156 +6576 1496 1497 2156 2155 +6577 1495 1496 2155 2154 +6578 1494 1495 2154 2153 +6579 1493 1494 2153 2152 +6580 1492 1493 2152 2151 +6581 1491 1492 2151 2150 +6582 1490 1491 2150 2149 +6583 1489 1490 2149 2148 +6584 1488 1489 2148 2147 +6585 1487 1488 2147 2146 +6586 1486 1487 2146 2145 +6587 1485 1486 2145 2144 +6588 1484 1485 2144 2143 +6589 1483 1484 2143 2142 +6590 1482 1483 2142 2141 +6591 1481 1482 2141 2140 +6592 1480 1481 2140 2139 +6593 1479 1480 2139 2138 +6594 1478 1479 2138 2137 +6595 1477 1478 2137 2136 +6596 1476 1477 2136 2135 +6597 1475 1476 2135 2134 +6598 1474 1475 2134 2133 +6599 1473 1474 2133 2132 +6600 1472 1473 2132 2131 +6601 1471 1472 2131 2037 +6602 1467 1468 1943 2130 +6603 1466 1467 2130 2129 +6604 1465 1466 2129 2128 +6605 1464 1465 2128 2127 +6606 1463 1464 2127 2126 +6607 1462 1463 2126 2125 +6608 1461 1462 2125 2124 +6609 1460 1461 2124 2123 +6610 1459 1460 2123 2122 +6611 1458 1459 2122 2121 +6612 1457 1458 2121 2120 +6613 1456 1457 2120 2119 +6614 1455 1456 2119 2118 +6615 1454 1455 2118 2117 +6616 1453 1454 2117 2116 +6617 1452 1453 2116 2115 +6618 1451 1452 2115 2114 +6619 1450 1451 2114 2113 +6620 1449 1450 2113 2112 +6621 1448 1449 2112 2111 +6622 1447 1448 2111 2110 +6623 1446 1447 2110 2109 +6624 1445 1446 2109 2108 +6625 1444 1445 2108 2107 +6626 1443 1444 2107 2106 +6627 1442 1443 2106 2105 +6628 1441 1442 2105 2104 +6629 1440 1441 2104 2103 +6630 1439 1440 2103 2102 +6631 1438 1439 2102 2101 +6632 1437 1438 2101 2100 +6633 1436 1437 2100 2099 +6634 1435 1436 2099 2098 +6635 1434 1435 2098 2097 +6636 1433 1434 2097 2096 +6637 1432 1433 2096 2095 +6638 1431 1432 2095 2094 +6639 1430 1431 2094 2093 +6640 1429 1430 2093 2092 +6641 1428 1429 2092 2091 +6642 1427 1428 2091 2090 +6643 1426 1427 2090 2089 +6644 1425 1426 2089 2088 +6645 1424 1425 2088 2087 +6646 1423 1424 2087 2086 +6647 1422 1423 2086 2085 +6648 1421 1422 2085 2084 +6649 1420 1421 2084 2083 +6650 1419 1420 2083 2082 +6651 1418 1419 2082 2081 +6652 1417 1418 2081 2080 +6653 1416 1417 2080 2079 +6654 1415 1416 2079 2078 +6655 1414 1415 2078 2077 +6656 1413 1414 2077 2076 +6657 1412 1413 2076 2075 +6658 1411 1412 2075 2074 +6659 1410 1411 2074 2073 +6660 1409 1410 2073 2072 +6661 1408 1409 2072 2071 +6662 1407 1408 2071 2070 +6663 1406 1407 2070 2069 +6664 1405 1406 2069 2068 +6665 1404 1405 2068 2067 +6666 1403 1404 2067 2066 +6667 1402 1403 2066 2065 +6668 1401 1402 2065 2064 +6669 1400 1401 2064 2063 +6670 1399 1400 2063 2062 +6671 1398 1399 2062 2061 +6672 1397 1398 2061 2060 +6673 1396 1397 2060 2059 +6674 1395 1396 2059 2058 +6675 1394 1395 2058 2057 +6676 1393 1394 2057 2056 +6677 1392 1393 2056 2055 +6678 1391 1392 2055 2054 +6679 1390 1391 2054 2053 +6680 1389 1390 2053 2052 +6681 1388 1389 2052 2051 +6682 1387 1388 2051 2050 +6683 1386 1387 2050 2049 +6684 1385 1386 2049 2048 +6685 1384 1385 2048 2047 +6686 1383 1384 2047 2046 +6687 1382 1383 2046 2045 +6688 1381 1382 2045 2044 +6689 1380 1381 2044 2043 +6690 1379 1380 2043 2042 +6691 1378 1379 2042 2041 +6692 1377 1378 2041 2040 +6693 1376 1377 2040 2039 +6694 1375 1376 2039 2038 +6695 1374 1375 2038 1757 +6696 1660 1470 1471 2037 +6697 1659 1660 2037 2036 +6698 1658 1659 2036 2035 +6699 1657 1658 2035 2034 +6700 1656 1657 2034 2033 +6701 1655 1656 2033 2032 +6702 1654 1655 2032 2031 +6703 1653 1654 2031 2030 +6704 1652 1653 2030 2029 +6705 1651 1652 2029 2028 +6706 1650 1651 2028 2027 +6707 1649 1650 2027 2026 +6708 1648 1649 2026 2025 +6709 1647 1648 2025 2024 +6710 1646 1647 2024 2023 +6711 1645 1646 2023 2022 +6712 1644 1645 2022 2021 +6713 1643 1644 2021 2020 +6714 1642 1643 2020 2019 +6715 1641 1642 2019 2018 +6716 1640 1641 2018 2017 +6717 1639 1640 2017 2016 +6718 1638 1639 2016 2015 +6719 1637 1638 2015 2014 +6720 1636 1637 2014 2013 +6721 1635 1636 2013 2012 +6722 1634 1635 2012 2011 +6723 1633 1634 2011 2010 +6724 1632 1633 2010 2009 +6725 1631 1632 2009 2008 +6726 1630 1631 2008 2007 +6727 1629 1630 2007 2006 +6728 1628 1629 2006 2005 +6729 1627 1628 2005 2004 +6730 1626 1627 2004 2003 +6731 1625 1626 2003 2002 +6732 1624 1625 2002 2001 +6733 1623 1624 2001 2000 +6734 1622 1623 2000 1999 +6735 1621 1622 1999 1998 +6736 1620 1621 1998 1997 +6737 1619 1620 1997 1996 +6738 1618 1619 1996 1995 +6739 1617 1618 1995 1994 +6740 1616 1617 1994 1993 +6741 1615 1616 1993 1992 +6742 1614 1615 1992 1991 +6743 1613 1614 1991 1990 +6744 1612 1613 1990 1989 +6745 1611 1612 1989 1988 +6746 1610 1611 1988 1987 +6747 1609 1610 1987 1986 +6748 1608 1609 1986 1985 +6749 1607 1608 1985 1984 +6750 1606 1607 1984 1983 +6751 1605 1606 1983 1982 +6752 1604 1605 1982 1981 +6753 1603 1604 1981 1980 +6754 1602 1603 1980 1979 +6755 1601 1602 1979 1978 +6756 1600 1601 1978 1977 +6757 1599 1600 1977 1976 +6758 1598 1599 1976 1975 +6759 1597 1598 1975 1974 +6760 1596 1597 1974 1973 +6761 1595 1596 1973 1972 +6762 1594 1595 1972 1971 +6763 1593 1594 1971 1970 +6764 1592 1593 1970 1969 +6765 1591 1592 1969 1968 +6766 1590 1591 1968 1967 +6767 1589 1590 1967 1966 +6768 1588 1589 1966 1965 +6769 1587 1588 1965 1964 +6770 1586 1587 1964 1963 +6771 1585 1586 1963 1962 +6772 1584 1585 1962 1961 +6773 1583 1584 1961 1960 +6774 1582 1583 1960 1959 +6775 1581 1582 1959 1958 +6776 1580 1581 1958 1957 +6777 1579 1580 1957 1956 +6778 1578 1579 1956 1955 +6779 1577 1578 1955 1954 +6780 1576 1577 1954 1953 +6781 1575 1576 1953 1952 +6782 1574 1575 1952 1951 +6783 1573 1574 1951 1950 +6784 1572 1573 1950 1949 +6785 1571 1572 1949 1948 +6786 1570 1571 1948 1947 +6787 1569 1570 1947 1946 +6788 1568 1569 1946 1945 +6789 1567 1568 1945 1944 +6790 1566 1567 1944 1943 +6791 1469 1566 1943 1468 +6792 1801 1163 1941 1942 +6793 1163 1164 1803 1941 +6794 1770 1136 1939 1940 +6795 1136 1137 1772 1939 +6796 1661 1662 1938 1936 +6797 1661 1936 1937 1935 +6798 1122 1661 1935 1934 +6799 1121 1122 1934 1933 +6800 1120 1121 1933 1932 +6801 1119 1120 1932 1931 +6802 1118 1119 1931 1930 +6803 1117 1118 1930 1929 +6804 1116 1117 1929 1928 +6805 1115 1116 1928 1927 +6806 1114 1115 1927 1926 +6807 1113 1114 1926 1925 +6808 1112 1113 1925 1924 +6809 1111 1112 1924 1923 +6810 1109 1111 1923 1922 +6811 1110 1109 1922 1921 +6812 1266 1110 1921 1920 +6813 1265 1266 1920 1919 +6814 1264 1265 1919 1918 +6815 1263 1264 1918 1917 +6816 1262 1263 1917 1916 +6817 1261 1262 1916 1915 +6818 1260 1261 1915 1914 +6819 1259 1260 1914 1913 +6820 1258 1259 1913 1912 +6821 1257 1258 1912 1911 +6822 1255 1257 1911 1910 +6823 1256 1255 1910 1909 +6824 1267 1256 1909 1908 +6825 1268 1267 1908 1906 +6826 1268 1906 1907 1905 +6827 1254 1268 1905 1904 +6828 1253 1254 1904 1903 +6829 1252 1253 1903 1902 +6830 1251 1252 1902 1901 +6831 1250 1251 1901 1900 +6832 1249 1250 1900 1899 +6833 1248 1249 1899 1898 +6834 1247 1248 1898 1897 +6835 1246 1247 1897 1896 +6836 1245 1246 1896 1895 +6837 1244 1245 1895 1894 +6838 1243 1244 1894 1893 +6839 1242 1243 1893 1892 +6840 1241 1242 1892 1891 +6841 1240 1241 1891 1890 +6842 1239 1240 1890 1889 +6843 1238 1239 1889 1888 +6844 1237 1238 1888 1887 +6845 1236 1237 1887 1886 +6846 1235 1236 1886 1885 +6847 1234 1235 1885 1884 +6848 1233 1234 1884 1883 +6849 1232 1233 1883 1882 +6850 1231 1232 1882 1881 +6851 1229 1231 1881 1880 +6852 1230 1229 1880 1879 +6853 1269 1230 1879 1878 +6854 1270 1269 1878 1876 +6855 1270 1876 1877 1875 +6856 1228 1270 1875 1874 +6857 1227 1228 1874 1873 +6858 1226 1227 1873 1872 +6859 1225 1226 1872 1871 +6860 1224 1225 1871 1870 +6861 1223 1224 1870 1869 +6862 1222 1223 1869 1868 +6863 1221 1222 1868 1867 +6864 1220 1221 1867 1866 +6865 1219 1220 1866 1865 +6866 1218 1219 1865 1864 +6867 1217 1218 1864 1863 +6868 1216 1217 1863 1862 +6869 1215 1216 1862 1861 +6870 1214 1215 1861 1860 +6871 1213 1214 1860 1859 +6872 1212 1213 1859 1858 +6873 1211 1212 1858 1857 +6874 1210 1211 1857 1856 +6875 1209 1210 1856 1855 +6876 1208 1209 1855 1854 +6877 1207 1208 1854 1853 +6878 1206 1207 1853 1852 +6879 1205 1206 1852 1851 +6880 1204 1205 1851 1850 +6881 1202 1204 1850 1849 +6882 1203 1202 1849 1848 +6883 1271 1203 1848 1847 +6884 1272 1271 1847 1845 +6885 1272 1845 1846 1844 +6886 1201 1272 1844 1843 +6887 1200 1201 1843 1842 +6888 1199 1200 1842 1841 +6889 1198 1199 1841 1840 +6890 1197 1198 1840 1839 +6891 1196 1197 1839 1838 +6892 1195 1196 1838 1837 +6893 1194 1195 1837 1836 +6894 1193 1194 1836 1835 +6895 1192 1193 1835 1834 +6896 1191 1192 1834 1833 +6897 1190 1191 1833 1832 +6898 1189 1190 1832 1831 +6899 1188 1189 1831 1830 +6900 1187 1188 1830 1829 +6901 1186 1187 1829 1828 +6902 1185 1186 1828 1827 +6903 1184 1185 1827 1826 +6904 1183 1184 1826 1825 +6905 1182 1183 1825 1824 +6906 1181 1182 1824 1823 +6907 1180 1181 1823 1822 +6908 1179 1180 1822 1821 +6909 1178 1179 1821 1820 +6910 1176 1178 1820 1819 +6911 1177 1176 1819 1818 +6912 1273 1177 1818 1817 +6913 1274 1273 1817 1815 +6914 1274 1815 1816 1814 +6915 1175 1274 1814 1813 +6916 1174 1175 1813 1812 +6917 1173 1174 1812 1811 +6918 1172 1173 1811 1810 +6919 1171 1172 1810 1809 +6920 1170 1171 1809 1808 +6921 1169 1170 1808 1807 +6922 1168 1169 1807 1806 +6923 1167 1168 1806 1805 +6924 1166 1167 1805 1804 +6925 1165 1166 1804 1802 +6926 1164 1165 1802 1803 +6927 1162 1163 1801 1800 +6928 1161 1162 1800 1799 +6929 1160 1161 1799 1798 +6930 1159 1160 1798 1797 +6931 1158 1159 1797 1796 +6932 1157 1158 1796 1795 +6933 1156 1157 1795 1794 +6934 1155 1156 1794 1793 +6935 1154 1155 1793 1792 +6936 1153 1154 1792 1791 +6937 1152 1153 1791 1790 +6938 1150 1152 1790 1789 +6939 1151 1150 1789 1788 +6940 1275 1151 1788 1787 +6941 1276 1275 1787 1785 +6942 1276 1785 1786 1784 +6943 1149 1276 1784 1783 +6944 1148 1149 1783 1782 +6945 1147 1148 1782 1781 +6946 1146 1147 1781 1780 +6947 1145 1146 1780 1779 +6948 1144 1145 1779 1778 +6949 1143 1144 1778 1777 +6950 1142 1143 1777 1776 +6951 1141 1142 1776 1775 +6952 1140 1141 1775 1774 +6953 1139 1140 1774 1773 +6954 1138 1139 1773 1771 +6955 1137 1138 1771 1772 +6956 1135 1136 1770 1769 +6957 1134 1135 1769 1768 +6958 1133 1134 1768 1767 +6959 1132 1133 1767 1766 +6960 1131 1132 1766 1765 +6961 1130 1131 1765 1764 +6962 1129 1130 1764 1763 +6963 1128 1129 1763 1762 +6964 1127 1128 1762 1761 +6965 1126 1127 1761 1760 +6966 1125 1126 1760 1759 +6967 1123 1125 1759 1758 +6968 1124 1123 1758 1662 +6969 1372 1373 1374 1757 +6970 1371 1372 1757 1756 +6971 1370 1371 1756 1755 +6972 1369 1370 1755 1754 +6973 1368 1369 1754 1753 +6974 1367 1368 1753 1752 +6975 1366 1367 1752 1751 +6976 1365 1366 1751 1750 +6977 1364 1365 1750 1749 +6978 1363 1364 1749 1748 +6979 1362 1363 1748 1747 +6980 1361 1362 1747 1746 +6981 1360 1361 1746 1745 +6982 1359 1360 1745 1744 +6983 1358 1359 1744 1743 +6984 1357 1358 1743 1742 +6985 1356 1357 1742 1741 +6986 1355 1356 1741 1740 +6987 1354 1355 1740 1739 +6988 1353 1354 1739 1738 +6989 1352 1353 1738 1737 +6990 1351 1352 1737 1736 +6991 1350 1351 1736 1735 +6992 1349 1350 1735 1734 +6993 1348 1349 1734 1733 +6994 1347 1348 1733 1732 +6995 1346 1347 1732 1731 +6996 1345 1346 1731 1730 +6997 1344 1345 1730 1729 +6998 1343 1344 1729 1728 +6999 1342 1343 1728 1727 +7000 1341 1342 1727 1726 +7001 1340 1341 1726 1725 +7002 1339 1340 1725 1724 +7003 1338 1339 1724 1723 +7004 1337 1338 1723 1722 +7005 1336 1337 1722 1721 +7006 1335 1336 1721 1720 +7007 1334 1335 1720 1719 +7008 1333 1334 1719 1718 +7009 1332 1333 1718 1717 +7010 1331 1332 1717 1716 +7011 1330 1331 1716 1715 +7012 1329 1330 1715 1714 +7013 1328 1329 1714 1713 +7014 1327 1328 1713 1712 +7015 1326 1327 1712 1711 +7016 1325 1326 1711 1710 +7017 1324 1325 1710 1709 +7018 1323 1324 1709 1708 +7019 1322 1323 1708 1707 +7020 1321 1322 1707 1706 +7021 1320 1321 1706 1705 +7022 1319 1320 1705 1704 +7023 1318 1319 1704 1703 +7024 1317 1318 1703 1702 +7025 1316 1317 1702 1701 +7026 1315 1316 1701 1700 +7027 1314 1315 1700 1699 +7028 1313 1314 1699 1698 +7029 1312 1313 1698 1697 +7030 1311 1312 1697 1696 +7031 1310 1311 1696 1695 +7032 1309 1310 1695 1694 +7033 1308 1309 1694 1693 +7034 1307 1308 1693 1692 +7035 1306 1307 1692 1691 +7036 1305 1306 1691 1690 +7037 1304 1305 1690 1689 +7038 1303 1304 1689 1688 +7039 1302 1303 1688 1687 +7040 1301 1302 1687 1686 +7041 1300 1301 1686 1685 +7042 1299 1300 1685 1684 +7043 1298 1299 1684 1683 +7044 1297 1298 1683 1682 +7045 1296 1297 1682 1681 +7046 1295 1296 1681 1680 +7047 1294 1295 1680 1679 +7048 1293 1294 1679 1678 +7049 1292 1293 1678 1677 +7050 1291 1292 1677 1676 +7051 1290 1291 1676 1675 +7052 1289 1290 1675 1674 +7053 1288 1289 1674 1673 +7054 1287 1288 1673 1672 +7055 1286 1287 1672 1671 +7056 1285 1286 1671 1670 +7057 1284 1285 1670 1669 +7058 1283 1284 1669 1668 +7059 1282 1283 1668 1667 +7060 1281 1282 1667 1666 +7061 1280 1281 1666 1665 +7062 1279 1280 1665 1664 +7063 1278 1279 1664 1663 +7064 1277 1278 1663 1565 +7065 1661 1122 1124 1662 +7066 1106 1108 1470 1660 +7067 1104 1106 1660 1659 +7068 1102 1104 1659 1658 +7069 1100 1102 1658 1657 +7070 1098 1100 1657 1656 +7071 1096 1098 1656 1655 +7072 1094 1096 1655 1654 +7073 1092 1094 1654 1653 +7074 1090 1092 1653 1652 +7075 1088 1090 1652 1651 +7076 1086 1088 1651 1650 +7077 1084 1086 1650 1649 +7078 1082 1084 1649 1648 +7079 1080 1082 1648 1647 +7080 1078 1080 1647 1646 +7081 1076 1078 1646 1645 +7082 1074 1076 1645 1644 +7083 1072 1074 1644 1643 +7084 1070 1072 1643 1642 +7085 1068 1070 1642 1641 +7086 1066 1068 1641 1640 +7087 1064 1066 1640 1639 +7088 1062 1064 1639 1638 +7089 1060 1062 1638 1637 +7090 1058 1060 1637 1636 +7091 1056 1058 1636 1635 +7092 1054 1056 1635 1634 +7093 1052 1054 1634 1633 +7094 1050 1052 1633 1632 +7095 1048 1050 1632 1631 +7096 1046 1048 1631 1630 +7097 1044 1046 1630 1629 +7098 1042 1044 1629 1628 +7099 1040 1042 1628 1627 +7100 1038 1040 1627 1626 +7101 1036 1038 1626 1625 +7102 1034 1036 1625 1624 +7103 1032 1034 1624 1623 +7104 1030 1032 1623 1622 +7105 1028 1030 1622 1621 +7106 1026 1028 1621 1620 +7107 1024 1026 1620 1619 +7108 1022 1024 1619 1618 +7109 1020 1022 1618 1617 +7110 1018 1020 1617 1616 +7111 1016 1018 1616 1615 +7112 1014 1016 1615 1614 +7113 1012 1014 1614 1613 +7114 1010 1012 1613 1612 +7115 1008 1010 1612 1611 +7116 1006 1008 1611 1610 +7117 1004 1006 1610 1609 +7118 1002 1004 1609 1608 +7119 1000 1002 1608 1607 +7120 998 1000 1607 1606 +7121 996 998 1606 1605 +7122 994 996 1605 1604 +7123 992 994 1604 1603 +7124 990 992 1603 1602 +7125 988 990 1602 1601 +7126 986 988 1601 1600 +7127 984 986 1600 1599 +7128 982 984 1599 1598 +7129 980 982 1598 1597 +7130 978 980 1597 1596 +7131 976 978 1596 1595 +7132 974 976 1595 1594 +7133 972 974 1594 1593 +7134 970 972 1593 1592 +7135 968 970 1592 1591 +7136 966 968 1591 1590 +7137 964 966 1590 1589 +7138 962 964 1589 1588 +7139 960 962 1588 1587 +7140 958 960 1587 1586 +7141 956 958 1586 1585 +7142 954 956 1585 1584 +7143 952 954 1584 1583 +7144 950 952 1583 1582 +7145 948 950 1582 1581 +7146 946 948 1581 1580 +7147 944 946 1580 1579 +7148 942 944 1579 1578 +7149 940 942 1578 1577 +7150 938 940 1577 1576 +7151 936 938 1576 1575 +7152 934 936 1575 1574 +7153 932 934 1574 1573 +7154 930 932 1573 1572 +7155 928 930 1572 1571 +7156 926 928 1571 1570 +7157 924 926 1570 1569 +7158 922 924 1569 1568 +7159 920 922 1568 1567 +7160 918 920 1567 1566 +7161 916 918 1566 1469 +7162 512 514 1277 1565 +7163 510 512 1565 1564 +7164 508 510 1564 1563 +7165 506 508 1563 1562 +7166 504 506 1562 1561 +7167 502 504 1561 1560 +7168 500 502 1560 1559 +7169 498 500 1559 1558 +7170 496 498 1558 1557 +7171 494 496 1557 1556 +7172 492 494 1556 1555 +7173 490 492 1555 1554 +7174 488 490 1554 1553 +7175 486 488 1553 1552 +7176 484 486 1552 1551 +7177 482 484 1551 1550 +7178 480 482 1550 1549 +7179 478 480 1549 1548 +7180 476 478 1548 1547 +7181 474 476 1547 1546 +7182 472 474 1546 1545 +7183 470 472 1545 1544 +7184 468 470 1544 1543 +7185 466 468 1543 1542 +7186 464 466 1542 1541 +7187 462 464 1541 1540 +7188 460 462 1540 1539 +7189 458 460 1539 1538 +7190 456 458 1538 1537 +7191 454 456 1537 1536 +7192 452 454 1536 1535 +7193 450 452 1535 1534 +7194 448 450 1534 1533 +7195 446 448 1533 1532 +7196 444 446 1532 1531 +7197 442 444 1531 1530 +7198 440 442 1530 1529 +7199 438 440 1529 1528 +7200 436 438 1528 1527 +7201 434 436 1527 1526 +7202 432 434 1526 1525 +7203 430 432 1525 1524 +7204 428 430 1524 1523 +7205 426 428 1523 1522 +7206 424 426 1522 1521 +7207 422 424 1521 1520 +7208 420 422 1520 1519 +7209 418 420 1519 1518 +7210 416 418 1518 1517 +7211 414 416 1517 1516 +7212 412 414 1516 1515 +7213 410 412 1515 1514 +7214 408 410 1514 1513 +7215 406 408 1513 1512 +7216 404 406 1512 1511 +7217 402 404 1511 1510 +7218 400 402 1510 1509 +7219 398 400 1509 1508 +7220 396 398 1508 1507 +7221 394 396 1507 1506 +7222 392 394 1506 1505 +7223 390 392 1505 1504 +7224 388 390 1504 1503 +7225 386 388 1503 1502 +7226 384 386 1502 1501 +7227 382 384 1501 1500 +7228 380 382 1500 1499 +7229 378 380 1499 1498 +7230 376 378 1498 1497 +7231 374 376 1497 1496 +7232 372 374 1496 1495 +7233 370 372 1495 1494 +7234 368 370 1494 1493 +7235 366 368 1493 1492 +7236 364 366 1492 1491 +7237 362 364 1491 1490 +7238 360 362 1490 1489 +7239 358 360 1489 1488 +7240 356 358 1488 1487 +7241 354 356 1487 1486 +7242 352 354 1486 1485 +7243 350 352 1485 1484 +7244 348 350 1484 1483 +7245 346 348 1483 1482 +7246 344 346 1482 1481 +7247 342 344 1481 1480 +7248 340 342 1480 1479 +7249 338 340 1479 1478 +7250 336 338 1478 1477 +7251 334 336 1477 1476 +7252 332 334 1476 1475 +7253 330 332 1475 1474 +7254 328 330 1474 1473 +7255 326 328 1473 1472 +7256 324 326 1472 1471 +7257 322 324 1471 1470 +7258 319 322 1470 1108 +7259 716 718 916 1469 +7260 714 716 1469 1468 +7261 712 714 1468 1467 +7262 710 712 1467 1466 +7263 708 710 1466 1465 +7264 706 708 1465 1464 +7265 704 706 1464 1463 +7266 702 704 1463 1462 +7267 700 702 1462 1461 +7268 698 700 1461 1460 +7269 696 698 1460 1459 +7270 694 696 1459 1458 +7271 692 694 1458 1457 +7272 690 692 1457 1456 +7273 688 690 1456 1455 +7274 686 688 1455 1454 +7275 684 686 1454 1453 +7276 682 684 1453 1452 +7277 680 682 1452 1451 +7278 678 680 1451 1450 +7279 676 678 1450 1449 +7280 674 676 1449 1448 +7281 672 674 1448 1447 +7282 670 672 1447 1446 +7283 668 670 1446 1445 +7284 666 668 1445 1444 +7285 664 666 1444 1443 +7286 662 664 1443 1442 +7287 660 662 1442 1441 +7288 658 660 1441 1440 +7289 656 658 1440 1439 +7290 654 656 1439 1438 +7291 652 654 1438 1437 +7292 650 652 1437 1436 +7293 648 650 1436 1435 +7294 646 648 1435 1434 +7295 644 646 1434 1433 +7296 642 644 1433 1432 +7297 640 642 1432 1431 +7298 638 640 1431 1430 +7299 636 638 1430 1429 +7300 634 636 1429 1428 +7301 632 634 1428 1427 +7302 630 632 1427 1426 +7303 628 630 1426 1425 +7304 626 628 1425 1424 +7305 624 626 1424 1423 +7306 622 624 1423 1422 +7307 620 622 1422 1421 +7308 618 620 1421 1420 +7309 616 618 1420 1419 +7310 614 616 1419 1418 +7311 612 614 1418 1417 +7312 610 612 1417 1416 +7313 608 610 1416 1415 +7314 606 608 1415 1414 +7315 604 606 1414 1413 +7316 602 604 1413 1412 +7317 600 602 1412 1411 +7318 598 600 1411 1410 +7319 596 598 1410 1409 +7320 594 596 1409 1408 +7321 592 594 1408 1407 +7322 590 592 1407 1406 +7323 588 590 1406 1405 +7324 586 588 1405 1404 +7325 584 586 1404 1403 +7326 582 584 1403 1402 +7327 580 582 1402 1401 +7328 578 580 1401 1400 +7329 576 578 1400 1399 +7330 574 576 1399 1398 +7331 572 574 1398 1397 +7332 570 572 1397 1396 +7333 568 570 1396 1395 +7334 566 568 1395 1394 +7335 564 566 1394 1393 +7336 562 564 1393 1392 +7337 560 562 1392 1391 +7338 558 560 1391 1390 +7339 556 558 1390 1389 +7340 554 556 1389 1388 +7341 552 554 1388 1387 +7342 550 552 1387 1386 +7343 548 550 1386 1385 +7344 546 548 1385 1384 +7345 544 546 1384 1383 +7346 542 544 1383 1382 +7347 540 542 1382 1381 +7348 538 540 1381 1380 +7349 536 538 1380 1379 +7350 534 536 1379 1378 +7351 532 534 1378 1377 +7352 530 532 1377 1376 +7353 528 530 1376 1375 +7354 526 528 1375 1374 +7355 524 526 1374 1373 +7356 914 521 524 1373 +7357 912 914 1373 1372 +7358 910 912 1372 1371 +7359 908 910 1371 1370 +7360 906 908 1370 1369 +7361 904 906 1369 1368 +7362 902 904 1368 1367 +7363 900 902 1367 1366 +7364 898 900 1366 1365 +7365 896 898 1365 1364 +7366 894 896 1364 1363 +7367 892 894 1363 1362 +7368 890 892 1362 1361 +7369 888 890 1361 1360 +7370 886 888 1360 1359 +7371 884 886 1359 1358 +7372 882 884 1358 1357 +7373 880 882 1357 1356 +7374 878 880 1356 1355 +7375 876 878 1355 1354 +7376 874 876 1354 1353 +7377 872 874 1353 1352 +7378 870 872 1352 1351 +7379 868 870 1351 1350 +7380 866 868 1350 1349 +7381 864 866 1349 1348 +7382 862 864 1348 1347 +7383 860 862 1347 1346 +7384 858 860 1346 1345 +7385 856 858 1345 1344 +7386 854 856 1344 1343 +7387 852 854 1343 1342 +7388 850 852 1342 1341 +7389 848 850 1341 1340 +7390 846 848 1340 1339 +7391 844 846 1339 1338 +7392 842 844 1338 1337 +7393 840 842 1337 1336 +7394 838 840 1336 1335 +7395 836 838 1335 1334 +7396 834 836 1334 1333 +7397 832 834 1333 1332 +7398 830 832 1332 1331 +7399 828 830 1331 1330 +7400 826 828 1330 1329 +7401 824 826 1329 1328 +7402 822 824 1328 1327 +7403 820 822 1327 1326 +7404 818 820 1326 1325 +7405 816 818 1325 1324 +7406 814 816 1324 1323 +7407 812 814 1323 1322 +7408 810 812 1322 1321 +7409 808 810 1321 1320 +7410 806 808 1320 1319 +7411 804 806 1319 1318 +7412 802 804 1318 1317 +7413 800 802 1317 1316 +7414 798 800 1316 1315 +7415 796 798 1315 1314 +7416 794 796 1314 1313 +7417 792 794 1313 1312 +7418 790 792 1312 1311 +7419 788 790 1311 1310 +7420 786 788 1310 1309 +7421 784 786 1309 1308 +7422 782 784 1308 1307 +7423 780 782 1307 1306 +7424 778 780 1306 1305 +7425 776 778 1305 1304 +7426 774 776 1304 1303 +7427 772 774 1303 1302 +7428 770 772 1302 1301 +7429 768 770 1301 1300 +7430 766 768 1300 1299 +7431 764 766 1299 1298 +7432 762 764 1298 1297 +7433 760 762 1297 1296 +7434 758 760 1296 1295 +7435 756 758 1295 1294 +7436 754 756 1294 1293 +7437 752 754 1293 1292 +7438 750 752 1292 1291 +7439 748 750 1291 1290 +7440 746 748 1290 1289 +7441 744 746 1289 1288 +7442 742 744 1288 1287 +7443 740 742 1287 1286 +7444 738 740 1286 1285 +7445 736 738 1285 1284 +7446 734 736 1284 1283 +7447 732 734 1283 1282 +7448 730 732 1282 1281 +7449 728 730 1281 1280 +7450 726 728 1280 1279 +7451 724 726 1279 1278 +7452 722 724 1278 1277 +7453 516 722 1277 514 +7454 30 32 1124 1122 +7455 1149 84 1275 1276 +7456 84 86 1151 1275 +7457 1175 136 1273 1274 +7458 136 138 1177 1273 +7459 1201 188 1271 1272 +7460 188 190 1203 1271 +7461 1228 242 1269 1270 +7462 242 244 1230 1269 +7463 1254 294 1267 1268 +7464 294 296 1256 1267 +7465 4 3 1110 1266 +7466 316 4 1266 1265 +7467 314 316 1265 1264 +7468 312 314 1264 1263 +7469 310 312 1263 1262 +7470 308 310 1262 1261 +7471 306 308 1261 1260 +7472 304 306 1260 1259 +7473 302 304 1259 1258 +7474 300 302 1258 1257 +7475 298 300 1257 1255 +7476 296 298 1255 1256 +7477 292 294 1254 1253 +7478 290 292 1253 1252 +7479 288 290 1252 1251 +7480 286 288 1251 1250 +7481 284 286 1250 1249 +7482 282 284 1249 1248 +7483 280 282 1248 1247 +7484 278 280 1247 1246 +7485 276 278 1246 1245 +7486 274 276 1245 1244 +7487 272 274 1244 1243 +7488 270 272 1243 1242 +7489 268 270 1242 1241 +7490 266 268 1241 1240 +7491 264 266 1240 1239 +7492 262 264 1239 1238 +7493 260 262 1238 1237 +7494 258 260 1237 1236 +7495 256 258 1236 1235 +7496 254 256 1235 1234 +7497 252 254 1234 1233 +7498 250 252 1233 1232 +7499 248 250 1232 1231 +7500 246 248 1231 1229 +7501 244 246 1229 1230 +7502 240 242 1228 1227 +7503 238 240 1227 1226 +7504 236 238 1226 1225 +7505 234 236 1225 1224 +7506 232 234 1224 1223 +7507 230 232 1223 1222 +7508 228 230 1222 1221 +7509 226 228 1221 1220 +7510 224 226 1220 1219 +7511 222 224 1219 1218 +7512 220 222 1218 1217 +7513 218 220 1217 1216 +7514 216 218 1216 1215 +7515 214 216 1215 1214 +7516 212 214 1214 1213 +7517 210 212 1213 1212 +7518 208 210 1212 1211 +7519 206 208 1211 1210 +7520 204 206 1210 1209 +7521 202 204 1209 1208 +7522 200 202 1208 1207 +7523 198 200 1207 1206 +7524 196 198 1206 1205 +7525 194 196 1205 1204 +7526 192 194 1204 1202 +7527 190 192 1202 1203 +7528 186 188 1201 1200 +7529 184 186 1200 1199 +7530 182 184 1199 1198 +7531 180 182 1198 1197 +7532 178 180 1197 1196 +7533 176 178 1196 1195 +7534 174 176 1195 1194 +7535 172 174 1194 1193 +7536 170 172 1193 1192 +7537 168 170 1192 1191 +7538 166 168 1191 1190 +7539 164 166 1190 1189 +7540 162 164 1189 1188 +7541 160 162 1188 1187 +7542 158 160 1187 1186 +7543 156 158 1186 1185 +7544 154 156 1185 1184 +7545 152 154 1184 1183 +7546 150 152 1183 1182 +7547 148 150 1182 1181 +7548 146 148 1181 1180 +7549 144 146 1180 1179 +7550 142 144 1179 1178 +7551 140 142 1178 1176 +7552 138 140 1176 1177 +7553 134 136 1175 1174 +7554 132 134 1174 1173 +7555 130 132 1173 1172 +7556 128 130 1172 1171 +7557 126 128 1171 1170 +7558 124 126 1170 1169 +7559 122 124 1169 1168 +7560 120 122 1168 1167 +7561 118 120 1167 1166 +7562 116 118 1166 1165 +7563 114 116 1165 1164 +7564 112 114 1164 1163 +7565 110 112 1163 1162 +7566 108 110 1162 1161 +7567 106 108 1161 1160 +7568 104 106 1160 1159 +7569 102 104 1159 1158 +7570 100 102 1158 1157 +7571 98 100 1157 1156 +7572 96 98 1156 1155 +7573 94 96 1155 1154 +7574 92 94 1154 1153 +7575 90 92 1153 1152 +7576 88 90 1152 1150 +7577 86 88 1150 1151 +7578 82 84 1149 1148 +7579 80 82 1148 1147 +7580 78 80 1147 1146 +7581 76 78 1146 1145 +7582 74 76 1145 1144 +7583 72 74 1144 1143 +7584 70 72 1143 1142 +7585 68 70 1142 1141 +7586 66 68 1141 1140 +7587 64 66 1140 1139 +7588 62 64 1139 1138 +7589 60 62 1138 1137 +7590 58 60 1137 1136 +7591 56 58 1136 1135 +7592 54 56 1135 1134 +7593 52 54 1134 1133 +7594 50 52 1133 1132 +7595 48 50 1132 1131 +7596 46 48 1131 1130 +7597 44 46 1130 1129 +7598 42 44 1129 1128 +7599 40 42 1128 1127 +7600 38 40 1127 1126 +7601 36 38 1126 1125 +7602 34 36 1125 1123 +7603 32 34 1123 1124 +7604 28 30 1122 1121 +7605 26 28 1121 1120 +7606 24 26 1120 1119 +7607 22 24 1119 1118 +7608 20 22 1118 1117 +7609 18 20 1117 1116 +7610 16 18 1116 1115 +7611 14 16 1115 1114 +7612 12 14 1114 1113 +7613 10 12 1113 1112 +7614 8 10 1112 1111 +7615 6 8 1111 1109 +7616 3 6 1109 1110 +7617 1107 320 319 1108 +7618 1105 1107 1108 1106 +7619 1103 1105 1106 1104 +7620 1101 1103 1104 1102 +7621 1099 1101 1102 1100 +7622 1097 1099 1100 1098 +7623 1095 1097 1098 1096 +7624 1093 1095 1096 1094 +7625 1091 1093 1094 1092 +7626 1089 1091 1092 1090 +7627 1087 1089 1090 1088 +7628 1085 1087 1088 1086 +7629 1083 1085 1086 1084 +7630 1081 1083 1084 1082 +7631 1079 1081 1082 1080 +7632 1077 1079 1080 1078 +7633 1075 1077 1078 1076 +7634 1073 1075 1076 1074 +7635 1071 1073 1074 1072 +7636 1069 1071 1072 1070 +7637 1067 1069 1070 1068 +7638 1065 1067 1068 1066 +7639 1063 1065 1066 1064 +7640 1061 1063 1064 1062 +7641 1059 1061 1062 1060 +7642 1057 1059 1060 1058 +7643 1055 1057 1058 1056 +7644 1053 1055 1056 1054 +7645 1051 1053 1054 1052 +7646 1049 1051 1052 1050 +7647 1047 1049 1050 1048 +7648 1045 1047 1048 1046 +7649 1043 1045 1046 1044 +7650 1041 1043 1044 1042 +7651 1039 1041 1042 1040 +7652 1037 1039 1040 1038 +7653 1035 1037 1038 1036 +7654 1033 1035 1036 1034 +7655 1031 1033 1034 1032 +7656 1029 1031 1032 1030 +7657 1027 1029 1030 1028 +7658 1025 1027 1028 1026 +7659 1023 1025 1026 1024 +7660 1021 1023 1024 1022 +7661 1019 1021 1022 1020 +7662 1017 1019 1020 1018 +7663 1015 1017 1018 1016 +7664 1013 1015 1016 1014 +7665 1011 1013 1014 1012 +7666 1009 1011 1012 1010 +7667 1007 1009 1010 1008 +7668 1005 1007 1008 1006 +7669 1003 1005 1006 1004 +7670 1001 1003 1004 1002 +7671 999 1001 1002 1000 +7672 997 999 1000 998 +7673 995 997 998 996 +7674 993 995 996 994 +7675 991 993 994 992 +7676 989 991 992 990 +7677 987 989 990 988 +7678 985 987 988 986 +7679 983 985 986 984 +7680 981 983 984 982 +7681 979 981 982 980 +7682 977 979 980 978 +7683 975 977 978 976 +7684 973 975 976 974 +7685 971 973 974 972 +7686 969 971 972 970 +7687 967 969 970 968 +7688 965 967 968 966 +7689 963 965 966 964 +7690 961 963 964 962 +7691 959 961 962 960 +7692 957 959 960 958 +7693 955 957 958 956 +7694 953 955 956 954 +7695 951 953 954 952 +7696 949 951 952 950 +7697 947 949 950 948 +7698 945 947 948 946 +7699 943 945 946 944 +7700 941 943 944 942 +7701 939 941 942 940 +7702 937 939 940 938 +7703 935 937 938 936 +7704 933 935 936 934 +7705 931 933 934 932 +7706 929 931 932 930 +7707 927 929 930 928 +7708 925 927 928 926 +7709 923 925 926 924 +7710 921 923 924 922 +7711 919 921 922 920 +7712 917 919 920 918 +7713 915 917 918 916 +7714 720 915 916 718 +7715 913 522 521 914 +7716 911 913 914 912 +7717 909 911 912 910 +7718 907 909 910 908 +7719 905 907 908 906 +7720 903 905 906 904 +7721 901 903 904 902 +7722 899 901 902 900 +7723 897 899 900 898 +7724 895 897 898 896 +7725 893 895 896 894 +7726 891 893 894 892 +7727 889 891 892 890 +7728 887 889 890 888 +7729 885 887 888 886 +7730 883 885 886 884 +7731 881 883 884 882 +7732 879 881 882 880 +7733 877 879 880 878 +7734 875 877 878 876 +7735 873 875 876 874 +7736 871 873 874 872 +7737 869 871 872 870 +7738 867 869 870 868 +7739 865 867 868 866 +7740 863 865 866 864 +7741 861 863 864 862 +7742 859 861 862 860 +7743 857 859 860 858 +7744 855 857 858 856 +7745 853 855 856 854 +7746 851 853 854 852 +7747 849 851 852 850 +7748 847 849 850 848 +7749 845 847 848 846 +7750 843 845 846 844 +7751 841 843 844 842 +7752 839 841 842 840 +7753 837 839 840 838 +7754 835 837 838 836 +7755 833 835 836 834 +7756 831 833 834 832 +7757 829 831 832 830 +7758 827 829 830 828 +7759 825 827 828 826 +7760 823 825 826 824 +7761 821 823 824 822 +7762 819 821 822 820 +7763 817 819 820 818 +7764 815 817 818 816 +7765 813 815 816 814 +7766 811 813 814 812 +7767 809 811 812 810 +7768 807 809 810 808 +7769 805 807 808 806 +7770 803 805 806 804 +7771 801 803 804 802 +7772 799 801 802 800 +7773 797 799 800 798 +7774 795 797 798 796 +7775 793 795 796 794 +7776 791 793 794 792 +7777 789 791 792 790 +7778 787 789 790 788 +7779 785 787 788 786 +7780 783 785 786 784 +7781 781 783 784 782 +7782 779 781 782 780 +7783 777 779 780 778 +7784 775 777 778 776 +7785 773 775 776 774 +7786 771 773 774 772 +7787 769 771 772 770 +7788 767 769 770 768 +7789 765 767 768 766 +7790 763 765 766 764 +7791 761 763 764 762 +7792 759 761 762 760 +7793 757 759 760 758 +7794 755 757 758 756 +7795 753 755 756 754 +7796 751 753 754 752 +7797 749 751 752 750 +7798 747 749 750 748 +7799 745 747 748 746 +7800 743 745 746 744 +7801 741 743 744 742 +7802 739 741 742 740 +7803 737 739 740 738 +7804 735 737 738 736 +7805 733 735 736 734 +7806 731 733 734 732 +7807 729 731 732 730 +7808 727 729 730 728 +7809 725 727 728 726 +7810 723 725 726 724 +7811 721 723 724 722 +7812 518 721 722 516 +7813 717 719 720 718 +7814 715 717 718 716 +7815 713 715 716 714 +7816 711 713 714 712 +7817 709 711 712 710 +7818 707 709 710 708 +7819 705 707 708 706 +7820 703 705 706 704 +7821 701 703 704 702 +7822 699 701 702 700 +7823 697 699 700 698 +7824 695 697 698 696 +7825 693 695 696 694 +7826 691 693 694 692 +7827 689 691 692 690 +7828 687 689 690 688 +7829 685 687 688 686 +7830 683 685 686 684 +7831 681 683 684 682 +7832 679 681 682 680 +7833 677 679 680 678 +7834 675 677 678 676 +7835 673 675 676 674 +7836 671 673 674 672 +7837 669 671 672 670 +7838 667 669 670 668 +7839 665 667 668 666 +7840 663 665 666 664 +7841 661 663 664 662 +7842 659 661 662 660 +7843 657 659 660 658 +7844 655 657 658 656 +7845 653 655 656 654 +7846 651 653 654 652 +7847 649 651 652 650 +7848 647 649 650 648 +7849 645 647 648 646 +7850 643 645 646 644 +7851 641 643 644 642 +7852 639 641 642 640 +7853 637 639 640 638 +7854 635 637 638 636 +7855 633 635 636 634 +7856 631 633 634 632 +7857 629 631 632 630 +7858 627 629 630 628 +7859 625 627 628 626 +7860 623 625 626 624 +7861 621 623 624 622 +7862 619 621 622 620 +7863 617 619 620 618 +7864 615 617 618 616 +7865 613 615 616 614 +7866 611 613 614 612 +7867 609 611 612 610 +7868 607 609 610 608 +7869 605 607 608 606 +7870 603 605 606 604 +7871 601 603 604 602 +7872 599 601 602 600 +7873 597 599 600 598 +7874 595 597 598 596 +7875 593 595 596 594 +7876 591 593 594 592 +7877 589 591 592 590 +7878 587 589 590 588 +7879 585 587 588 586 +7880 583 585 586 584 +7881 581 583 584 582 +7882 579 581 582 580 +7883 577 579 580 578 +7884 575 577 578 576 +7885 573 575 576 574 +7886 571 573 574 572 +7887 569 571 572 570 +7888 567 569 570 568 +7889 565 567 568 566 +7890 563 565 566 564 +7891 561 563 564 562 +7892 559 561 562 560 +7893 557 559 560 558 +7894 555 557 558 556 +7895 553 555 556 554 +7896 551 553 554 552 +7897 549 551 552 550 +7898 547 549 550 548 +7899 545 547 548 546 +7900 543 545 546 544 +7901 541 543 544 542 +7902 539 541 542 540 +7903 537 539 540 538 +7904 535 537 538 536 +7905 533 535 536 534 +7906 531 533 534 532 +7907 529 531 532 530 +7908 527 529 530 528 +7909 525 527 528 526 +7910 523 525 526 524 +7911 520 523 524 521 +7912 519 520 521 522 +7913 515 517 518 516 +7914 513 515 516 514 +7915 511 513 514 512 +7916 509 511 512 510 +7917 507 509 510 508 +7918 505 507 508 506 +7919 503 505 506 504 +7920 501 503 504 502 +7921 499 501 502 500 +7922 497 499 500 498 +7923 495 497 498 496 +7924 493 495 496 494 +7925 491 493 494 492 +7926 489 491 492 490 +7927 487 489 490 488 +7928 485 487 488 486 +7929 483 485 486 484 +7930 481 483 484 482 +7931 479 481 482 480 +7932 477 479 480 478 +7933 475 477 478 476 +7934 473 475 476 474 +7935 471 473 474 472 +7936 469 471 472 470 +7937 467 469 470 468 +7938 465 467 468 466 +7939 463 465 466 464 +7940 461 463 464 462 +7941 459 461 462 460 +7942 457 459 460 458 +7943 455 457 458 456 +7944 453 455 456 454 +7945 451 453 454 452 +7946 449 451 452 450 +7947 447 449 450 448 +7948 445 447 448 446 +7949 443 445 446 444 +7950 441 443 444 442 +7951 439 441 442 440 +7952 437 439 440 438 +7953 435 437 438 436 +7954 433 435 436 434 +7955 431 433 434 432 +7956 429 431 432 430 +7957 427 429 430 428 +7958 425 427 428 426 +7959 423 425 426 424 +7960 421 423 424 422 +7961 419 421 422 420 +7962 417 419 420 418 +7963 415 417 418 416 +7964 413 415 416 414 +7965 411 413 414 412 +7966 409 411 412 410 +7967 407 409 410 408 +7968 405 407 408 406 +7969 403 405 406 404 +7970 401 403 404 402 +7971 399 401 402 400 +7972 397 399 400 398 +7973 395 397 398 396 +7974 393 395 396 394 +7975 391 393 394 392 +7976 389 391 392 390 +7977 387 389 390 388 +7978 385 387 388 386 +7979 383 385 386 384 +7980 381 383 384 382 +7981 379 381 382 380 +7982 377 379 380 378 +7983 375 377 378 376 +7984 373 375 376 374 +7985 371 373 374 372 +7986 369 371 372 370 +7987 367 369 370 368 +7988 365 367 368 366 +7989 363 365 366 364 +7990 361 363 364 362 +7991 359 361 362 360 +7992 357 359 360 358 +7993 355 357 358 356 +7994 353 355 356 354 +7995 351 353 354 352 +7996 349 351 352 350 +7997 347 349 350 348 +7998 345 347 348 346 +7999 343 345 346 344 +8000 341 343 344 342 +8001 339 341 342 340 +8002 337 339 340 338 +8003 335 337 338 336 +8004 333 335 336 334 +8005 331 333 334 332 +8006 329 331 332 330 +8007 327 329 330 328 +8008 325 327 328 326 +8009 323 325 326 324 +8010 321 323 324 322 +8011 318 321 322 319 +8012 317 318 319 320 +8013 315 1 4 316 +8014 313 315 316 314 +8015 311 313 314 312 +8016 309 311 312 310 +8017 307 309 310 308 +8018 305 307 308 306 +8019 303 305 306 304 +8020 301 303 304 302 +8021 299 301 302 300 +8022 297 299 300 298 +8023 295 297 298 296 +8024 293 295 296 294 +8025 291 293 294 292 +8026 289 291 292 290 +8027 287 289 290 288 +8028 285 287 288 286 +8029 283 285 286 284 +8030 281 283 284 282 +8031 279 281 282 280 +8032 277 279 280 278 +8033 275 277 278 276 +8034 273 275 276 274 +8035 271 273 274 272 +8036 269 271 272 270 +8037 267 269 270 268 +8038 265 267 268 266 +8039 263 265 266 264 +8040 261 263 264 262 +8041 259 261 262 260 +8042 257 259 260 258 +8043 255 257 258 256 +8044 253 255 256 254 +8045 251 253 254 252 +8046 249 251 252 250 +8047 247 249 250 248 +8048 245 247 248 246 +8049 243 245 246 244 +8050 241 243 244 242 +8051 239 241 242 240 +8052 237 239 240 238 +8053 235 237 238 236 +8054 233 235 236 234 +8055 231 233 234 232 +8056 229 231 232 230 +8057 227 229 230 228 +8058 225 227 228 226 +8059 223 225 226 224 +8060 221 223 224 222 +8061 219 221 222 220 +8062 217 219 220 218 +8063 215 217 218 216 +8064 213 215 216 214 +8065 211 213 214 212 +8066 209 211 212 210 +8067 207 209 210 208 +8068 205 207 208 206 +8069 203 205 206 204 +8070 201 203 204 202 +8071 199 201 202 200 +8072 197 199 200 198 +8073 195 197 198 196 +8074 193 195 196 194 +8075 191 193 194 192 +8076 189 191 192 190 +8077 187 189 190 188 +8078 185 187 188 186 +8079 183 185 186 184 +8080 181 183 184 182 +8081 179 181 182 180 +8082 177 179 180 178 +8083 175 177 178 176 +8084 173 175 176 174 +8085 171 173 174 172 +8086 169 171 172 170 +8087 167 169 170 168 +8088 165 167 168 166 +8089 163 165 166 164 +8090 161 163 164 162 +8091 159 161 162 160 +8092 157 159 160 158 +8093 155 157 158 156 +8094 153 155 156 154 +8095 151 153 154 152 +8096 149 151 152 150 +8097 147 149 150 148 +8098 145 147 148 146 +8099 143 145 146 144 +8100 141 143 144 142 +8101 139 141 142 140 +8102 137 139 140 138 +8103 135 137 138 136 +8104 133 135 136 134 +8105 131 133 134 132 +8106 129 131 132 130 +8107 127 129 130 128 +8108 125 127 128 126 +8109 123 125 126 124 +8110 121 123 124 122 +8111 119 121 122 120 +8112 117 119 120 118 +8113 115 117 118 116 +8114 113 115 116 114 +8115 111 113 114 112 +8116 109 111 112 110 +8117 107 109 110 108 +8118 105 107 108 106 +8119 103 105 106 104 +8120 101 103 104 102 +8121 99 101 102 100 +8122 97 99 100 98 +8123 95 97 98 96 +8124 93 95 96 94 +8125 91 93 94 92 +8126 89 91 92 90 +8127 87 89 90 88 +8128 85 87 88 86 +8129 83 85 86 84 +8130 81 83 84 82 +8131 79 81 82 80 +8132 77 79 80 78 +8133 75 77 78 76 +8134 73 75 76 74 +8135 71 73 74 72 +8136 69 71 72 70 +8137 67 69 70 68 +8138 65 67 68 66 +8139 63 65 66 64 +8140 61 63 64 62 +8141 59 61 62 60 +8142 57 59 60 58 +8143 55 57 58 56 +8144 53 55 56 54 +8145 51 53 54 52 +8146 49 51 52 50 +8147 47 49 50 48 +8148 45 47 48 46 +8149 43 45 46 44 +8150 41 43 44 42 +8151 39 41 42 40 +8152 37 39 40 38 +8153 35 37 38 36 +8154 33 35 36 34 +8155 31 33 34 32 +8156 29 31 32 30 +8157 27 29 30 28 +8158 25 27 28 26 +8159 23 25 26 24 +8160 21 23 24 22 +8161 19 21 22 20 +8162 17 19 20 18 +8163 15 17 18 16 +8164 13 15 16 14 +8165 11 13 14 12 +8166 9 11 12 10 +8167 7 9 10 8 +8168 5 7 8 6 +8169 2 5 6 3 +8170 1 2 3 4 +$EndElements diff --git a/tests/grid/grids/grid_in_msh_01.2d.v4.msh b/tests/grid/grids/grid_in_msh_01.2d.v4.msh new file mode 100644 index 000000000000..f21e589ef9d0 --- /dev/null +++ b/tests/grid/grids/grid_in_msh_01.2d.v4.msh @@ -0,0 +1,36 @@ +$MeshFormat +4 0 8 +$EndMeshFormat +$Entities +0 4 1 0 +1 0 0 0 1 0 0 1 1 0 +2 1 0 0 1 1 0 1 1 0 +3 0 1 0 1 1 0 1 1 0 +4 0 0 0 0 1 0 1 1 0 +6 0 0 0 1 1 0 1 100 0 +$EndEntities +$Nodes +5 4 +1 1 0 2 +1 0 0 0 +2 1 0 0 +2 1 0 1 +3 1 1 0 +3 1 0 1 +4 0 1 0 +4 1 0 0 +6 2 0 0 +$EndNodes +$Elements +5 5 +1 1 1 1 +1 1 2 +2 1 1 1 +2 2 3 +3 1 1 1 +3 3 4 +4 1 1 1 +4 4 1 +6 2 3 1 +5 1 2 3 4 +$EndElements diff --git a/tests/grid/grids/grid_in_msh_01.2da.v4.msh b/tests/grid/grids/grid_in_msh_01.2da.v4.msh new file mode 100644 index 000000000000..c73826172012 --- /dev/null +++ b/tests/grid/grids/grid_in_msh_01.2da.v4.msh @@ -0,0 +1,904 @@ +$MeshFormat +4 0 8 +$EndMeshFormat +$Entities +0 7 1 0 +1 0 0 0 1 0 0 1 1 0 +3 0 0 0 0 3 0 1 1 0 +4 1 0 0 1 3 0 1 1 0 +14 3 0 0 4 4.440892098500626e-16 0 1 1 0 +15 4 4.440892098500626e-16 0 4 3 0 1 1 0 +16 3 0 0 3 3 0 1 1 0 +1000 0 3 0 3.975376681190276 5 0 1 1 0 +1000 0.1111111111111096 0 0 3.88888888888889 4.796440086335291 0 1 2 0 +$EndEntities +$Nodes +8 410 +1 1 0 10 +1 0 0 0 +2 1 0 0 +15 0.1111111111111096 0 0 +16 0.2222222222222192 0 0 +17 0.3333333333333288 0 0 +18 0.4444444444444383 0 0 +19 0.5555555555555478 0 0 +20 0.6666666666666574 0 0 +21 0.7777777777777686 0 0 +22 0.8888888888888843 0 0 +3 1 0 10 +3 0 3 0 +31 0 0.3 0 +32 0 0.6 0 +33 0 0.9 0 +34 0 1.2 0 +35 0 1.5 0 +36 0 1.8 0 +37 0 2.1 0 +38 0 2.4 0 +39 0 2.7 0 +4 1 0 10 +4 1 3 0 +41 1 0.3 0 +42 1 0.6 0 +43 1 0.9 0 +44 1 1.2 0 +45 1 1.5 0 +46 1 1.8 0 +47 1 2.1 0 +48 1 2.4 0 +49 1 2.7 0 +14 1 0 10 +13 4 4.440892098500626e-16 0 +14 3 0 0 +107 3.88888888888889 4.440892098500626e-16 0 +108 3.77777777777778 0 0 +109 3.666666666666671 0 0 +110 3.555555555555562 0 0 +111 3.444444444444452 0 0 +112 3.333333333333343 0 0 +113 3.222222222222231 0 0 +114 3.111111111111116 0 0 +15 1 0 10 +11 4 3 0 +115 4 2.700000000000001 0 +116 4 2.4 0 +117 4 2.100000000000001 0 +118 4 1.8 0 +119 4 1.5 0 +120 4 1.2 0 +121 4 0.9000000000000005 0 +122 4 0.6000000000000004 0 +123 4 0.3000000000000004 0 +16 1 0 10 +12 3 3 0 +125 3 2.7 0 +126 3 2.4 0 +127 3 2.1 0 +128 3 1.8 0 +129 3 1.5 0 +130 3 1.2 0 +131 3 0.9 0 +132 3 0.6 0 +133 3 0.3 0 +1000 1 0 38 +5 2 5 0 +6 2 4 0 +59 0.02462331880972446 3.312868930080462 0 +60 0.09788696740969294 3.618033988749895 0 +61 0.2179869516232642 3.907980999479093 0 +62 0.3819660112501051 4.175570504584947 0 +63 0.5857864376269049 4.414213562373095 0 +64 0.8244294954150537 4.618033988749895 0 +65 1.092019000520907 4.782013048376736 0 +66 1.381966011250105 4.902113032590307 0 +67 1.687131069919538 4.975376681190276 0 +69 1.012311659404862 3.156434465040231 0 +70 1.048943483704846 3.309016994374947 0 +71 1.108993475811632 3.453990499739547 0 +72 1.190983005625053 3.587785252292473 0 +73 1.292893218813453 3.707106781186547 0 +74 1.412214747707527 3.809016994374947 0 +75 1.546009500260453 3.891006524188368 0 +76 1.690983005625053 3.951056516295154 0 +77 1.843565534959769 3.987688340595138 0 +87 2.312868930080461 4.975376681190276 0 +88 2.618033988749894 4.902113032590307 0 +89 2.907980999479093 4.782013048376736 0 +90 3.175570504584946 4.618033988749895 0 +91 3.414213562373095 4.414213562373096 0 +92 3.618033988749895 4.175570504584947 0 +93 3.782013048376736 3.907980999479094 0 +94 3.902113032590307 3.618033988749895 0 +95 3.975376681190276 3.312868930080462 0 +97 2.156434465040231 3.987688340595138 0 +98 2.309016994374947 3.951056516295154 0 +99 2.453990499739547 3.891006524188368 0 +100 2.587785252292473 3.809016994374947 0 +101 2.707106781186547 3.707106781186547 0 +102 2.809016994374947 3.587785252292473 0 +103 2.891006524188368 3.453990499739547 0 +104 2.951056516295154 3.309016994374947 0 +105 2.987688340595138 3.156434465040231 0 +1000 2 0 312 +23 0.1111111111111096 3 0 +24 0.2222222222222192 3 0 +25 0.3333333333333288 3 0 +26 0.4444444444444383 3 0 +27 0.5555555555555478 3 0 +28 0.6666666666666574 3 0 +29 0.7777777777777686 3 0 +30 0.8888888888888843 3 0 +51 2 4.88888888888889 0 +52 2 4.77777777777778 0 +53 2 4.666666666666671 0 +54 2 4.555555555555562 0 +55 2 4.444444444444452 0 +56 2 4.333333333333343 0 +57 2 4.222222222222231 0 +58 2 4.111111111111116 0 +79 3.88888888888889 3 0 +80 3.77777777777778 3 0 +81 3.666666666666671 3 0 +82 3.555555555555562 3 0 +83 3.444444444444452 3 0 +84 3.333333333333343 3 0 +85 3.222222222222231 3 0 +86 3.111111111111116 3 0 +145 0.1111111111111096 0.3 0 +146 0.1111111111111096 0.6 0 +147 0.1111111111111096 0.9 0 +148 0.1111111111111096 1.2 0 +149 0.1111111111111096 1.5 0 +150 0.1111111111111096 1.8 0 +151 0.1111111111111096 2.1 0 +152 0.1111111111111096 2.4 0 +153 0.1111111111111096 2.7 0 +155 0.2222222222222192 0.3 0 +156 0.2222222222222192 0.6 0 +157 0.2222222222222192 0.9 0 +158 0.2222222222222192 1.2 0 +159 0.2222222222222192 1.5 0 +160 0.2222222222222192 1.8 0 +161 0.2222222222222192 2.1 0 +162 0.2222222222222192 2.4 0 +163 0.2222222222222192 2.7 0 +165 0.3333333333333288 0.3 0 +166 0.3333333333333288 0.6 0 +167 0.3333333333333288 0.9 0 +168 0.3333333333333288 1.2 0 +169 0.3333333333333288 1.5 0 +170 0.3333333333333288 1.8 0 +171 0.3333333333333288 2.1 0 +172 0.3333333333333288 2.4 0 +173 0.3333333333333288 2.7 0 +175 0.4444444444444383 0.3 0 +176 0.4444444444444383 0.6 0 +177 0.4444444444444383 0.9 0 +178 0.4444444444444383 1.2 0 +179 0.4444444444444383 1.5 0 +180 0.4444444444444383 1.8 0 +181 0.4444444444444383 2.1 0 +182 0.4444444444444383 2.4 0 +183 0.4444444444444383 2.7 0 +185 0.5555555555555478 0.3 0 +186 0.5555555555555478 0.6 0 +187 0.5555555555555478 0.9 0 +188 0.5555555555555478 1.2 0 +189 0.5555555555555478 1.5 0 +190 0.5555555555555478 1.8 0 +191 0.5555555555555478 2.1 0 +192 0.5555555555555478 2.4 0 +193 0.5555555555555478 2.7 0 +195 0.6666666666666574 0.3 0 +196 0.6666666666666574 0.6 0 +197 0.6666666666666574 0.9 0 +198 0.6666666666666574 1.2 0 +199 0.6666666666666574 1.5 0 +200 0.6666666666666574 1.8 0 +201 0.6666666666666574 2.1 0 +202 0.6666666666666574 2.4 0 +203 0.6666666666666574 2.7 0 +205 0.7777777777777686 0.3 0 +206 0.7777777777777686 0.6 0 +207 0.7777777777777686 0.9 0 +208 0.7777777777777686 1.2 0 +209 0.7777777777777686 1.5 0 +210 0.7777777777777686 1.8 0 +211 0.7777777777777686 2.1 0 +212 0.7777777777777686 2.4 0 +213 0.7777777777777686 2.7 0 +215 0.8888888888888843 0.3 0 +216 0.8888888888888843 0.6 0 +217 0.8888888888888843 0.9 0 +218 0.8888888888888843 1.2 0 +219 0.8888888888888843 1.5 0 +220 0.8888888888888843 1.8 0 +221 0.8888888888888843 2.1 0 +222 0.8888888888888843 2.4 0 +223 0.8888888888888843 2.7 0 +245 0.1343664677647383 3.29548732285377 0 +246 0.2035599136647086 3.583698767152679 0 +247 0.3169876765330815 3.857537610619144 0 +248 0.4718567884028759 4.110261032108006 0 +249 0.6643538577587424 4.335646142241258 0 +250 0.8897389678919942 4.528143211597124 0 +251 1.142462389380855 4.683012323466919 0 +252 1.416301232847321 4.796440086335291 0 +253 1.70451267714623 4.865633532235262 0 +255 0.2441096167197521 3.278105715627078 0 +256 0.3092328599197243 3.549363545555463 0 +257 0.4159884014428987 3.807094221759196 0 +258 0.5617475655556465 4.044951559631065 0 +259 0.74292127789058 4.257078722109419 0 +260 0.9550484403689348 4.438252434444354 0 +261 1.192905778240804 4.584011598557101 0 +262 1.450636454444537 4.690767140080276 0 +263 1.721894284372922 4.755890383280247 0 +265 0.3538527656747659 3.260724108400385 0 +266 0.4149058061747397 3.515028323958247 0 +267 0.5149891263527162 3.756650832899247 0 +268 0.6516383427084174 3.979642087154124 0 +269 0.8214886980224174 4.178511301977583 0 +270 1.020357912845876 4.348361657291583 0 +271 1.243349167100753 4.485010873647283 0 +272 1.484971676041753 4.585094193825261 0 +273 1.739275891599614 4.646147234325234 0 +275 0.4635959146297797 3.243342501173693 0 +276 0.5205787524297554 3.480693102361031 0 +277 0.6139898512625335 3.706207444039298 0 +278 0.741529119861188 3.914332614677184 0 +279 0.900056118154255 4.099943881845745 0 +280 1.085667385322816 4.258470880138812 0 +281 1.293792555960702 4.386010148737467 0 +282 1.519306897638969 4.479421247570245 0 +283 1.756657498826307 4.53640408537022 0 +285 0.5733390635847933 3.225960893947001 0 +286 0.6262516986847708 3.446357880763815 0 +287 0.7129905761723505 3.655764055179349 0 +288 0.8314198970139586 3.849023142200243 0 +289 0.9786235382860924 4.021376461713907 0 +290 1.150976857799757 4.168580102986041 0 +291 1.344235944820651 4.28700942382765 0 +292 1.553642119236185 4.37374830131523 0 +293 1.774039106052999 4.426660936415207 0 +295 0.6830822125398073 3.208579286720309 0 +296 0.7319246449397865 3.412022659166599 0 +297 0.811991301082168 3.6053206663194 0 +298 0.9213106741667292 3.783713669723303 0 +299 1.05719095841793 3.94280904158207 0 +300 1.216286330276697 4.07868932583327 0 +301 1.3946793336806 4.188008698917832 0 +302 1.587977340833401 4.268075355060214 0 +303 1.791420713279691 4.316917787460193 0 +305 0.7928253614948226 3.191197679493617 0 +306 0.8375975911948037 3.377687437569383 0 +307 0.9109920259919866 3.55487727745945 0 +308 1.011201451319501 3.718404197246362 0 +309 1.135758378549769 3.864241621450231 0 +310 1.281595802753638 3.988798548680499 0 +311 1.44512272254055 4.089007974008013 0 +312 1.622312562430617 4.162402408805196 0 +313 1.808802320506383 4.207174638505178 0 +315 0.9025685104498424 3.173816072266924 0 +316 0.9432705374498251 3.343352215972165 0 +317 1.009992750901809 3.504433888599499 0 +318 1.101092228472277 3.653094724769417 0 +319 1.214325798681611 3.785674201318389 0 +320 1.346905275230583 3.898907771527723 0 +321 1.495566111400501 3.99000724909819 0 +322 1.656647784027835 4.056729462550175 0 +323 1.826183927733076 4.097431489550157 0 +345 2.29548732285377 4.865633532235261 0 +346 2.583698767152679 4.796440086335291 0 +347 2.857537610619144 4.683012323466919 0 +348 3.110261032108006 4.528143211597124 0 +349 3.335646142241257 4.335646142241258 0 +350 3.528143211597124 4.110261032108006 0 +351 3.683012323466918 3.857537610619145 0 +352 3.796440086335291 3.583698767152679 0 +353 3.865633532235262 3.29548732285377 0 +355 2.278105715627078 4.755890383280247 0 +356 2.549363545555463 4.690767140080276 0 +357 2.807094221759195 4.584011598557101 0 +358 3.044951559631065 4.438252434444353 0 +359 3.257078722109419 4.257078722109419 0 +360 3.438252434444353 4.044951559631064 0 +361 3.584011598557101 3.807094221759195 0 +362 3.690767140080276 3.549363545555463 0 +363 3.755890383280247 3.278105715627078 0 +365 2.260724108400385 4.646147234325234 0 +366 2.515028323958247 4.585094193825261 0 +367 2.756650832899247 4.485010873647284 0 +368 2.979642087154125 4.348361657291583 0 +369 3.178511301977582 4.178511301977583 0 +370 3.348361657291583 3.979642087154125 0 +371 3.485010873647284 3.756650832899247 0 +372 3.585094193825261 3.515028323958247 0 +373 3.646147234325234 3.260724108400386 0 +375 2.243342501173693 4.53640408537022 0 +376 2.480693102361031 4.479421247570245 0 +377 2.706207444039298 4.386010148737467 0 +378 2.914332614677184 4.258470880138812 0 +379 3.099943881845745 4.099943881845745 0 +380 3.258470880138812 3.914332614677184 0 +381 3.386010148737467 3.706207444039298 0 +382 3.479421247570245 3.480693102361031 0 +383 3.53640408537022 3.243342501173693 0 +385 2.225960893947001 4.426660936415207 0 +386 2.446357880763815 4.373748301315229 0 +387 2.655764055179349 4.287009423827649 0 +388 2.849023142200243 4.168580102986041 0 +389 3.021376461713907 4.021376461713907 0 +390 3.168580102986041 3.849023142200243 0 +391 3.287009423827649 3.655764055179349 0 +392 3.373748301315229 3.446357880763815 0 +393 3.426660936415206 3.225960893947001 0 +395 2.208579286720309 4.316917787460193 0 +396 2.412022659166599 4.268075355060214 0 +397 2.6053206663194 4.188008698917832 0 +398 2.783713669723303 4.078689325833271 0 +399 2.94280904158207 3.94280904158207 0 +400 3.078689325833271 3.783713669723303 0 +401 3.188008698917832 3.6053206663194 0 +402 3.268075355060214 3.412022659166599 0 +403 3.316917787460193 3.20857928672031 0 +405 2.191197679493617 4.207174638505178 0 +406 2.377687437569383 4.162402408805196 0 +407 2.55487727745945 4.089007974008013 0 +408 2.718404197246361 3.988798548680498 0 +409 2.864241621450231 3.864241621450231 0 +410 2.988798548680498 3.718404197246361 0 +411 3.089007974008013 3.55487727745945 0 +412 3.162402408805196 3.377687437569383 0 +413 3.207174638505177 3.191197679493617 0 +415 2.173816072266924 4.097431489550158 0 +416 2.343352215972165 4.056729462550175 0 +417 2.504433888599499 3.990007249098191 0 +418 2.653094724769418 3.898907771527723 0 +419 2.78567420131839 3.78567420131839 0 +420 2.898907771527723 3.653094724769418 0 +421 2.990007249098191 3.504433888599499 0 +422 3.056729462550175 3.343352215972165 0 +423 3.097431489550158 3.173816072266924 0 +445 3.88888888888889 2.700000000000001 0 +446 3.88888888888889 2.4 0 +447 3.88888888888889 2.100000000000001 0 +448 3.88888888888889 1.8 0 +449 3.88888888888889 1.5 0 +450 3.88888888888889 1.2 0 +451 3.88888888888889 0.9000000000000005 0 +452 3.88888888888889 0.6000000000000004 0 +453 3.88888888888889 0.3000000000000004 0 +455 3.77777777777778 2.7 0 +456 3.77777777777778 2.4 0 +457 3.77777777777778 2.1 0 +458 3.77777777777778 1.8 0 +459 3.77777777777778 1.5 0 +460 3.77777777777778 1.2 0 +461 3.77777777777778 0.9 0 +462 3.77777777777778 0.6 0 +463 3.77777777777778 0.3 0 +465 3.666666666666671 2.7 0 +466 3.666666666666671 2.4 0 +467 3.666666666666671 2.1 0 +468 3.666666666666671 1.8 0 +469 3.666666666666671 1.5 0 +470 3.666666666666671 1.2 0 +471 3.666666666666671 0.9 0 +472 3.666666666666671 0.6 0 +473 3.666666666666671 0.3 0 +475 3.555555555555562 2.7 0 +476 3.555555555555562 2.4 0 +477 3.555555555555562 2.1 0 +478 3.555555555555562 1.8 0 +479 3.555555555555562 1.5 0 +480 3.555555555555562 1.2 0 +481 3.555555555555562 0.9 0 +482 3.555555555555562 0.6 0 +483 3.555555555555562 0.3 0 +485 3.444444444444452 2.7 0 +486 3.444444444444452 2.4 0 +487 3.444444444444452 2.1 0 +488 3.444444444444452 1.8 0 +489 3.444444444444452 1.5 0 +490 3.444444444444452 1.2 0 +491 3.444444444444452 0.9 0 +492 3.444444444444452 0.6 0 +493 3.444444444444452 0.3 0 +495 3.333333333333343 2.7 0 +496 3.333333333333343 2.4 0 +497 3.333333333333343 2.1 0 +498 3.333333333333343 1.8 0 +499 3.333333333333343 1.5 0 +500 3.333333333333343 1.2 0 +501 3.333333333333343 0.9 0 +502 3.333333333333343 0.6 0 +503 3.333333333333343 0.3 0 +505 3.222222222222231 2.7 0 +506 3.222222222222231 2.4 0 +507 3.222222222222231 2.1 0 +508 3.222222222222231 1.8 0 +509 3.222222222222231 1.5 0 +510 3.222222222222231 1.2 0 +511 3.222222222222231 0.9 0 +512 3.222222222222231 0.6 0 +513 3.222222222222231 0.3 0 +515 3.111111111111116 2.7 0 +516 3.111111111111116 2.4 0 +517 3.111111111111116 2.1 0 +518 3.111111111111116 1.8 0 +519 3.111111111111116 1.5 0 +520 3.111111111111116 1.2 0 +521 3.111111111111116 0.9 0 +522 3.111111111111116 0.6 0 +523 3.111111111111116 0.3 0 +$EndNodes +$Elements +8 458 +1 1 1 9 +361 1 15 +362 15 16 +363 16 17 +364 17 18 +365 18 19 +366 19 20 +367 20 21 +368 21 22 +369 22 2 +3 1 1 10 +449 1 31 +450 31 32 +451 32 33 +452 33 34 +453 34 35 +454 35 36 +455 36 37 +456 37 38 +457 38 39 +458 39 3 +4 1 1 10 +370 2 41 +371 41 42 +372 42 43 +373 43 44 +374 44 45 +375 45 46 +376 46 47 +377 47 48 +378 48 49 +379 49 4 +14 1 1 9 +410 13 107 +411 107 108 +412 108 109 +413 109 110 +414 110 111 +415 111 112 +416 112 113 +417 113 114 +418 114 14 +15 1 1 10 +419 11 115 +420 115 116 +421 116 117 +422 117 118 +423 118 119 +424 119 120 +425 120 121 +426 121 122 +427 122 123 +428 123 13 +16 1 1 10 +400 12 125 +401 125 126 +402 126 127 +403 127 128 +404 128 129 +405 129 130 +406 130 131 +407 131 132 +408 132 133 +409 133 14 +1000 1 1 40 +380 4 69 +381 69 70 +382 70 71 +383 71 72 +384 72 73 +385 73 74 +386 74 75 +387 75 76 +388 76 77 +389 77 6 +390 6 97 +391 97 98 +392 98 99 +393 99 100 +394 100 101 +395 101 102 +396 102 103 +397 103 104 +398 104 105 +399 105 12 +429 5 87 +430 87 88 +431 88 89 +432 89 90 +433 90 91 +434 91 92 +435 92 93 +436 93 94 +437 94 95 +438 95 11 +439 3 59 +440 59 60 +441 60 61 +442 61 62 +443 62 63 +444 63 64 +445 64 65 +446 65 66 +447 66 67 +448 67 5 +1000 2 3 360 +1 223 49 4 30 +2 222 48 49 223 +3 221 47 48 222 +4 220 46 47 221 +5 219 45 46 220 +6 218 44 45 219 +7 217 43 44 218 +8 216 42 43 217 +9 215 41 42 216 +10 22 2 41 215 +11 213 223 30 29 +12 212 222 223 213 +13 211 221 222 212 +14 210 220 221 211 +15 209 219 220 210 +16 208 218 219 209 +17 207 217 218 208 +18 206 216 217 207 +19 205 215 216 206 +20 21 22 215 205 +21 203 213 29 28 +22 202 212 213 203 +23 201 211 212 202 +24 200 210 211 201 +25 199 209 210 200 +26 198 208 209 199 +27 197 207 208 198 +28 196 206 207 197 +29 195 205 206 196 +30 20 21 205 195 +31 193 203 28 27 +32 192 202 203 193 +33 191 201 202 192 +34 190 200 201 191 +35 189 199 200 190 +36 188 198 199 189 +37 187 197 198 188 +38 186 196 197 187 +39 185 195 196 186 +40 19 20 195 185 +41 183 193 27 26 +42 182 192 193 183 +43 181 191 192 182 +44 180 190 191 181 +45 179 189 190 180 +46 178 188 189 179 +47 177 187 188 178 +48 176 186 187 177 +49 175 185 186 176 +50 18 19 185 175 +51 173 183 26 25 +52 172 182 183 173 +53 171 181 182 172 +54 170 180 181 171 +55 169 179 180 170 +56 168 178 179 169 +57 167 177 178 168 +58 166 176 177 167 +59 165 175 176 166 +60 17 18 175 165 +61 163 173 25 24 +62 162 172 173 163 +63 161 171 172 162 +64 160 170 171 161 +65 159 169 170 160 +66 158 168 169 159 +67 157 167 168 158 +68 156 166 167 157 +69 155 165 166 156 +70 16 17 165 155 +71 153 163 24 23 +72 152 162 163 153 +73 151 161 162 152 +74 150 160 161 151 +75 149 159 160 150 +76 148 158 159 149 +77 147 157 158 148 +78 146 156 157 147 +79 145 155 156 146 +80 15 16 155 145 +81 39 153 23 3 +82 38 152 153 39 +83 37 151 152 38 +84 36 150 151 37 +85 35 149 150 36 +86 34 148 149 35 +87 33 147 148 34 +88 32 146 147 33 +89 31 145 146 32 +90 1 15 145 31 +91 323 77 6 58 +92 322 76 77 323 +93 321 75 76 322 +94 320 74 75 321 +95 319 73 74 320 +96 318 72 73 319 +97 317 71 72 318 +98 316 70 71 317 +99 315 69 70 316 +100 30 4 69 315 +101 313 323 58 57 +102 312 322 323 313 +103 311 321 322 312 +104 310 320 321 311 +105 309 319 320 310 +106 308 318 319 309 +107 307 317 318 308 +108 306 316 317 307 +109 305 315 316 306 +110 29 30 315 305 +111 303 313 57 56 +112 302 312 313 303 +113 301 311 312 302 +114 300 310 311 301 +115 299 309 310 300 +116 298 308 309 299 +117 297 307 308 298 +118 296 306 307 297 +119 295 305 306 296 +120 28 29 305 295 +121 293 303 56 55 +122 292 302 303 293 +123 291 301 302 292 +124 290 300 301 291 +125 289 299 300 290 +126 288 298 299 289 +127 287 297 298 288 +128 286 296 297 287 +129 285 295 296 286 +130 27 28 295 285 +131 283 293 55 54 +132 282 292 293 283 +133 281 291 292 282 +134 280 290 291 281 +135 279 289 290 280 +136 278 288 289 279 +137 277 287 288 278 +138 276 286 287 277 +139 275 285 286 276 +140 26 27 285 275 +141 273 283 54 53 +142 272 282 283 273 +143 271 281 282 272 +144 270 280 281 271 +145 269 279 280 270 +146 268 278 279 269 +147 267 277 278 268 +148 266 276 277 267 +149 265 275 276 266 +150 25 26 275 265 +151 263 273 53 52 +152 262 272 273 263 +153 261 271 272 262 +154 260 270 271 261 +155 259 269 270 260 +156 258 268 269 259 +157 257 267 268 258 +158 256 266 267 257 +159 255 265 266 256 +160 24 25 265 255 +161 253 263 52 51 +162 252 262 263 253 +163 251 261 262 252 +164 250 260 261 251 +165 249 259 260 250 +166 248 258 259 249 +167 247 257 258 248 +168 246 256 257 247 +169 245 255 256 246 +170 23 24 255 245 +171 67 253 51 5 +172 66 252 253 67 +173 65 251 252 66 +174 64 250 251 65 +175 63 249 250 64 +176 62 248 249 63 +177 61 247 248 62 +178 60 246 247 61 +179 59 245 246 60 +180 3 23 245 59 +181 423 105 12 86 +182 422 104 105 423 +183 421 103 104 422 +184 420 102 103 421 +185 419 101 102 420 +186 418 100 101 419 +187 417 99 100 418 +188 416 98 99 417 +189 415 97 98 416 +190 58 6 97 415 +191 413 423 86 85 +192 412 422 423 413 +193 411 421 422 412 +194 410 420 421 411 +195 409 419 420 410 +196 408 418 419 409 +197 407 417 418 408 +198 406 416 417 407 +199 405 415 416 406 +200 57 58 415 405 +201 403 413 85 84 +202 402 412 413 403 +203 401 411 412 402 +204 400 410 411 401 +205 399 409 410 400 +206 398 408 409 399 +207 397 407 408 398 +208 396 406 407 397 +209 395 405 406 396 +210 56 57 405 395 +211 393 403 84 83 +212 392 402 403 393 +213 391 401 402 392 +214 390 400 401 391 +215 389 399 400 390 +216 388 398 399 389 +217 387 397 398 388 +218 386 396 397 387 +219 385 395 396 386 +220 55 56 395 385 +221 383 393 83 82 +222 382 392 393 383 +223 381 391 392 382 +224 380 390 391 381 +225 379 389 390 380 +226 378 388 389 379 +227 377 387 388 378 +228 376 386 387 377 +229 375 385 386 376 +230 54 55 385 375 +231 373 383 82 81 +232 372 382 383 373 +233 371 381 382 372 +234 370 380 381 371 +235 369 379 380 370 +236 368 378 379 369 +237 367 377 378 368 +238 366 376 377 367 +239 365 375 376 366 +240 53 54 375 365 +241 363 373 81 80 +242 362 372 373 363 +243 361 371 372 362 +244 360 370 371 361 +245 359 369 370 360 +246 358 368 369 359 +247 357 367 368 358 +248 356 366 367 357 +249 355 365 366 356 +250 52 53 365 355 +251 353 363 80 79 +252 352 362 363 353 +253 351 361 362 352 +254 350 360 361 351 +255 349 359 360 350 +256 348 358 359 349 +257 347 357 358 348 +258 346 356 357 347 +259 345 355 356 346 +260 51 52 355 345 +261 95 353 79 11 +262 94 352 353 95 +263 93 351 352 94 +264 92 350 351 93 +265 91 349 350 92 +266 90 348 349 91 +267 89 347 348 90 +268 88 346 347 89 +269 87 345 346 88 +270 5 51 345 87 +271 523 133 14 114 +272 522 132 133 523 +273 521 131 132 522 +274 520 130 131 521 +275 519 129 130 520 +276 518 128 129 519 +277 517 127 128 518 +278 516 126 127 517 +279 515 125 126 516 +280 86 12 125 515 +281 513 523 114 113 +282 512 522 523 513 +283 511 521 522 512 +284 510 520 521 511 +285 509 519 520 510 +286 508 518 519 509 +287 507 517 518 508 +288 506 516 517 507 +289 505 515 516 506 +290 85 86 515 505 +291 503 513 113 112 +292 502 512 513 503 +293 501 511 512 502 +294 500 510 511 501 +295 499 509 510 500 +296 498 508 509 499 +297 497 507 508 498 +298 496 506 507 497 +299 495 505 506 496 +300 84 85 505 495 +301 493 503 112 111 +302 492 502 503 493 +303 491 501 502 492 +304 490 500 501 491 +305 489 499 500 490 +306 488 498 499 489 +307 487 497 498 488 +308 486 496 497 487 +309 485 495 496 486 +310 83 84 495 485 +311 483 493 111 110 +312 482 492 493 483 +313 481 491 492 482 +314 480 490 491 481 +315 479 489 490 480 +316 478 488 489 479 +317 477 487 488 478 +318 476 486 487 477 +319 475 485 486 476 +320 82 83 485 475 +321 473 483 110 109 +322 472 482 483 473 +323 471 481 482 472 +324 470 480 481 471 +325 469 479 480 470 +326 468 478 479 469 +327 467 477 478 468 +328 466 476 477 467 +329 465 475 476 466 +330 81 82 475 465 +331 463 473 109 108 +332 462 472 473 463 +333 461 471 472 462 +334 460 470 471 461 +335 459 469 470 460 +336 458 468 469 459 +337 457 467 468 458 +338 456 466 467 457 +339 455 465 466 456 +340 80 81 465 455 +341 453 463 108 107 +342 452 462 463 453 +343 451 461 462 452 +344 450 460 461 451 +345 449 459 460 450 +346 448 458 459 449 +347 447 457 458 448 +348 446 456 457 447 +349 445 455 456 446 +350 79 80 455 445 +351 123 453 107 13 +352 122 452 453 123 +353 121 451 452 122 +354 120 450 451 121 +355 119 449 450 120 +356 118 448 449 119 +357 117 447 448 118 +358 116 446 447 117 +359 115 445 446 116 +360 11 79 445 115 +$EndElements diff --git a/tests/grid/grids/grid_in_msh_01.3d.v4.msh b/tests/grid/grids/grid_in_msh_01.3d.v4.msh new file mode 100644 index 000000000000..d620ebb45cf6 --- /dev/null +++ b/tests/grid/grids/grid_in_msh_01.3d.v4.msh @@ -0,0 +1,48 @@ +$MeshFormat +4 0 8 +$EndMeshFormat +$Entities +0 0 6 1 +6 0 0 0 1 0 1 1 1 0 +15 0 0 1 1 1 1 1 1 0 +19 0 0 0 1 1 0 1 1 0 +23 0 1 0 1 1 1 1 1 0 +27 1 0 0 1 1 1 1 1 0 +28 0 0 0 0 1 1 1 1 0 +1000 0 0 0 1 1 1 1 100 0 +$EndEntities +$Nodes +7 8 +6 2 0 4 +1 0 0 0 +2 1 0 0 +5 1 0 1 +14 0 0 1 +15 2 0 2 +6 1 1 1 +10 0 1 1 +19 2 0 2 +3 1 1 0 +4 0 1 0 +23 2 0 0 +27 2 0 0 +28 2 0 0 +1000 3 0 0 +$EndNodes +$Elements +7 7 +6 2 3 1 +1 1 2 5 14 +15 2 3 1 +5 14 5 6 10 +19 2 3 1 +3 1 2 3 4 +23 2 3 1 +2 4 3 6 10 +27 2 3 1 +4 2 3 6 5 +28 2 3 1 +6 1 4 10 14 +1000 3 5 1 +7 1 2 5 14 4 3 6 10 +$EndElements diff --git a/tests/grid/grids/grid_in_msh_01.3d_neg.v4.msh b/tests/grid/grids/grid_in_msh_01.3d_neg.v4.msh new file mode 100644 index 000000000000..c923afc0e573 --- /dev/null +++ b/tests/grid/grids/grid_in_msh_01.3d_neg.v4.msh @@ -0,0 +1,48 @@ +$MeshFormat +4 0 8 +$EndMeshFormat +$Entities +0 0 6 1 +6 0 0 0 1 1 0 1 1 0 +15 1 0 0 1 1 1 1 1 0 +19 0 1 0 1 1 1 1 1 0 +23 0 0 0 0 1 1 1 1 0 +27 0 0 0 1 0 1 1 1 0 +28 0 0 1 1 1 1 1 1 0 +1000 0 0 0 1 1 1 1 100 0 +$EndEntities +$Nodes +7 8 +6 2 0 4 +1 0 0 0 +2 1 0 0 +3 1 1 0 +4 0 1 0 +15 2 0 2 +5 1 0 1 +6 1 1 1 +19 2 0 1 +10 0 1 1 +23 2 0 1 +14 0 0 1 +27 2 0 0 +28 2 0 0 +1000 3 0 0 +$EndNodes +$Elements +7 7 +6 2 3 1 +1 1 2 3 4 +15 2 3 1 +5 2 3 6 5 +19 2 3 1 +3 3 4 10 6 +23 2 3 1 +2 4 1 14 10 +27 2 3 1 +4 1 2 5 14 +28 2 3 1 +6 14 5 6 10 +1000 3 5 1 +7 1 2 3 4 14 5 6 10 +$EndElements diff --git a/tests/grid/grids/grid_in_msh_01.3da.v4.msh b/tests/grid/grids/grid_in_msh_01.3da.v4.msh new file mode 100644 index 000000000000..05f65167305a --- /dev/null +++ b/tests/grid/grids/grid_in_msh_01.3da.v4.msh @@ -0,0 +1,1218 @@ +$MeshFormat +4 0 8 +$EndMeshFormat +$Entities +0 0 27 1 +18 0 -1 0 1 0 1 1 1 0 +22 0.2 -0.8000000000000002 0 1.692820323027551 0 1 1 1 0 +30 0 -1 0 1.866025403784439 0 1 1 1 0 +44 0.5999999999999999 -0.8000000000000003 0 1.8 0.4 1 1 1 0 +48 1.4 -0.8660254037844388 0 1.994521895368274 0.4999999999999998 1 1 1 0 +52 0.4999999999999999 -1 0 2 0.4999999999999997 1 1 1 0 +62 0.9999999999999999 -1 1 2 -5.551115123125783e-17 2 1 1 0 +66 1 -0.8 1 1.8 0.6928203230275509 2 1 1 0 +74 0.9999999999999999 -1 1 2 0.8660254037844386 2 1 1 0 +88 0.6000000000000002 -0.4000000000000001 1 1.8 0.8 2 1 1 0 +92 0.5000000000000003 0.3999999999999999 1 1.866025403784439 0.9945218953682734 2 1 1 0 +96 0.5000000000000003 -0.5 1 2 1 2 1 1 0 +106 1 -2.220446049250313e-16 2 2 1 3 1 1 0 +110 0.3071796769724491 -5.551115123125783e-17 2 1.8 0.8 3 1 1 0 +118 0.1339745962155614 -2.220446049250313e-16 2 2 1 3 1 1 0 +132 0.2000000000000001 -0.3999999999999996 2 1.4 0.8 3 1 1 0 +136 0.00547810463172671 -0.4999999999999996 2 0.6000000000000002 0.8660254037844388 3 1 1 0 +140 0 -0.4999999999999996 2 1.5 1 3 1 1 0 +150 0 5.551115123125783e-17 3 1 1 4 1 1 0 +154 0.2 -0.6928203230275509 3 1 0.8 4 1 1 0 +162 0 -0.8660254037844386 3 1 1 4 1 1 0 +163 0 -0.8660254037844386 4 0.5999999999999995 2.775557561562891e-16 4 1 1 0 +176 0.1999999999999997 -0.7999999999999999 3 1.4 0.4000000000000005 4 1 1 0 +180 0.1339745962155612 -0.9945218953682733 3 1.5 -0.3999999999999997 4 1 1 0 +184 -2.220446049250313e-16 -1 3 1.5 0.5 4 1 1 0 +185 0.5 -0.9945218953682735 4 1.5 -0.6928203230275509 4 1 1 0 +1000 0 -0.9945218953682734 0 1.5 0 0 1 1 0 +1000 -1.110223024625157e-16 -1 0 2 1 3.2 1 2 0 +$EndEntities +$Nodes +28 462 +18 2 0 12 +1 0 0 0 +2 0.2 0 0 +11 0.9999999999999999 -1 1 +12 1 -0.8 1 +33 0.04894348370484647 -0.3090169943749474 0.2 +34 0.1909830056250525 -0.5877852522924731 0.4 +35 0.4122147477075269 -0.8090169943749475 0.6 +36 0.6909830056250525 -0.9510565162951535 0.8 +38 0.2391547869638772 -0.2472135954999579 0.2 +39 0.352786404500042 -0.4702282018339785 0.4 +40 0.5297717981660215 -0.647213595499958 0.6 +41 0.7527864045000421 -0.7608452130361228 0.8 +22 2 0 30 +4 0.5999999999999999 -0.6928203230275509 0 +17 1.692820323027551 -0.4000000000000002 1 +53 0.8336706473457924 -0.7825180805870445 0.2 +54 1.083622770614123 -0.7956175162946187 0.4 +55 1.32538931446064 -0.7308363661140809 0.6 +56 1.535304485087087 -0.5945158603819155 0.8 +496 0.2174819194129554 -0.1663293526542075 0 +497 0.2691636338859192 -0.3253893144606401 0 +498 0.352786404500042 -0.4702282018339785 0 +499 0.4646955149129134 -0.5945158603819153 0 +511 1.166329352654207 -0.7825180805870446 1 +512 1.32538931446064 -0.7308363661140808 1 +513 1.470228201833979 -0.647213595499958 1 +514 1.594515860381915 -0.5353044850870866 1 +730 0.307179676972449 -0.4 0.2 +731 0.4646955149129133 -0.5945158603819155 0.4 +732 0.6746106855393597 -0.7308363661140809 0.6 +733 0.9163772293858772 -0.7956175162946187 0.8 +735 0.4054841396180846 -0.5353044850870865 0.2 +736 0.6 -0.6928203230275509 0.4 +737 0.8336706473457924 -0.7825180805870445 0.6 +738 1.083622770614123 -0.7956175162946186 0.8 +740 0.5297717981660215 -0.6472135954999579 0.2 +741 0.752786404500042 -0.760845213036123 0.4 +742 1 -0.8000000000000002 0.6 +743 1.247213595499958 -0.760845213036123 0.8 +745 0.6746106855393599 -0.7308363661140806 0.2 +746 0.9163772293858772 -0.7956175162946186 0.4 +747 1.166329352654207 -0.7825180805870445 0.6 +748 1.4 -0.6928203230275509 0.8 +30 2 0 30 +3 0.4999999999999999 -0.8660254037844386 0 +21 1.866025403784439 -0.5000000000000001 1 +67 0.7920883091822405 -0.9781476007338056 0.2 +68 1.104528463267653 -0.9945218953682734 0.4 +69 1.4067366430758 -0.913545457642601 0.6 +70 1.669130606358858 -0.7431448254773944 0.8 +491 0.02185239926619431 -0.2079116908177593 0 +492 0.08645454235739913 -0.4067366430758002 0 +493 0.1909830056250525 -0.5877852522924731 0 +494 0.3308693936411418 -0.7431448254773941 0 +515 1.743144825477394 -0.6691306063588582 1 +516 1.587785252292473 -0.8090169943749475 1 +517 1.4067366430758 -0.9135454576426009 1 +518 1.207911690817759 -0.9781476007338057 1 +770 0.1339745962155613 -0.4999999999999999 0.2 +771 0.3308693936411418 -0.7431448254773944 0.4 +772 0.5932633569241996 -0.913545457642601 0.6 +773 0.8954715367323465 -0.9945218953682734 0.8 +775 0.2568551745226058 -0.6691306063588581 0.2 +776 0.5 -0.8660254037844386 0.4 +777 0.7920883091822406 -0.9781476007338057 0.6 +778 1.104528463267653 -0.9945218953682733 0.8 +780 0.4122147477075269 -0.8090169943749473 0.2 +781 0.6909830056250525 -0.9510565162951536 0.4 +782 1 -1 0.6 +783 1.309016994374947 -0.9510565162951536 0.8 +785 0.5932633569241998 -0.9135454576426008 0.2 +786 0.8954715367323465 -0.9945218953682733 0.4 +787 1.207911690817759 -0.9781476007338057 0.6 +788 1.5 -0.8660254037844386 0.8 +44 2 0 30 +10 1.4 -0.6928203230275511 0 +77 1.692820323027551 0.3999999999999999 1 +113 1.594515860381915 -0.5353044850870868 0.2 +114 1.730836366114081 -0.3253893144606404 0.4 +115 1.795617516294619 -0.08362277061412297 0.6 +116 1.782518080587045 0.1663293526542073 0.8 +506 0.7527864045000419 -0.760845213036123 0 +507 0.9163772293858771 -0.7956175162946186 0 +508 1.083622770614123 -0.7956175162946187 0 +509 1.247213595499958 -0.760845213036123 0 +539 1.760845213036123 -0.2472135954999582 1 +540 1.795617516294619 -0.08362277061412299 1 +541 1.795617516294619 0.08362277061412254 1 +542 1.760845213036123 0.2472135954999576 1 +820 0.9999999999999999 -0.8000000000000002 0.2 +821 1.247213595499958 -0.7608452130361231 0.4 +822 1.470228201833979 -0.6472135954999582 0.6 +823 1.647213595499958 -0.4702282018339787 0.8 +825 1.166329352654207 -0.7825180805870445 0.2 +826 1.4 -0.692820323027551 0.4 +827 1.594515860381915 -0.5353044850870867 0.6 +828 1.730836366114081 -0.3253893144606403 0.8 +830 1.32538931446064 -0.7308363661140808 0.2 +831 1.535304485087087 -0.5945158603819156 0.4 +832 1.692820323027551 -0.4000000000000002 0.6 +833 1.782518080587045 -0.1663293526542077 0.8 +835 1.470228201833978 -0.647213595499958 0.2 +836 1.647213595499958 -0.4702282018339787 0.4 +837 1.760845213036123 -0.2472135954999582 0.6 +838 1.8 -2.983453328136987e-16 0.8 +48 2 0 6 +9 1.5 -0.8660254037844388 0 +81 1.866025403784439 0.4999999999999997 1 +127 1.743144825477394 -0.6691306063588585 0.2 +128 1.913545457642601 -0.4067366430758005 0.4 +129 1.994521895368274 -0.1045284632676537 0.6 +130 1.978147600733806 0.207911690817759 0.8 +52 2 0 24 +501 0.6909830056250523 -0.9510565162951535 0 +502 0.8954715367323464 -0.9945218953682733 0 +503 1.104528463267653 -0.9945218953682734 0 +504 1.309016994374947 -0.9510565162951535 0 +543 1.951056516295154 0.3090169943749472 1 +544 1.994521895368274 0.1045284632676532 1 +545 1.994521895368273 -0.1045284632676537 1 +546 1.951056516295154 -0.3090169943749477 1 +860 0.9999999999999998 -1 0.2 +861 1.309016994374947 -0.9510565162951538 0.4 +862 1.587785252292473 -0.8090169943749477 0.6 +863 1.809016994374947 -0.5877852522924734 0.8 +865 1.207911690817759 -0.9781476007338056 0.2 +866 1.5 -0.8660254037844387 0.4 +867 1.743144825477394 -0.6691306063588583 0.6 +868 1.913545457642601 -0.4067366430758004 0.8 +870 1.4067366430758 -0.913545457642601 0.2 +871 1.669130606358858 -0.7431448254773945 0.4 +872 1.866025403784439 -0.5000000000000002 0.6 +873 1.978147600733806 -0.2079116908177596 0.8 +875 1.587785252292473 -0.8090169943749475 0.2 +876 1.809016994374947 -0.5877852522924732 0.4 +877 1.951056516295153 -0.3090169943749476 0.6 +878 2 -2.312603233911581e-16 0.8 +62 2 0 10 +131 2 -1.722526201536345e-16 2 +132 1.8 -4.898425415289509e-17 2 +153 1.309016994374947 -0.9510565162951535 1.2 +154 1.587785252292473 -0.8090169943749476 1.4 +155 1.809016994374947 -0.5877852522924732 1.6 +156 1.951056516295154 -0.3090169943749476 1.8 +158 1.247213595499958 -0.7608452130361228 1.2 +159 1.470228201833979 -0.647213595499958 1.4 +160 1.647213595499958 -0.4702282018339785 1.6 +161 1.760845213036123 -0.247213595499958 1.8 +66 2 0 25 +137 1.4 0.6928203230275509 2 +173 1.782518080587045 -0.1663293526542076 1.2 +174 1.795617516294619 0.0836227706141226 1.4 +175 1.730836366114081 0.3253893144606401 1.6 +176 1.594515860381916 0.5353044850870865 1.8 +557 1.782518080587045 0.1663293526542073 2 +558 1.730836366114081 0.3253893144606401 2 +559 1.647213595499958 0.4702282018339785 2 +560 1.535304485087087 0.5945158603819154 2 +920 1.4 -0.692820323027551 1.2 +921 1.594515860381915 -0.5353044850870867 1.4 +922 1.730836366114081 -0.3253893144606403 1.6 +923 1.795617516294619 -0.08362277061412296 1.8 +925 1.535304485087087 -0.5945158603819154 1.2 +926 1.692820323027551 -0.4000000000000001 1.4 +927 1.782518080587045 -0.1663293526542075 1.6 +928 1.795617516294619 0.08362277061412268 1.8 +930 1.647213595499958 -0.4702282018339786 1.2 +931 1.760845213036123 -0.247213595499958 1.4 +932 1.8 -7.53791560420547e-17 1.6 +933 1.760845213036123 0.2472135954999579 1.8 +935 1.730836366114081 -0.3253893144606402 1.2 +936 1.795617516294619 -0.08362277061412283 1.4 +937 1.782518080587045 0.1663293526542075 1.6 +938 1.692820323027551 0.4 1.8 +74 2 0 25 +141 1.5 0.8660254037844386 2 +187 1.978147600733806 -0.2079116908177595 1.2 +188 1.994521895368274 0.1045284632676533 1.4 +189 1.913545457642601 0.4067366430758001 1.6 +190 1.743144825477394 0.6691306063588581 1.8 +561 1.669130606358858 0.743144825477394 2 +562 1.809016994374947 0.5877852522924731 2 +563 1.913545457642601 0.4067366430758001 2 +564 1.978147600733806 0.2079116908177591 2 +960 1.913545457642601 -0.4067366430758003 1.2 +961 1.994521895368273 -0.1045284632676536 1.4 +962 1.978147600733806 0.2079116908177592 1.6 +963 1.866025403784439 0.4999999999999998 1.8 +965 1.809016994374947 -0.5877852522924731 1.2 +966 1.951056516295154 -0.3090169943749475 1.4 +967 2 1.265806036376826e-17 1.6 +968 1.951056516295154 0.3090169943749474 1.8 +970 1.669130606358858 -0.7431448254773942 1.2 +971 1.866025403784439 -0.5 1.4 +972 1.978147600733806 -0.2079116908177594 1.6 +973 1.994521895368273 0.1045284632676534 1.8 +975 1.5 -0.8660254037844387 1.2 +976 1.743144825477394 -0.6691306063588583 1.4 +977 1.913545457642601 -0.4067366430758004 1.6 +978 1.994521895368273 -0.1045284632676537 1.8 +88 2 0 25 +197 0.6000000000000002 0.6928203230275511 2 +233 1.535304485087087 0.5945158603819153 1.2 +234 1.325389314460641 0.7308363661140808 1.4 +235 1.083622770614123 0.7956175162946187 1.6 +236 0.8336706473457928 0.7825180805870446 1.8 +585 1.247213595499958 0.760845213036123 2 +586 1.083622770614123 0.7956175162946186 2 +587 0.9163772293858775 0.7956175162946186 2 +588 0.7527864045000424 0.760845213036123 2 +1010 1.8 -2.291054715733432e-16 1.2 +1011 1.760845213036123 0.2472135954999578 1.4 +1012 1.647213595499958 0.4702282018339784 1.6 +1013 1.470228201833979 0.6472135954999579 1.8 +1015 1.782518080587045 0.1663293526542072 1.2 +1016 1.692820323027551 0.3999999999999998 1.4 +1017 1.535304485087087 0.5945158603819153 1.6 +1018 1.32538931446064 0.7308363661140805 1.8 +1020 1.730836366114081 0.3253893144606399 1.2 +1021 1.594515860381915 0.5353044850870864 1.4 +1022 1.4 0.6928203230275508 1.6 +1023 1.166329352654208 0.7825180805870443 1.8 +1025 1.647213595499958 0.4702282018339782 1.2 +1026 1.470228201833979 0.6472135954999577 1.4 +1027 1.247213595499958 0.7608452130361227 1.6 +1028 1 0.8 1.8 +92 2 0 5 +201 0.5000000000000003 0.8660254037844388 2 +247 1.669130606358858 0.743144825477394 1.2 +248 1.406736643075801 0.9135454576426008 1.4 +249 1.104528463267654 0.9945218953682734 1.6 +250 0.792088309182241 0.9781476007338057 1.8 +96 2 0 20 +589 0.6909830056250529 0.9510565162951536 2 +590 0.8954715367323468 0.9945218953682735 2 +591 1.104528463267654 0.9945218953682733 2 +592 1.309016994374948 0.9510565162951536 2 +1050 1.809016994374947 0.5877852522924729 1.2 +1051 1.587785252292473 0.8090169943749472 1.4 +1052 1.309016994374948 0.9510565162951534 1.6 +1053 1 1 1.8 +1055 1.913545457642601 0.4067366430758 1.2 +1056 1.743144825477394 0.6691306063588581 1.4 +1057 1.5 0.8660254037844387 1.6 +1058 1.20791169081776 0.9781476007338058 1.8 +1060 1.978147600733806 0.2079116908177591 1.2 +1061 1.866025403784439 0.4999999999999998 1.4 +1062 1.669130606358858 0.7431448254773941 1.6 +1063 1.4067366430758 0.9135454576426008 1.8 +1065 2 -2.73191842412035e-16 1.2 +1066 1.951056516295154 0.3090169943749472 1.4 +1067 1.809016994374948 0.587785252292473 1.6 +1068 1.587785252292473 0.8090169943749473 1.8 +106 2 0 10 +251 1 1 3 +252 1 0.8 3 +273 1.951056516295154 0.3090169943749472 2.2 +274 1.809016994374947 0.587785252292473 2.4 +275 1.587785252292473 0.8090169943749473 2.6 +276 1.309016994374948 0.9510565162951535 2.8 +278 1.760845213036123 0.2472135954999579 2.2 +279 1.647213595499958 0.4702282018339785 2.4 +280 1.470228201833979 0.647213595499958 2.6 +281 1.247213595499958 0.7608452130361228 2.8 +110 2 0 25 +257 0.3071796769724491 0.4000000000000004 3 +293 1.166329352654208 0.7825180805870446 2.2 +294 0.9163772293858775 0.795617516294619 2.4 +295 0.6746106855393601 0.730836366114081 2.6 +296 0.4646955149129136 0.5945158603819157 2.8 +603 0.8336706473457928 0.7825180805870446 3 +604 0.67461068553936 0.7308363661140809 3 +605 0.5297717981660216 0.647213595499958 3 +606 0.4054841396180846 0.5353044850870865 3 +1110 1.692820323027551 0.3999999999999998 2.2 +1111 1.535304485087087 0.5945158603819153 2.4 +1112 1.32538931446064 0.7308363661140808 2.6 +1113 1.083622770614123 0.7956175162946187 2.8 +1115 1.594515860381915 0.5353044850870865 2.2 +1116 1.4 0.6928203230275509 2.4 +1117 1.166329352654208 0.7825180805870446 2.6 +1118 0.9163772293858774 0.7956175162946187 2.8 +1120 1.470228201833979 0.6472135954999579 2.2 +1121 1.247213595499958 0.7608452130361228 2.4 +1122 1 0.8 2.6 +1123 0.7527864045000422 0.760845213036123 2.8 +1125 1.32538931446064 0.7308363661140806 2.2 +1126 1.083622770614123 0.7956175162946186 2.4 +1127 0.8336706473457924 0.7825180805870445 2.6 +1128 0.6 0.6928203230275508 2.8 +118 2 0 25 +261 0.1339745962155614 0.5 3 +307 1.207911690817759 0.9781476007338056 2.2 +308 0.8954715367323466 0.9945218953682733 2.4 +309 0.5932633569241998 0.9135454576426009 2.6 +310 0.3308693936411419 0.7431448254773942 2.8 +607 0.256855174522606 0.6691306063588582 3 +608 0.4122147477075269 0.8090169943749475 3 +609 0.5932633569242 0.9135454576426008 3 +610 0.7920883091822409 0.9781476007338057 3 +1150 1.4067366430758 0.9135454576426006 2.2 +1151 1.104528463267654 0.9945218953682732 2.4 +1152 0.7920883091822408 0.9781476007338056 2.6 +1153 0.5000000000000002 0.8660254037844386 2.8 +1155 1.587785252292473 0.8090169943749473 2.2 +1156 1.309016994374947 0.9510565162951536 2.4 +1157 1 1 2.6 +1158 0.6909830056250527 0.9510565162951536 2.8 +1160 1.743144825477394 0.669130606358858 2.2 +1161 1.5 0.8660254037844385 2.4 +1162 1.207911690817759 0.9781476007338055 2.6 +1163 0.8954715367323467 0.9945218953682732 2.8 +1165 1.866025403784439 0.4999999999999998 2.2 +1166 1.669130606358858 0.7431448254773941 2.4 +1167 1.406736643075801 0.9135454576426009 2.6 +1168 1.104528463267654 0.9945218953682733 2.8 +132 2 0 25 +317 0.3071796769724489 -0.3999999999999997 3 +353 0.4054841396180848 0.5353044850870868 2.2 +354 0.2691636338859194 0.3253893144606405 2.4 +355 0.2043824837053813 0.08362277061412308 2.6 +356 0.2174819194129554 -0.1663293526542071 2.8 +631 0.239154786963877 0.2472135954999582 3 +632 0.2043824837053814 0.0836227706141231 3 +633 0.2043824837053814 -0.08362277061412243 3 +634 0.239154786963877 -0.2472135954999575 3 +1200 1 0.8000000000000002 2.2 +1201 0.7527864045000422 0.7608452130361231 2.4 +1202 0.5297717981660215 0.6472135954999582 2.6 +1203 0.3527864045000421 0.4702282018339787 2.8 +1205 0.8336706473457929 0.7825180805870445 2.2 +1206 0.6000000000000003 0.692820323027551 2.4 +1207 0.4054841396180848 0.5353044850870867 2.6 +1208 0.2691636338859195 0.3253893144606404 2.8 +1210 0.6746106855393601 0.7308363661140808 2.2 +1211 0.4646955149129137 0.5945158603819155 2.4 +1212 0.3071796769724493 0.4000000000000002 2.6 +1213 0.2174819194129557 0.1663293526542078 2.8 +1215 0.5297717981660218 0.6472135954999582 2.2 +1216 0.3527864045000423 0.4702282018339788 2.4 +1217 0.2391547869638773 0.2472135954999583 2.6 +1218 0.2000000000000001 4.093676352762143e-16 2.8 +136 2 0 5 +321 0.1339745962155612 -0.4999999999999996 3 +367 0.2568551745226061 0.6691306063588585 2.2 +368 0.08645454235739924 0.4067366430758006 2.4 +369 0.00547810463172671 0.1045284632676538 2.6 +370 0.02185239926619431 -0.2079116908177589 2.8 +140 2 0 20 +635 0.04894348370484636 -0.3090169943749471 3 +636 0.005478104631726488 -0.1045284632676531 3 +637 0.00547810463172671 0.1045284632676538 3 +638 0.04894348370484636 0.309016994374948 3 +1240 0.4122147477075272 0.8090169943749476 2.2 +1241 0.1909830056250528 0.5877852522924734 2.4 +1242 0.04894348370484658 0.3090169943749477 2.6 +1243 0 3.7659762461284e-16 2.8 +1245 0.5932633569242001 0.9135454576426011 2.2 +1246 0.3308693936411419 0.7431448254773946 2.4 +1247 0.1339745962155613 0.5000000000000003 2.6 +1248 0.02185239926619431 0.2079116908177597 2.8 +1250 0.7920883091822409 0.9781476007338057 2.2 +1251 0.5000000000000002 0.8660254037844388 2.4 +1252 0.256855174522606 0.6691306063588585 2.6 +1253 0.08645454235739924 0.4067366430758005 2.8 +1255 1 1 2.2 +1256 0.690983005625053 0.951056516295154 2.4 +1257 0.4122147477075271 0.8090169943749479 2.6 +1258 0.1909830056250527 0.5877852522924736 2.8 +150 2 0 10 +371 0 2.832749226161502e-16 4 +372 0.2 4.898425415289509e-17 4 +393 0.6909830056250528 0.9510565162951536 3.2 +394 0.4122147477075271 0.8090169943749476 3.4 +395 0.1909830056250527 0.5877852522924734 3.6 +396 0.04894348370484658 0.3090169943749477 3.8 +398 0.7527864045000421 0.7608452130361228 3.2 +399 0.5297717981660215 0.647213595499958 3.4 +400 0.352786404500042 0.4702282018339785 3.6 +401 0.2391547869638772 0.247213595499958 3.8 +154 2 0 25 +377 0.5999999999999995 -0.6928203230275509 4 +413 0.2174819194129554 0.1663293526542079 3.2 +414 0.204382483705381 -0.08362277061412242 3.4 +415 0.2691636338859189 -0.32538931446064 3.6 +416 0.4054841396180843 -0.5353044850870865 3.8 +649 0.2174819194129554 -0.1663293526542072 4 +650 0.2691636338859191 -0.32538931446064 4 +651 0.352786404500042 -0.4702282018339783 4 +652 0.4646955149129135 -0.5945158603819154 4 +1300 0.6000000000000002 0.692820323027551 3.2 +1301 0.4054841396180847 0.5353044850870868 3.4 +1302 0.2691636338859192 0.3253893144606405 3.6 +1303 0.2043824837053813 0.08362277061412307 3.8 +1305 0.4646955149129136 0.5945158603819155 3.2 +1306 0.3071796769724491 0.4000000000000002 3.4 +1307 0.2174819194129555 0.1663293526542077 3.6 +1308 0.2043824837053813 -0.08362277061412253 3.8 +1310 0.3527864045000422 0.4702282018339786 3.2 +1311 0.2391547869638772 0.2472135954999581 3.4 +1312 0.2 1.308903072733125e-16 3.6 +1313 0.239154786963877 -0.2472135954999578 3.8 +1315 0.2691636338859192 0.3253893144606401 3.2 +1316 0.2043824837053814 0.08362277061412275 3.4 +1317 0.2174819194129556 -0.1663293526542075 3.6 +1318 0.3071796769724492 -0.4 3.8 +162 2 0 25 +381 0.5 -0.8660254037844386 4 +427 0.02185239926619442 0.2079116908177593 3.2 +428 0.00547810463172671 -0.1045284632676534 3.4 +429 0.08645454235739913 -0.4067366430758002 3.6 +430 0.2568551745226058 -0.6691306063588581 3.8 +653 0.3308693936411418 -0.743144825477394 4 +654 0.1909830056250525 -0.5877852522924731 4 +655 0.08645454235739924 -0.4067366430758 4 +656 0.02185239926619431 -0.207911690817759 4 +1340 0.08645454235739924 0.4067366430758003 3.2 +1341 0.00547810463172671 0.1045284632676536 3.4 +1342 0.02185239926619442 -0.2079116908177592 3.6 +1343 0.1339745962155614 -0.4999999999999998 3.8 +1345 0.1909830056250525 0.5877852522924731 3.2 +1346 0.04894348370484636 0.3090169943749475 3.4 +1347 0 -1.265806036376826e-17 3.6 +1348 0.04894348370484636 -0.3090169943749474 3.8 +1350 0.330869393641142 0.7431448254773941 3.2 +1351 0.1339745962155615 0.5 3.4 +1352 0.02185239926619453 0.2079116908177594 3.6 +1353 0.005478104631726821 -0.1045284632676533 3.8 +1355 0.5000000000000002 0.8660254037844387 3.2 +1356 0.256855174522606 0.6691306063588585 3.4 +1357 0.08645454235739924 0.4067366430758005 3.6 +1358 0.00547810463172671 0.1045284632676538 3.8 +163 2 0 0 +176 2 0 25 +437 1.4 -0.6928203230275511 4 +473 0.4646955149129132 -0.5945158603819152 3.2 +474 0.6746106855393594 -0.7308363661140806 3.4 +475 0.9163772293858768 -0.7956175162946187 3.6 +476 1.166329352654207 -0.7825180805870445 3.8 +677 0.7527864045000418 -0.760845213036123 4 +678 0.9163772293858768 -0.7956175162946186 4 +679 1.083622770614122 -0.7956175162946186 4 +680 1.247213595499957 -0.760845213036123 4 +1390 0.1999999999999998 2.291054715733432e-16 3.2 +1391 0.2391547869638769 -0.2472135954999578 3.4 +1392 0.3527864045000418 -0.4702282018339784 3.6 +1393 0.5297717981660213 -0.6472135954999579 3.8 +1395 0.2174819194129555 -0.1663293526542071 3.2 +1396 0.3071796769724489 -0.3999999999999997 3.4 +1397 0.4646955149129132 -0.5945158603819152 3.6 +1398 0.6746106855393595 -0.7308363661140805 3.8 +1400 0.2691636338859192 -0.3253893144606398 3.2 +1401 0.4054841396180844 -0.5353044850870863 3.4 +1402 0.5999999999999998 -0.6928203230275507 3.6 +1403 0.8336706473457922 -0.7825180805870443 3.8 +1405 0.3527864045000418 -0.4702282018339781 3.2 +1406 0.5297717981660213 -0.6472135954999576 3.4 +1407 0.7527864045000416 -0.7608452130361226 3.6 +1408 0.9999999999999996 -0.7999999999999999 3.8 +180 2 0 5 +441 1.5 -0.8660254037844388 4 +487 0.3308693936411415 -0.7431448254773939 3.2 +488 0.5932633569241994 -0.9135454576426006 3.4 +489 0.8954715367323461 -0.9945218953682733 3.6 +490 1.207911690817759 -0.9781476007338057 3.8 +184 2 0 20 +681 1.309016994374947 -0.9510565162951536 4 +682 1.104528463267653 -0.9945218953682735 4 +683 0.8954715367323461 -0.9945218953682733 4 +684 0.690983005625052 -0.9510565162951536 4 +1430 0.1909830056250524 -0.5877852522924728 3.2 +1431 0.4122147477075266 -0.8090169943749471 3.4 +1432 0.6909830056250523 -0.9510565162951534 3.6 +1433 0.9999999999999996 -0.9999999999999999 3.8 +1435 0.0864545423573988 -0.4067366430757999 3.2 +1436 0.2568551745226054 -0.669130606358858 3.4 +1437 0.4999999999999996 -0.8660254037844387 3.6 +1438 0.7920883091822403 -0.9781476007338057 3.8 +1440 0.02185239926619431 -0.207911690817759 3.2 +1441 0.1339745962155612 -0.4999999999999997 3.4 +1442 0.3308693936411415 -0.743144825477394 3.6 +1443 0.5932633569241994 -0.9135454576426008 3.8 +1445 -2.220446049250313e-16 4.843673205578991e-16 3.2 +1446 0.04894348370484602 -0.309016994374947 3.4 +1447 0.1909830056250521 -0.5877852522924728 3.6 +1448 0.4122147477075263 -0.8090169943749472 3.8 +185 2 0 0 +1000 2 0 0 +1000 3 0 0 +$EndNodes +$Elements +28 660 +18 2 3 5 +306 36 41 12 11 +307 35 40 41 36 +308 34 39 40 35 +309 33 38 39 34 +310 1 2 38 33 +22 2 3 25 +201 748 56 17 514 +202 747 55 56 748 +203 746 54 55 747 +204 745 53 54 746 +205 499 4 53 745 +206 743 748 514 513 +207 742 747 748 743 +208 741 746 747 742 +209 740 745 746 741 +210 498 499 745 740 +211 738 743 513 512 +212 737 742 743 738 +213 736 741 742 737 +214 735 740 741 736 +215 497 498 740 735 +216 733 738 512 511 +217 732 737 738 733 +218 731 736 737 732 +219 730 735 736 731 +220 496 497 735 730 +221 41 733 511 12 +222 40 732 733 41 +223 39 731 732 40 +224 38 730 731 39 +225 2 496 730 38 +30 2 3 25 +251 788 70 21 515 +252 787 69 70 788 +253 786 68 69 787 +254 785 67 68 786 +255 494 3 67 785 +256 783 788 515 516 +257 782 787 788 783 +258 781 786 787 782 +259 780 785 786 781 +260 493 494 785 780 +261 778 783 516 517 +262 777 782 783 778 +263 776 781 782 777 +264 775 780 781 776 +265 492 493 780 775 +266 773 778 517 518 +267 772 777 778 773 +268 771 776 777 772 +269 770 775 776 771 +270 491 492 775 770 +271 36 773 518 11 +272 35 772 773 36 +273 34 771 772 35 +274 33 770 771 34 +275 1 491 770 33 +44 2 3 25 +226 838 116 77 542 +227 837 115 116 838 +228 836 114 115 837 +229 835 113 114 836 +230 509 10 113 835 +231 833 838 542 541 +232 832 837 838 833 +233 831 836 837 832 +234 830 835 836 831 +235 508 509 835 830 +236 828 833 541 540 +237 827 832 833 828 +238 826 831 832 827 +239 825 830 831 826 +240 507 508 830 825 +241 823 828 540 539 +242 822 827 828 823 +243 821 826 827 822 +244 820 825 826 821 +245 506 507 825 820 +246 56 823 539 17 +247 55 822 823 56 +248 54 821 822 55 +249 53 820 821 54 +250 4 506 820 53 +48 2 3 5 +301 130 116 77 81 +302 129 115 116 130 +303 128 114 115 129 +304 127 113 114 128 +305 9 10 113 127 +52 2 3 25 +276 878 130 81 543 +277 877 129 130 878 +278 876 128 129 877 +279 875 127 128 876 +280 504 9 127 875 +281 873 878 543 544 +282 872 877 878 873 +283 871 876 877 872 +284 870 875 876 871 +285 503 504 875 870 +286 868 873 544 545 +287 867 872 873 868 +288 866 871 872 867 +289 865 870 871 866 +290 502 503 870 865 +291 863 868 545 546 +292 862 867 868 863 +293 861 866 867 862 +294 860 865 866 861 +295 501 502 865 860 +296 70 863 546 21 +297 69 862 863 70 +298 68 861 862 69 +299 67 860 861 68 +300 3 501 860 67 +62 2 3 5 +426 156 161 132 131 +427 155 160 161 156 +428 154 159 160 155 +429 153 158 159 154 +430 11 12 158 153 +66 2 3 25 +401 938 176 137 560 +402 937 175 176 938 +403 936 174 175 937 +404 935 173 174 936 +405 514 17 173 935 +406 933 938 560 559 +407 932 937 938 933 +408 931 936 937 932 +409 930 935 936 931 +410 513 514 935 930 +411 928 933 559 558 +412 927 932 933 928 +413 926 931 932 927 +414 925 930 931 926 +415 512 513 930 925 +416 923 928 558 557 +417 922 927 928 923 +418 921 926 927 922 +419 920 925 926 921 +420 511 512 925 920 +421 161 923 557 132 +422 160 922 923 161 +423 159 921 922 160 +424 158 920 921 159 +425 12 511 920 158 +74 2 3 25 +376 978 156 131 564 +377 977 155 156 978 +378 976 154 155 977 +379 975 153 154 976 +380 518 11 153 975 +381 973 978 564 563 +382 972 977 978 973 +383 971 976 977 972 +384 970 975 976 971 +385 517 518 975 970 +386 968 973 563 562 +387 967 972 973 968 +388 966 971 972 967 +389 965 970 971 966 +390 516 517 970 965 +391 963 968 562 561 +392 962 967 968 963 +393 961 966 967 962 +394 960 965 966 961 +395 515 516 965 960 +396 190 963 561 141 +397 189 962 963 190 +398 188 961 962 189 +399 187 960 961 188 +400 21 515 960 187 +88 2 3 25 +351 1028 236 197 588 +352 1027 235 236 1028 +353 1026 234 235 1027 +354 1025 233 234 1026 +355 542 77 233 1025 +356 1023 1028 588 587 +357 1022 1027 1028 1023 +358 1021 1026 1027 1022 +359 1020 1025 1026 1021 +360 541 542 1025 1020 +361 1018 1023 587 586 +362 1017 1022 1023 1018 +363 1016 1021 1022 1017 +364 1015 1020 1021 1016 +365 540 541 1020 1015 +366 1013 1018 586 585 +367 1012 1017 1018 1013 +368 1011 1016 1017 1012 +369 1010 1015 1016 1011 +370 539 540 1015 1010 +371 176 1013 585 137 +372 175 1012 1013 176 +373 174 1011 1012 175 +374 173 1010 1011 174 +375 17 539 1010 173 +92 2 3 5 +321 236 250 201 197 +322 235 249 250 236 +323 234 248 249 235 +324 233 247 248 234 +325 77 81 247 233 +96 2 3 25 +326 1068 190 141 592 +327 1067 189 190 1068 +328 1066 188 189 1067 +329 1065 187 188 1066 +330 546 21 187 1065 +331 1063 1068 592 591 +332 1062 1067 1068 1063 +333 1061 1066 1067 1062 +334 1060 1065 1066 1061 +335 545 546 1065 1060 +336 1058 1063 591 590 +337 1057 1062 1063 1058 +338 1056 1061 1062 1057 +339 1055 1060 1061 1056 +340 544 545 1060 1055 +341 1053 1058 590 589 +342 1052 1057 1058 1053 +343 1051 1056 1057 1052 +344 1050 1055 1056 1051 +345 543 544 1055 1050 +346 250 1053 589 201 +347 249 1052 1053 250 +348 248 1051 1052 249 +349 247 1050 1051 248 +350 81 543 1050 247 +106 2 3 5 +536 276 281 252 251 +537 275 280 281 276 +538 274 279 280 275 +539 273 278 279 274 +540 131 132 278 273 +110 2 3 25 +511 1128 296 257 606 +512 1127 295 296 1128 +513 1126 294 295 1127 +514 1125 293 294 1126 +515 560 137 293 1125 +516 1123 1128 606 605 +517 1122 1127 1128 1123 +518 1121 1126 1127 1122 +519 1120 1125 1126 1121 +520 559 560 1125 1120 +521 1118 1123 605 604 +522 1117 1122 1123 1118 +523 1116 1121 1122 1117 +524 1115 1120 1121 1116 +525 558 559 1120 1115 +526 1113 1118 604 603 +527 1112 1117 1118 1113 +528 1111 1116 1117 1112 +529 1110 1115 1116 1111 +530 557 558 1115 1110 +531 281 1113 603 252 +532 280 1112 1113 281 +533 279 1111 1112 280 +534 278 1110 1111 279 +535 132 557 1110 278 +118 2 3 25 +486 1168 276 251 610 +487 1167 275 276 1168 +488 1166 274 275 1167 +489 1165 273 274 1166 +490 564 131 273 1165 +491 1163 1168 610 609 +492 1162 1167 1168 1163 +493 1161 1166 1167 1162 +494 1160 1165 1166 1161 +495 563 564 1165 1160 +496 1158 1163 609 608 +497 1157 1162 1163 1158 +498 1156 1161 1162 1157 +499 1155 1160 1161 1156 +500 562 563 1160 1155 +501 1153 1158 608 607 +502 1152 1157 1158 1153 +503 1151 1156 1157 1152 +504 1150 1155 1156 1151 +505 561 562 1155 1150 +506 310 1153 607 261 +507 309 1152 1153 310 +508 308 1151 1152 309 +509 307 1150 1151 308 +510 141 561 1150 307 +132 2 3 25 +456 1218 356 317 634 +457 1217 355 356 1218 +458 1216 354 355 1217 +459 1215 353 354 1216 +460 588 197 353 1215 +461 1213 1218 634 633 +462 1212 1217 1218 1213 +463 1211 1216 1217 1212 +464 1210 1215 1216 1211 +465 587 588 1215 1210 +466 1208 1213 633 632 +467 1207 1212 1213 1208 +468 1206 1211 1212 1207 +469 1205 1210 1211 1206 +470 586 587 1210 1205 +471 1203 1208 632 631 +472 1202 1207 1208 1203 +473 1201 1206 1207 1202 +474 1200 1205 1206 1201 +475 585 586 1205 1200 +476 296 1203 631 257 +477 295 1202 1203 296 +478 294 1201 1202 295 +479 293 1200 1201 294 +480 137 585 1200 293 +136 2 3 5 +481 356 370 321 317 +482 355 369 370 356 +483 354 368 369 355 +484 353 367 368 354 +485 197 201 367 353 +140 2 3 25 +431 1258 310 261 638 +432 1257 309 310 1258 +433 1256 308 309 1257 +434 1255 307 308 1256 +435 592 141 307 1255 +436 1253 1258 638 637 +437 1252 1257 1258 1253 +438 1251 1256 1257 1252 +439 1250 1255 1256 1251 +440 591 592 1255 1250 +441 1248 1253 637 636 +442 1247 1252 1253 1248 +443 1246 1251 1252 1247 +444 1245 1250 1251 1246 +445 590 591 1250 1245 +446 1243 1248 636 635 +447 1242 1247 1248 1243 +448 1241 1246 1247 1242 +449 1240 1245 1246 1241 +450 589 590 1245 1240 +451 370 1243 635 321 +452 369 1242 1243 370 +453 368 1241 1242 369 +454 367 1240 1241 368 +455 201 589 1240 367 +150 2 3 5 +591 396 401 372 371 +592 395 400 401 396 +593 394 399 400 395 +594 393 398 399 394 +595 251 252 398 393 +154 2 3 25 +566 1318 416 377 652 +567 1317 415 416 1318 +568 1316 414 415 1317 +569 1315 413 414 1316 +570 606 257 413 1315 +571 1313 1318 652 651 +572 1312 1317 1318 1313 +573 1311 1316 1317 1312 +574 1310 1315 1316 1311 +575 605 606 1315 1310 +576 1308 1313 651 650 +577 1307 1312 1313 1308 +578 1306 1311 1312 1307 +579 1305 1310 1311 1306 +580 604 605 1310 1305 +581 1303 1308 650 649 +582 1302 1307 1308 1303 +583 1301 1306 1307 1302 +584 1300 1305 1306 1301 +585 603 604 1305 1300 +586 401 1303 649 372 +587 400 1302 1303 401 +588 399 1301 1302 400 +589 398 1300 1301 399 +590 252 603 1300 398 +162 2 3 25 +541 1358 396 371 656 +542 1357 395 396 1358 +543 1356 394 395 1357 +544 1355 393 394 1356 +545 610 251 393 1355 +546 1353 1358 656 655 +547 1352 1357 1358 1353 +548 1351 1356 1357 1352 +549 1350 1355 1356 1351 +550 609 610 1355 1350 +551 1348 1353 655 654 +552 1347 1352 1353 1348 +553 1346 1351 1352 1347 +554 1345 1350 1351 1346 +555 608 609 1350 1345 +556 1343 1348 654 653 +557 1342 1347 1348 1343 +558 1341 1346 1347 1342 +559 1340 1345 1346 1341 +560 607 608 1345 1340 +561 430 1343 653 381 +562 429 1342 1343 430 +563 428 1341 1342 429 +564 427 1340 1341 428 +565 261 607 1340 427 +163 2 3 5 +656 653 652 377 381 +657 654 651 652 653 +658 655 650 651 654 +659 656 649 650 655 +660 371 372 649 656 +176 2 3 25 +621 1408 476 437 680 +622 1407 475 476 1408 +623 1406 474 475 1407 +624 1405 473 474 1406 +625 634 317 473 1405 +626 1403 1408 680 679 +627 1402 1407 1408 1403 +628 1401 1406 1407 1402 +629 1400 1405 1406 1401 +630 633 634 1405 1400 +631 1398 1403 679 678 +632 1397 1402 1403 1398 +633 1396 1401 1402 1397 +634 1395 1400 1401 1396 +635 632 633 1400 1395 +636 1393 1398 678 677 +637 1392 1397 1398 1393 +638 1391 1396 1397 1392 +639 1390 1395 1396 1391 +640 631 632 1395 1390 +641 416 1393 677 377 +642 415 1392 1393 416 +643 414 1391 1392 415 +644 413 1390 1391 414 +645 257 631 1390 413 +180 2 3 5 +646 476 490 441 437 +647 475 489 490 476 +648 474 488 489 475 +649 473 487 488 474 +650 317 321 487 473 +184 2 3 25 +596 1448 430 381 684 +597 1447 429 430 1448 +598 1446 428 429 1447 +599 1445 427 428 1446 +600 638 261 427 1445 +601 1443 1448 684 683 +602 1442 1447 1448 1443 +603 1441 1446 1447 1442 +604 1440 1445 1446 1441 +605 637 638 1445 1440 +606 1438 1443 683 682 +607 1437 1442 1443 1438 +608 1436 1441 1442 1437 +609 1435 1440 1441 1436 +610 636 637 1440 1435 +611 1433 1438 682 681 +612 1432 1437 1438 1433 +613 1431 1436 1437 1432 +614 1430 1435 1436 1431 +615 635 636 1435 1430 +616 490 1433 681 441 +617 489 1432 1433 490 +618 488 1431 1432 489 +619 487 1430 1431 488 +620 321 635 1430 487 +185 2 3 5 +651 681 680 437 441 +652 682 679 680 681 +653 683 678 679 682 +654 684 677 678 683 +655 381 377 677 684 +1000 2 3 10 +311 504 509 10 9 +312 503 508 509 504 +313 502 507 508 503 +314 501 506 507 502 +315 3 4 506 501 +316 494 499 4 3 +317 493 498 499 494 +318 492 497 498 493 +319 491 496 497 492 +320 1 2 496 491 +1000 3 5 200 +1 494 499 4 3 785 745 53 67 +2 785 745 53 67 786 746 54 68 +3 786 746 54 68 787 747 55 69 +4 787 747 55 69 788 748 56 70 +5 788 748 56 70 515 514 17 21 +6 493 498 499 494 780 740 745 785 +7 780 740 745 785 781 741 746 786 +8 781 741 746 786 782 742 747 787 +9 782 742 747 787 783 743 748 788 +10 783 743 748 788 516 513 514 515 +11 492 497 498 493 775 735 740 780 +12 775 735 740 780 776 736 741 781 +13 776 736 741 781 777 737 742 782 +14 777 737 742 782 778 738 743 783 +15 778 738 743 783 517 512 513 516 +16 491 496 497 492 770 730 735 775 +17 770 730 735 775 771 731 736 776 +18 771 731 736 776 772 732 737 777 +19 772 732 737 777 773 733 738 778 +20 773 733 738 778 518 511 512 517 +21 1 2 496 491 33 38 730 770 +22 33 38 730 770 34 39 731 771 +23 34 39 731 771 35 40 732 772 +24 35 40 732 772 36 41 733 773 +25 36 41 733 773 11 12 511 518 +26 504 509 10 9 875 835 113 127 +27 875 835 113 127 876 836 114 128 +28 876 836 114 128 877 837 115 129 +29 877 837 115 129 878 838 116 130 +30 878 838 116 130 543 542 77 81 +31 503 508 509 504 870 830 835 875 +32 870 830 835 875 871 831 836 876 +33 871 831 836 876 872 832 837 877 +34 872 832 837 877 873 833 838 878 +35 873 833 838 878 544 541 542 543 +36 502 507 508 503 865 825 830 870 +37 865 825 830 870 866 826 831 871 +38 866 826 831 871 867 827 832 872 +39 867 827 832 872 868 828 833 873 +40 868 828 833 873 545 540 541 544 +41 501 506 507 502 860 820 825 865 +42 860 820 825 865 861 821 826 866 +43 861 821 826 866 862 822 827 867 +44 862 822 827 867 863 823 828 868 +45 863 823 828 868 546 539 540 545 +46 3 4 506 501 67 53 820 860 +47 67 53 820 860 68 54 821 861 +48 68 54 821 861 69 55 822 862 +49 69 55 822 862 70 56 823 863 +50 70 56 823 863 21 17 539 546 +51 515 514 17 21 960 935 173 187 +52 960 935 173 187 961 936 174 188 +53 961 936 174 188 962 937 175 189 +54 962 937 175 189 963 938 176 190 +55 963 938 176 190 561 560 137 141 +56 516 513 514 515 965 930 935 960 +57 965 930 935 960 966 931 936 961 +58 966 931 936 961 967 932 937 962 +59 967 932 937 962 968 933 938 963 +60 968 933 938 963 562 559 560 561 +61 517 512 513 516 970 925 930 965 +62 970 925 930 965 971 926 931 966 +63 971 926 931 966 972 927 932 967 +64 972 927 932 967 973 928 933 968 +65 973 928 933 968 563 558 559 562 +66 518 511 512 517 975 920 925 970 +67 975 920 925 970 976 921 926 971 +68 976 921 926 971 977 922 927 972 +69 977 922 927 972 978 923 928 973 +70 978 923 928 973 564 557 558 563 +71 11 12 511 518 153 158 920 975 +72 153 158 920 975 154 159 921 976 +73 154 159 921 976 155 160 922 977 +74 155 160 922 977 156 161 923 978 +75 156 161 923 978 131 132 557 564 +76 543 542 77 81 1050 1025 233 247 +77 1050 1025 233 247 1051 1026 234 248 +78 1051 1026 234 248 1052 1027 235 249 +79 1052 1027 235 249 1053 1028 236 250 +80 1053 1028 236 250 589 588 197 201 +81 544 541 542 543 1055 1020 1025 1050 +82 1055 1020 1025 1050 1056 1021 1026 1051 +83 1056 1021 1026 1051 1057 1022 1027 1052 +84 1057 1022 1027 1052 1058 1023 1028 1053 +85 1058 1023 1028 1053 590 587 588 589 +86 545 540 541 544 1060 1015 1020 1055 +87 1060 1015 1020 1055 1061 1016 1021 1056 +88 1061 1016 1021 1056 1062 1017 1022 1057 +89 1062 1017 1022 1057 1063 1018 1023 1058 +90 1063 1018 1023 1058 591 586 587 590 +91 546 539 540 545 1065 1010 1015 1060 +92 1065 1010 1015 1060 1066 1011 1016 1061 +93 1066 1011 1016 1061 1067 1012 1017 1062 +94 1067 1012 1017 1062 1068 1013 1018 1063 +95 1068 1013 1018 1063 592 585 586 591 +96 21 17 539 546 187 173 1010 1065 +97 187 173 1010 1065 188 174 1011 1066 +98 188 174 1011 1066 189 175 1012 1067 +99 189 175 1012 1067 190 176 1013 1068 +100 190 176 1013 1068 141 137 585 592 +101 561 560 137 141 1150 1125 293 307 +102 1150 1125 293 307 1151 1126 294 308 +103 1151 1126 294 308 1152 1127 295 309 +104 1152 1127 295 309 1153 1128 296 310 +105 1153 1128 296 310 607 606 257 261 +106 562 559 560 561 1155 1120 1125 1150 +107 1155 1120 1125 1150 1156 1121 1126 1151 +108 1156 1121 1126 1151 1157 1122 1127 1152 +109 1157 1122 1127 1152 1158 1123 1128 1153 +110 1158 1123 1128 1153 608 605 606 607 +111 563 558 559 562 1160 1115 1120 1155 +112 1160 1115 1120 1155 1161 1116 1121 1156 +113 1161 1116 1121 1156 1162 1117 1122 1157 +114 1162 1117 1122 1157 1163 1118 1123 1158 +115 1163 1118 1123 1158 609 604 605 608 +116 564 557 558 563 1165 1110 1115 1160 +117 1165 1110 1115 1160 1166 1111 1116 1161 +118 1166 1111 1116 1161 1167 1112 1117 1162 +119 1167 1112 1117 1162 1168 1113 1118 1163 +120 1168 1113 1118 1163 610 603 604 609 +121 131 132 557 564 273 278 1110 1165 +122 273 278 1110 1165 274 279 1111 1166 +123 274 279 1111 1166 275 280 1112 1167 +124 275 280 1112 1167 276 281 1113 1168 +125 276 281 1113 1168 251 252 603 610 +126 589 588 197 201 1240 1215 353 367 +127 1240 1215 353 367 1241 1216 354 368 +128 1241 1216 354 368 1242 1217 355 369 +129 1242 1217 355 369 1243 1218 356 370 +130 1243 1218 356 370 635 634 317 321 +131 590 587 588 589 1245 1210 1215 1240 +132 1245 1210 1215 1240 1246 1211 1216 1241 +133 1246 1211 1216 1241 1247 1212 1217 1242 +134 1247 1212 1217 1242 1248 1213 1218 1243 +135 1248 1213 1218 1243 636 633 634 635 +136 591 586 587 590 1250 1205 1210 1245 +137 1250 1205 1210 1245 1251 1206 1211 1246 +138 1251 1206 1211 1246 1252 1207 1212 1247 +139 1252 1207 1212 1247 1253 1208 1213 1248 +140 1253 1208 1213 1248 637 632 633 636 +141 592 585 586 591 1255 1200 1205 1250 +142 1255 1200 1205 1250 1256 1201 1206 1251 +143 1256 1201 1206 1251 1257 1202 1207 1252 +144 1257 1202 1207 1252 1258 1203 1208 1253 +145 1258 1203 1208 1253 638 631 632 637 +146 141 137 585 592 307 293 1200 1255 +147 307 293 1200 1255 308 294 1201 1256 +148 308 294 1201 1256 309 295 1202 1257 +149 309 295 1202 1257 310 296 1203 1258 +150 310 296 1203 1258 261 257 631 638 +151 607 606 257 261 1340 1315 413 427 +152 1340 1315 413 427 1341 1316 414 428 +153 1341 1316 414 428 1342 1317 415 429 +154 1342 1317 415 429 1343 1318 416 430 +155 1343 1318 416 430 653 652 377 381 +156 608 605 606 607 1345 1310 1315 1340 +157 1345 1310 1315 1340 1346 1311 1316 1341 +158 1346 1311 1316 1341 1347 1312 1317 1342 +159 1347 1312 1317 1342 1348 1313 1318 1343 +160 1348 1313 1318 1343 654 651 652 653 +161 609 604 605 608 1350 1305 1310 1345 +162 1350 1305 1310 1345 1351 1306 1311 1346 +163 1351 1306 1311 1346 1352 1307 1312 1347 +164 1352 1307 1312 1347 1353 1308 1313 1348 +165 1353 1308 1313 1348 655 650 651 654 +166 610 603 604 609 1355 1300 1305 1350 +167 1355 1300 1305 1350 1356 1301 1306 1351 +168 1356 1301 1306 1351 1357 1302 1307 1352 +169 1357 1302 1307 1352 1358 1303 1308 1353 +170 1358 1303 1308 1353 656 649 650 655 +171 251 252 603 610 393 398 1300 1355 +172 393 398 1300 1355 394 399 1301 1356 +173 394 399 1301 1356 395 400 1302 1357 +174 395 400 1302 1357 396 401 1303 1358 +175 396 401 1303 1358 371 372 649 656 +176 635 634 317 321 1430 1405 473 487 +177 1430 1405 473 487 1431 1406 474 488 +178 1431 1406 474 488 1432 1407 475 489 +179 1432 1407 475 489 1433 1408 476 490 +180 1433 1408 476 490 681 680 437 441 +181 636 633 634 635 1435 1400 1405 1430 +182 1435 1400 1405 1430 1436 1401 1406 1431 +183 1436 1401 1406 1431 1437 1402 1407 1432 +184 1437 1402 1407 1432 1438 1403 1408 1433 +185 1438 1403 1408 1433 682 679 680 681 +186 637 632 633 636 1440 1395 1400 1435 +187 1440 1395 1400 1435 1441 1396 1401 1436 +188 1441 1396 1401 1436 1442 1397 1402 1437 +189 1442 1397 1402 1437 1443 1398 1403 1438 +190 1443 1398 1403 1438 683 678 679 682 +191 638 631 632 637 1445 1390 1395 1440 +192 1445 1390 1395 1440 1446 1391 1396 1441 +193 1446 1391 1396 1441 1447 1392 1397 1442 +194 1447 1392 1397 1442 1448 1393 1398 1443 +195 1448 1393 1398 1443 684 677 678 683 +196 261 257 631 638 427 413 1390 1445 +197 427 413 1390 1445 428 414 1391 1446 +198 428 414 1391 1446 429 415 1392 1447 +199 429 415 1392 1447 430 416 1393 1448 +200 430 416 1393 1448 381 377 677 684 +$EndElements diff --git a/tests/grid/grids/grid_in_msh_02_v4.msh b/tests/grid/grids/grid_in_msh_02_v4.msh new file mode 100644 index 000000000000..a2676871b9a2 --- /dev/null +++ b/tests/grid/grids/grid_in_msh_02_v4.msh @@ -0,0 +1,44 @@ +$MeshFormat +4 0 8 +$EndMeshFormat +$Entities +2 1 0 0 +1 0 0 0 0 0 0 1 10 +2 1 0 0 1 0 0 1 20 +1 0 0 0 1 0 0 1 100 0 +$EndEntities +$Nodes +3 11 +1 0 0 1 +1 0 0 0 +2 0 0 1 +2 1 0 0 +1 1 0 9 +3 0.1 0 0 +4 0.2 0 0 +5 0.3 0 0 +6 0.4 0 0 +7 0.5 0 0 +8 0.6 0 0 +9 0.7 0 0 +10 0.8 0 0 +11 0.9 0 0 +$EndNodes +$Elements +3 12 +1 0 15 1 +1 1 +2 0 15 1 +2 2 +1 1 1 10 +3 1 3 +4 3 4 +5 4 5 +6 5 6 +7 6 7 +8 7 8 +9 8 9 +10 9 10 +11 10 11 +12 11 2 +$EndElements From ef7fa1d3469fd98cba6925fdd7029237612b12f6 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 26 Jan 2019 15:34:33 +0100 Subject: [PATCH 012/507] Fix TrilinosWrappers::PreconditionMueLu --- source/lac/trilinos_precondition_muelu.cc | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/source/lac/trilinos_precondition_muelu.cc b/source/lac/trilinos_precondition_muelu.cc index f36f7cbd6746..cbaa3124a40a 100644 --- a/source/lac/trilinos_precondition_muelu.cc +++ b/source/lac/trilinos_precondition_muelu.cc @@ -18,21 +18,11 @@ #ifdef DEAL_II_WITH_TRILINOS # if DEAL_II_TRILINOS_VERSION_GTE(11, 14, 0) - # include -# include # include -# include -# include -# include # include -# include -# include -# include -# include # include -# include DEAL_II_NAMESPACE_OPEN @@ -98,6 +88,8 @@ namespace TrilinosWrappers // Build the AMG preconditioner. Teuchos::ParameterList parameter_list; + parameter_list.set("parameterlist: syntax", "ml"); + if (additional_data.elliptic == true) ML_Epetra::SetDefaults("SA", parameter_list); else From d10fed17a8ab6fc7b7634a8727e2944dbc74f2aa Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 26 Jan 2019 16:13:16 +0100 Subject: [PATCH 013/507] Don't use __builtin_expect in Utilities::pow --- include/deal.II/base/utilities.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/include/deal.II/base/utilities.h b/include/deal.II/base/utilities.h index f2a1cb6b6e1b..f49c3021321b 100644 --- a/include/deal.II/base/utilities.h +++ b/include/deal.II/base/utilities.h @@ -404,9 +404,10 @@ namespace Utilities constexpr unsigned int pow(const unsigned int base, const int iexp) { -#ifdef DEAL_II_WITH_CXX14 -# ifdef DEAL_II_HAVE_CXX14_CONSTEXPR_CAN_CALL_NONCONSTEXPR -# if defined(DEAL_II_HAVE_BUILTIN_EXPECT) && defined(__INTEL_COMPILER) +#if defined(DEBUG) && defined(DEAL_II_WITH_CXX14) && \ + defined(DEAL_II_HAVE_CXX14_CONSTEXPR_CAN_CALL_NONCONSTEXPR) + // Up to __builtin_expect this is the same code as in the 'Assert' macro. + // The call to __builtin_expect turns out to be problematic. if (!(iexp >= 0)) ::dealii::deal_II_exceptions::internals::issue_error_noreturn( ::dealii::deal_II_exceptions::internals::abort_or_throw_on_exception, @@ -416,10 +417,6 @@ namespace Utilities "iexp>=0", "ExcMessage(\"The exponent must not be negative!\")", ExcMessage("The exponent must not be negative!")); -# else - Assert(iexp >= 0, ExcMessage("The exponent must not be negative!")); -# endif -# endif #endif // The "exponentiation by squaring" algorithm used below has to be // compressed to one statement due to C++11's restrictions on constexpr From 033699e59ff20c5cdb86e069259eba3e715f5cf4 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 26 Jan 2019 16:54:16 +0100 Subject: [PATCH 014/507] Rename variables using snake_case style --- source/grid/grid_in.cc | 83 +++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/source/grid/grid_in.cc b/source/grid/grid_in.cc index 87fe841d9c03..2aac678cadd5 100644 --- a/source/grid/grid_in.cc +++ b/source/grid/grid_in.cc @@ -1455,69 +1455,68 @@ GridIn::read_msh(std::istream &in) // if the next block is of kind $Entities, parse it if (line == "$Entities") { - unsigned long numPoints, numCurves, numSurfaces, numVolumes, - numPhysicals; - int tag, physicalTag; - double boxMinX, boxMinY, boxMinZ, boxMaxX, boxMaxY, boxMaxZ; - - in >> numPoints >> numCurves >> numSurfaces >> numVolumes; - for (unsigned int i = 0; i < numPoints; ++i) + unsigned long n_points, n_curves, n_surfaces, n_volumes, n_physicals; + int tag, physical_tag; + double box_min_x, box_min_y, box_min_z, box_max_x, box_max_y, + box_max_z; + + // we only care for physical_tag to fill tag_maps + in >> n_points >> n_curves >> n_surfaces >> n_volumes; + for (unsigned int i = 0; i < n_points; ++i) { // parse point ids - in >> tag >> boxMinX >> boxMinY >> boxMinZ >> boxMaxX >> - boxMaxY >> boxMaxZ >> numPhysicals; - AssertThrow(numPhysicals < 2, + in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> + box_max_y >> box_max_z >> n_physicals; + AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); - for (unsigned int j = 0; j < numPhysicals; ++j) - in >> physicalTag; - tag_maps[0][tag] = (numPhysicals == 0) ? 0 : physicalTag; + for (unsigned int j = 0; j < n_physicals; ++j) + in >> physical_tag; + tag_maps[0][tag] = (n_physicals == 0) ? 0 : physical_tag; } - for (unsigned int i = 0; i < numCurves; ++i) + for (unsigned int i = 0; i < n_curves; ++i) { // parse curve ids - in >> tag >> boxMinX >> boxMinY >> boxMinZ >> boxMaxX >> - boxMaxY >> boxMaxZ >> numPhysicals; - AssertThrow(numPhysicals < 2, + in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> + box_max_y >> box_max_z >> n_physicals; + AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); - for (unsigned int j = 0; j < numPhysicals; ++j) - in >> physicalTag; - tag_maps[1][tag] = (numPhysicals == 0) ? 0 : physicalTag; - in >> numPoints; - for (unsigned int j = 0; j < numPoints; ++j) + for (unsigned int j = 0; j < n_physicals; ++j) + in >> physical_tag; + tag_maps[1][tag] = (n_physicals == 0) ? 0 : physical_tag; + in >> n_points; + for (unsigned int j = 0; j < n_points; ++j) in >> tag; } - for (unsigned int i = 0; i < numSurfaces; ++i) + for (unsigned int i = 0; i < n_surfaces; ++i) { // parse surface ids - in >> tag >> boxMinX >> boxMinY >> boxMinZ >> boxMaxX >> - boxMaxY >> boxMaxZ >> numPhysicals; - AssertThrow(numPhysicals < 2, + in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> + box_max_y >> box_max_z >> n_physicals; + AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); - for (unsigned int j = 0; j < numPhysicals; ++j) - in >> physicalTag; - tag_maps[2][tag] = (numPhysicals == 0) ? 0 : physicalTag; - in >> numCurves; - for (unsigned int j = 0; j < numCurves; ++j) + for (unsigned int j = 0; j < n_physicals; ++j) + in >> physical_tag; + tag_maps[2][tag] = (n_physicals == 0) ? 0 : physical_tag; + in >> n_curves; + for (unsigned int j = 0; j < n_curves; ++j) in >> tag; } - for (unsigned int i = 0; i < numVolumes; ++i) + for (unsigned int i = 0; i < n_volumes; ++i) { // parse volume ids - in >> tag >> boxMinX >> boxMinY >> boxMinZ >> boxMaxX >> - boxMaxY >> boxMaxZ >> numPhysicals; - AssertThrow(numPhysicals < 2, + in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> + box_max_y >> box_max_z >> n_physicals; + AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); - for (unsigned int j = 0; j < numPhysicals; ++j) - in >> physicalTag; - tag_maps[3][tag] = (numPhysicals == 0) ? 0 : physicalTag; - in >> numSurfaces; - for (unsigned int j = 0; j < numSurfaces; ++j) + for (unsigned int j = 0; j < n_physicals; ++j) + in >> physical_tag; + tag_maps[3][tag] = (n_physicals == 0) ? 0 : physical_tag; + in >> n_surfaces; + for (unsigned int j = 0; j < n_surfaces; ++j) in >> tag; } - std::cout << line << std::endl; in >> line; - std::cout << line << std::endl; AssertThrow(line == "$EndEntities", ExcInvalidGMSHInput(line)); in >> line; } From e3578030656392270b92be80198fea5859fb8a2f Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 26 Jan 2019 17:35:22 +0100 Subject: [PATCH 015/507] Use default destructor and avoid constructor to be defaulted --- include/deal.II/lac/trilinos_precondition.h | 2 +- source/lac/trilinos_precondition_muelu.cc | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/include/deal.II/lac/trilinos_precondition.h b/include/deal.II/lac/trilinos_precondition.h index 0b75cd92a8b3..cb6d2ee11b62 100644 --- a/include/deal.II/lac/trilinos_precondition.h +++ b/include/deal.II/lac/trilinos_precondition.h @@ -1783,7 +1783,7 @@ namespace TrilinosWrappers /** * Destructor. */ - ~PreconditionAMGMueLu() override; + virtual ~PreconditionAMGMueLu() override = default; /** * Let Trilinos compute a multilevel hierarchy for the solution of a diff --git a/source/lac/trilinos_precondition_muelu.cc b/source/lac/trilinos_precondition_muelu.cc index cbaa3124a40a..3a26b73462e1 100644 --- a/source/lac/trilinos_precondition_muelu.cc +++ b/source/lac/trilinos_precondition_muelu.cc @@ -55,19 +55,16 @@ namespace TrilinosWrappers PreconditionAMGMueLu::PreconditionAMGMueLu() { + // clang-tidy wants to default the constructor if we disable the check + // in case we compile without 64-bit indices # ifdef DEAL_II_WITH_64BIT_INDICES - AssertThrow(false, + constexpr bool enabled = false; +# else + constexpr bool enabled = true; +# endif + AssertThrow(enabled, ExcMessage( "PreconditionAMGMueLu does not support 64bit-indices!")); -# endif - } - - - - PreconditionAMGMueLu::~PreconditionAMGMueLu() - { - preconditioner.reset(); - trilinos_matrix.reset(); } From c7dc2af1af5fe17420262d1607df1a5bee749646 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 27 Jan 2019 11:15:31 +0100 Subject: [PATCH 016/507] Add more comments --- source/grid/grid_in.cc | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/source/grid/grid_in.cc b/source/grid/grid_in.cc index 2aac678cadd5..c063e1794e2e 100644 --- a/source/grid/grid_in.cc +++ b/source/grid/grid_in.cc @@ -1460,29 +1460,37 @@ GridIn::read_msh(std::istream &in) double box_min_x, box_min_y, box_min_z, box_max_x, box_max_y, box_max_z; - // we only care for physical_tag to fill tag_maps + // we only care for 'physical_tag' to fill tag_maps in >> n_points >> n_curves >> n_surfaces >> n_volumes; for (unsigned int i = 0; i < n_points; ++i) { // parse point ids + // we only care for 'tag' as key for tag_maps[0] in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> box_max_y >> box_max_z >> n_physicals; + // if there is a physical tag, we will use it as boundary id below AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); for (unsigned int j = 0; j < n_physicals; ++j) in >> physical_tag; + // if there is no physical tag, use 0 as default tag_maps[0][tag] = (n_physicals == 0) ? 0 : physical_tag; } for (unsigned int i = 0; i < n_curves; ++i) { // parse curve ids + // we only care for 'tag' as key for tag_maps[1] in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> box_max_y >> box_max_z >> n_physicals; + // if there is a physical tag, we will use it as boundary id below AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); for (unsigned int j = 0; j < n_physicals; ++j) in >> physical_tag; + // if there is no physical tag, use 0 as default tag_maps[1][tag] = (n_physicals == 0) ? 0 : physical_tag; + // we don't care about the points associated to a curve, but have + // to parse them anyway because their format is unstructured in >> n_points; for (unsigned int j = 0; j < n_points; ++j) in >> tag; @@ -1491,13 +1499,18 @@ GridIn::read_msh(std::istream &in) for (unsigned int i = 0; i < n_surfaces; ++i) { // parse surface ids + // we only care for 'tag' as key for tag_maps[2] in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> box_max_y >> box_max_z >> n_physicals; + // if there is a physical tag, we will use it as boundary id below AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); for (unsigned int j = 0; j < n_physicals; ++j) in >> physical_tag; + // if there is no physical tag, use 0 as default tag_maps[2][tag] = (n_physicals == 0) ? 0 : physical_tag; + // we don't care about the curves associated to a surface, but + // have to parse them anyway because their format is unstructured in >> n_curves; for (unsigned int j = 0; j < n_curves; ++j) in >> tag; @@ -1505,13 +1518,18 @@ GridIn::read_msh(std::istream &in) for (unsigned int i = 0; i < n_volumes; ++i) { // parse volume ids + // we only care for 'tag' as key for tag_maps[3] in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> box_max_y >> box_max_z >> n_physicals; + // if there is a physical tag, we will use it as boundary id below AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); for (unsigned int j = 0; j < n_physicals; ++j) in >> physical_tag; + // if there is no physical tag, use 0 as default tag_maps[3][tag] = (n_physicals == 0) ? 0 : physical_tag; + // we don't care about the surfaces associated to a volume, but + // have to parse them anyway because their format is unstructured in >> n_surfaces; for (unsigned int j = 0; j < n_surfaces; ++j) in >> tag; From ab38b0beb03be3e58bcf369abca609beb1d8fa15 Mon Sep 17 00:00:00 2001 From: David Wells Date: Sun, 27 Jan 2019 16:48:17 -0500 Subject: [PATCH 017/507] Explicitly use Zoltan in two tests. This doesn't matter in 05 (since that test only uses one processor) but the output file states that we use Zoltan, so we should be consistent. This is needed in 07 since the default third argument to partition_triangulation is metis, but the output file states that we use Zoltan. --- tests/fe/fe_enriched_color_05.cc | 6 ++++-- tests/fe/fe_enriched_color_07.cc | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/fe/fe_enriched_color_05.cc b/tests/fe/fe_enriched_color_05.cc index 650462f4cb46..0f4d5c629f54 100644 --- a/tests/fe/fe_enriched_color_05.cc +++ b/tests/fe/fe_enriched_color_05.cc @@ -254,8 +254,10 @@ main(int argc, char **argv) } #ifdef DATA_OUT_FE_ENRICHED - GridTools::partition_triangulation( - Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD), triangulation); + GridTools::partition_triangulation(Utilities::MPI::n_mpi_processes( + MPI_COMM_WORLD), + triangulation, + SparsityTools::Partitioner::zoltan); dof_handler.distribute_dofs(*fe_collection); plot_shape_function(dof_handler, 5); diff --git a/tests/fe/fe_enriched_color_07.cc b/tests/fe/fe_enriched_color_07.cc index cb542663952a..1ff3fa834e05 100644 --- a/tests/fe/fe_enriched_color_07.cc +++ b/tests/fe/fe_enriched_color_07.cc @@ -1424,7 +1424,9 @@ LaplaceProblem::setup_system() { pcout << "...start setup system" << std::endl; - GridTools::partition_triangulation(n_mpi_processes, triangulation); + GridTools::partition_triangulation(n_mpi_processes, + triangulation, + SparsityTools::Partitioner::zoltan); dof_handler.distribute_dofs(*fe_collection); From 34e105d67b4de6411073e30eabb8324352fa0181 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 28 Jan 2019 14:15:57 +0100 Subject: [PATCH 018/507] Declare VectorizedArray::n_array_elemnts outside the class in the general case --- include/deal.II/base/vectorization.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/deal.II/base/vectorization.h b/include/deal.II/base/vectorization.h index 1a6d223e62a7..3f82e165c52e 100644 --- a/include/deal.II/base/vectorization.h +++ b/include/deal.II/base/vectorization.h @@ -174,9 +174,11 @@ class VectorizedArray { public: /** - * This gives the number of vectors collected in this class. + * This gives the number of elements collected in this class. In the general + * case, there is only one element. Specializations use SIMD intrinsics and + * can work on multiple elements at the same time. */ - static const unsigned int n_array_elements = 1; + static const unsigned int n_array_elements; // POD means that there should be no user-defined constructors, destructors // and copy functions (the standard is somewhat relaxed in C++2011, though). @@ -449,6 +451,10 @@ class VectorizedArray std::min(const VectorizedArray &, const VectorizedArray &); }; +// We need to have a separate declaration for static const members +template +const unsigned int VectorizedArray::n_array_elements = 1; + /** From 1dfa511f2ea11dcfb7129baad827298b91ed9563 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Wed, 16 Jan 2019 17:43:46 -0700 Subject: [PATCH 019/507] [CI] test on OSX - add a separate Jenkinsfile for OSX - compile deal.II using clang on OSX --- contrib/ci/Jenkinsfile.osx | 88 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 contrib/ci/Jenkinsfile.osx diff --git a/contrib/ci/Jenkinsfile.osx b/contrib/ci/Jenkinsfile.osx new file mode 100644 index 000000000000..fbee05a7686f --- /dev/null +++ b/contrib/ci/Jenkinsfile.osx @@ -0,0 +1,88 @@ +#!groovy + +/* +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 +*/ + +pipeline +{ + agent { + node { + label 'osx' + } + } + + 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 + 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 + ''' + } + } + + post + { + failure + { + githubNotify context: 'OSX', description: 'build failed', status: 'FAILURE' + } + } + } + + stage("finalize") + { + steps + { + githubNotify context: 'OSX', description: 'OK', status: 'SUCCESS' + } + } + } +} From be7654056ae98f3841220236484ff053be05afc3 Mon Sep 17 00:00:00 2001 From: David Wells Date: Mon, 28 Jan 2019 16:51:31 -0500 Subject: [PATCH 020/507] Mark a few Subscriptor functions as inline. These are simple enough that they should live in the header. This will allow classes inheriting from Subscriptor to potentially inline some more constructors too. --- include/deal.II/base/subscriptor.h | 31 +++++++++++++++++++++++++++ source/base/subscriptor.cc | 34 ------------------------------ 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/include/deal.II/base/subscriptor.h b/include/deal.II/base/subscriptor.h index f59d18283973..431f8c03e412 100644 --- a/include/deal.II/base/subscriptor.h +++ b/include/deal.II/base/subscriptor.h @@ -290,6 +290,37 @@ class Subscriptor //--------------------------------------------------------------------------- +inline Subscriptor::Subscriptor() + : counter(0) + , object_info(nullptr) +{} + + + +inline Subscriptor::Subscriptor(const Subscriptor &) + : counter(0) + , object_info(nullptr) +{} + + + +inline Subscriptor & +Subscriptor::operator=(const Subscriptor &s) +{ + object_info = s.object_info; + return *this; +} + + + +inline unsigned int +Subscriptor::n_subscriptions() const +{ + return counter; +} + + + template inline void Subscriptor::serialize(Archive &, const unsigned int) diff --git a/source/base/subscriptor.cc b/source/base/subscriptor.cc index aeac2c0807dd..669f71b9092b 100644 --- a/source/base/subscriptor.cc +++ b/source/base/subscriptor.cc @@ -31,23 +31,6 @@ static const char *unknown_subscriber = "unknown subscriber"; std::mutex Subscriptor::mutex; -Subscriptor::Subscriptor() - : counter(0) - , object_info(nullptr) -{ - // this has to go somewhere to avoid an extra warning. - (void)unknown_subscriber; -} - - - -Subscriptor::Subscriptor(const Subscriptor &) - : counter(0) - , object_info(nullptr) -{} - - - Subscriptor::Subscriptor(Subscriptor &&subscriptor) noexcept : counter(0) , object_info(subscriptor.object_info) @@ -132,15 +115,6 @@ Subscriptor::check_no_subscribers() const noexcept -Subscriptor & -Subscriptor::operator=(const Subscriptor &s) -{ - object_info = s.object_info; - return *this; -} - - - Subscriptor & Subscriptor::operator=(Subscriptor &&s) noexcept { @@ -224,14 +198,6 @@ Subscriptor::unsubscribe(std::atomic *const validity, -unsigned int -Subscriptor::n_subscriptions() const -{ - return counter; -} - - - void Subscriptor::list_subscribers() const { From b7195c403286301321129fad732fb81f9a657ce8 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 29 Jan 2019 02:01:52 +0100 Subject: [PATCH 021/507] Move some declarations around and document tag_maps --- source/grid/grid_in.cc | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/source/grid/grid_in.cc b/source/grid/grid_in.cc index c063e1794e2e..f1adce9915e5 100644 --- a/source/grid/grid_in.cc +++ b/source/grid/grid_in.cc @@ -1404,10 +1404,13 @@ GridIn::read_msh(std::istream &in) Assert(tria != nullptr, ExcNoTriangulationSelected()); AssertThrow(in, ExcIO()); - unsigned int n_vertices; - unsigned int n_cells; - unsigned int dummy; - std::string line; + unsigned int n_vertices; + unsigned int n_cells; + unsigned int dummy; + std::string line; + // This array stores maps from the 'entities' to the 'physical tags' for + // points, curves, surfaces and volumes. We use this information later to + // assign boundary ids. std::array, 4> tag_maps; in >> line; @@ -1455,22 +1458,24 @@ GridIn::read_msh(std::istream &in) // if the next block is of kind $Entities, parse it if (line == "$Entities") { - unsigned long n_points, n_curves, n_surfaces, n_volumes, n_physicals; - int tag, physical_tag; - double box_min_x, box_min_y, box_min_z, box_max_x, box_max_y, - box_max_z; + unsigned long n_points, n_curves, n_surfaces, n_volumes; - // we only care for 'physical_tag' to fill tag_maps in >> n_points >> n_curves >> n_surfaces >> n_volumes; for (unsigned int i = 0; i < n_points; ++i) { // parse point ids + int tag; + unsigned int n_physicals; + double box_min_x, box_min_y, box_min_z, box_max_x, box_max_y, + box_max_z; + // we only care for 'tag' as key for tag_maps[0] in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> box_max_y >> box_max_z >> n_physicals; // if there is a physical tag, we will use it as boundary id below AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); + int physical_tag; for (unsigned int j = 0; j < n_physicals; ++j) in >> physical_tag; // if there is no physical tag, use 0 as default @@ -1479,12 +1484,18 @@ GridIn::read_msh(std::istream &in) for (unsigned int i = 0; i < n_curves; ++i) { // parse curve ids + int tag; + unsigned int n_physicals; + double box_min_x, box_min_y, box_min_z, box_max_x, box_max_y, + box_max_z; + // we only care for 'tag' as key for tag_maps[1] in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> box_max_y >> box_max_z >> n_physicals; // if there is a physical tag, we will use it as boundary id below AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); + int physical_tag; for (unsigned int j = 0; j < n_physicals; ++j) in >> physical_tag; // if there is no physical tag, use 0 as default @@ -1499,12 +1510,18 @@ GridIn::read_msh(std::istream &in) for (unsigned int i = 0; i < n_surfaces; ++i) { // parse surface ids + int tag; + unsigned int n_physicals; + double box_min_x, box_min_y, box_min_z, box_max_x, box_max_y, + box_max_z; + // we only care for 'tag' as key for tag_maps[2] in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> box_max_y >> box_max_z >> n_physicals; // if there is a physical tag, we will use it as boundary id below AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); + int physical_tag; for (unsigned int j = 0; j < n_physicals; ++j) in >> physical_tag; // if there is no physical tag, use 0 as default @@ -1518,12 +1535,18 @@ GridIn::read_msh(std::istream &in) for (unsigned int i = 0; i < n_volumes; ++i) { // parse volume ids + int tag; + unsigned int n_physicals; + double box_min_x, box_min_y, box_min_z, box_max_x, box_max_y, + box_max_z; + // we only care for 'tag' as key for tag_maps[3] in >> tag >> box_min_x >> box_min_y >> box_min_z >> box_max_x >> box_max_y >> box_max_z >> n_physicals; // if there is a physical tag, we will use it as boundary id below AssertThrow(n_physicals < 2, ExcMessage("More than one tag is not supported!")); + int physical_tag; for (unsigned int j = 0; j < n_physicals; ++j) in >> physical_tag; // if there is no physical tag, use 0 as default From d54882b789fef2396453d2c571dee4930d7038de Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 29 Jan 2019 10:52:18 +0100 Subject: [PATCH 022/507] modernize-return-braced-init-list --- examples/step-33/step-33.cc | 8 ++-- examples/step-42/step-42.cc | 2 +- examples/step-49/step-49.cc | 2 +- examples/step-53/step-53.cc | 7 ++- include/deal.II/base/geometry_info.h | 6 ++- include/deal.II/base/index_set.h | 14 ++---- include/deal.II/base/symmetric_tensor.h | 46 +++++++++---------- include/deal.II/fe/fe_values.h | 22 ++++----- .../deal.II/grid/tria_accessor.templates.h | 4 +- include/deal.II/lac/block_indices.h | 2 +- include/deal.II/lac/chunk_sparsity_pattern.h | 10 ++-- .../deal.II/lac/dynamic_sparsity_pattern.h | 12 ++--- include/deal.II/lac/linear_operator.h | 4 +- include/deal.II/lac/sparsity_pattern.h | 10 ++-- include/deal.II/lac/trilinos_sparse_matrix.h | 2 +- include/deal.II/matrix_free/matrix_free.h | 5 +- source/base/data_out_base.cc | 2 +- source/base/function_lib.cc | 2 +- source/base/hdf5.cc | 8 ++-- source/dofs/dof_handler_policy.cc | 2 +- source/fe/fe.cc | 20 ++++---- source/fe/mapping_q_generic.cc | 10 ++-- source/grid/grid_tools.cc | 22 ++++----- source/grid/manifold.cc | 20 ++++---- source/grid/manifold_lib.cc | 12 ++--- source/grid/tria_accessor.cc | 6 +-- source/opencascade/manifold_lib.cc | 2 +- 27 files changed, 124 insertions(+), 138 deletions(-) diff --git a/examples/step-33/step-33.cc b/examples/step-33/step-33.cc index a3ce08eb58b4..917b51fcd30d 100644 --- a/examples/step-33/step-33.cc +++ b/examples/step-33/step-33.cc @@ -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-42/step-42.cc b/examples/step-42/step-42.cc index 2006200602e5..94cc9e445aa9 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 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-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/include/deal.II/base/geometry_info.h b/include/deal.II/base/geometry_info.h index 31e75d1f0e0e..f5b35f8fddc8 100644 --- a/include/deal.II/base/geometry_info.h +++ b/include/deal.II/base/geometry_info.h @@ -2519,7 +2519,7 @@ GeometryInfo<2>::unit_cell_vertex(const unsigned int vertex) Assert(vertex < vertices_per_cell, ExcIndexRange(vertex, 0, vertices_per_cell)); - return Point<2>(vertex % 2, vertex / 2); + return {static_cast(vertex % 2), static_cast(vertex / 2)}; } @@ -2531,7 +2531,9 @@ GeometryInfo<3>::unit_cell_vertex(const unsigned int vertex) Assert(vertex < vertices_per_cell, ExcIndexRange(vertex, 0, vertices_per_cell)); - return Point<3>(vertex % 2, vertex / 2 % 2, vertex / 4); + return {static_cast(vertex % 2), + static_cast(vertex / 2 % 2), + static_cast(vertex / 4)}; } diff --git a/include/deal.II/base/index_set.h b/include/deal.II/base/index_set.h index 439775a1309f..fec38b883f22 100644 --- a/include/deal.II/base/index_set.h +++ b/include/deal.II/base/index_set.h @@ -1030,9 +1030,7 @@ inline IndexSet::ElementIterator IndexSet::IntervalAccessor::begin() const { Assert(is_valid(), ExcMessage("invalid iterator")); - return IndexSet::ElementIterator(index_set, - range_idx, - index_set->ranges[range_idx].begin); + return {index_set, range_idx, index_set->ranges[range_idx].begin}; } @@ -1044,9 +1042,7 @@ IndexSet::IntervalAccessor::end() const // point to first index in next interval unless we are the last interval. if (range_idx < index_set->ranges.size() - 1) - return IndexSet::ElementIterator(index_set, - range_idx + 1, - index_set->ranges[range_idx + 1].begin); + return {index_set, range_idx + 1, index_set->ranges[range_idx + 1].begin}; else return index_set->end(); } @@ -1479,7 +1475,7 @@ IndexSet::begin() const { compress(); if (ranges.size() > 0) - return IndexSet::ElementIterator(this, 0, ranges[0].begin); + return {this, 0, ranges[0].begin}; else return end(); } @@ -1530,9 +1526,9 @@ IndexSet::at(const size_type global_index) const // [a,b[ and we will return an iterator pointing directly at global_index // (else branch). if (global_index < p->begin) - return IndexSet::ElementIterator(this, p - ranges.begin(), p->begin); + return {this, static_cast(p - ranges.begin()), p->begin}; else - return IndexSet::ElementIterator(this, p - ranges.begin(), global_index); + return {this, static_cast(p - ranges.begin()), global_index}; } diff --git a/include/deal.II/base/symmetric_tensor.h b/include/deal.II/base/symmetric_tensor.h index f903c4078da6..f16414247234 100644 --- a/include/deal.II/base/symmetric_tensor.h +++ b/include/deal.II/base/symmetric_tensor.h @@ -101,9 +101,9 @@ namespace internal Assert(position < 2, ExcIndexRange(position, 0, 2)); if (position == 0) - return TableIndices<2>(new_index, numbers::invalid_unsigned_int); + return {new_index, numbers::invalid_unsigned_int}; else - return TableIndices<2>(previous_indices[0], new_index); + return {previous_indices[0], new_index}; } @@ -124,28 +124,28 @@ namespace internal switch (position) { case 0: - return TableIndices<4>(new_index, - numbers::invalid_unsigned_int, - numbers::invalid_unsigned_int, - numbers::invalid_unsigned_int); + return {new_index, + numbers::invalid_unsigned_int, + numbers::invalid_unsigned_int, + numbers::invalid_unsigned_int}; case 1: - return TableIndices<4>(previous_indices[0], - new_index, - numbers::invalid_unsigned_int, - numbers::invalid_unsigned_int); + return {previous_indices[0], + new_index, + numbers::invalid_unsigned_int, + numbers::invalid_unsigned_int}; case 2: - return TableIndices<4>(previous_indices[0], - previous_indices[1], - new_index, - numbers::invalid_unsigned_int); + return {previous_indices[0], + previous_indices[1], + new_index, + numbers::invalid_unsigned_int}; case 3: - return TableIndices<4>(previous_indices[0], - previous_indices[1], - previous_indices[2], - new_index); + return {previous_indices[0], + previous_indices[1], + previous_indices[2], + new_index}; } Assert(false, ExcInternalError()); - return TableIndices<4>(); + return {}; } @@ -2463,7 +2463,7 @@ namespace internal { case 1: { - return TableIndices<2>(0, 0); + return {0, 0}; } case 2: @@ -2487,16 +2487,16 @@ namespace internal default: if (i < dim) - return TableIndices<2>(i, i); + return {i, i}; for (unsigned int d = 0, c = 0; d < dim; ++d) for (unsigned int e = d + 1; e < dim; ++e, ++c) if (c == i) - return TableIndices<2>(d, e); + return {d, e}; // should never get here: Assert(false, ExcInternalError()); - return TableIndices<2>(0, 0); + return {0, 0}; } } diff --git a/include/deal.II/fe/fe_values.h b/include/deal.II/fe/fe_values.h index 311cbbd64e12..3e03139485d1 100644 --- a/include/deal.II/fe/fe_values.h +++ b/include/deal.II/fe/fe_values.h @@ -4363,8 +4363,7 @@ namespace FEValuesViews Assert(n < 1, ExcIndexRange(n, 0, 1)); (void)n; - const double array[1] = {t[0]}; - return dealii::SymmetricTensor<2, 1>(array); + return {{t[0]}}; } @@ -4376,18 +4375,16 @@ namespace FEValuesViews { case 0: { - const double array[3] = {t[0], 0, t[1] / 2}; - return dealii::SymmetricTensor<2, 2>(array); + return {{t[0], 0, t[1] / 2}}; } case 1: { - const double array[3] = {0, t[1], t[0] / 2}; - return dealii::SymmetricTensor<2, 2>(array); + return {{0, t[1], t[0] / 2}}; } default: { Assert(false, ExcIndexRange(n, 0, 2)); - return dealii::SymmetricTensor<2, 2>(); + return {}; } } } @@ -4401,23 +4398,20 @@ namespace FEValuesViews { case 0: { - const double array[6] = {t[0], 0, 0, t[1] / 2, t[2] / 2, 0}; - return dealii::SymmetricTensor<2, 3>(array); + return {{t[0], 0, 0, t[1] / 2, t[2] / 2, 0}}; } case 1: { - const double array[6] = {0, t[1], 0, t[0] / 2, 0, t[2] / 2}; - return dealii::SymmetricTensor<2, 3>(array); + return {{0, t[1], 0, t[0] / 2, 0, t[2] / 2}}; } case 2: { - const double array[6] = {0, 0, t[2], 0, t[0] / 2, t[1] / 2}; - return dealii::SymmetricTensor<2, 3>(array); + return {{0, 0, t[2], 0, t[0] / 2, t[1] / 2}}; } default: { Assert(false, ExcIndexRange(n, 0, 3)); - return dealii::SymmetricTensor<2, 3>(); + return {}; } } } diff --git a/include/deal.II/grid/tria_accessor.templates.h b/include/deal.II/grid/tria_accessor.templates.h index 03fa332247bc..bd9bc7b43cd2 100644 --- a/include/deal.II/grid/tria_accessor.templates.h +++ b/include/deal.II/grid/tria_accessor.templates.h @@ -2586,7 +2586,7 @@ template inline RefinementCase<0> TriaAccessor<0, dim, spacedim>::refinement_case() { - return RefinementCase<0>(RefinementPossibilities<0>::no_refinement); + return {RefinementPossibilities<0>::no_refinement}; } @@ -2998,7 +2998,7 @@ template inline RefinementCase<0> TriaAccessor<0, 1, spacedim>::refinement_case() { - return RefinementCase<0>(RefinementPossibilities<0>::no_refinement); + return {RefinementPossibilities<0>::no_refinement}; } template diff --git a/include/deal.II/lac/block_indices.h b/include/deal.II/lac/block_indices.h index 4860a039b9fd..6ada38375a72 100644 --- a/include/deal.II/lac/block_indices.h +++ b/include/deal.II/lac/block_indices.h @@ -337,7 +337,7 @@ BlockIndices::global_to_local(const size_type i) const while (i < start_indices[block]) --block; - return std::pair(block, i - start_indices[block]); + return {block, i - start_indices[block]}; } diff --git a/include/deal.II/lac/chunk_sparsity_pattern.h b/include/deal.II/lac/chunk_sparsity_pattern.h index 261786b52663..4a458f598213 100644 --- a/include/deal.II/lac/chunk_sparsity_pattern.h +++ b/include/deal.II/lac/chunk_sparsity_pattern.h @@ -1105,14 +1105,14 @@ namespace ChunkSparsityPatternIterators inline ChunkSparsityPattern::iterator ChunkSparsityPattern::begin() const { - return iterator(this, 0); + return {this, 0}; } inline ChunkSparsityPattern::iterator ChunkSparsityPattern::end() const { - return iterator(this, n_rows()); + return {this, n_rows()}; } @@ -1121,7 +1121,7 @@ inline ChunkSparsityPattern::iterator ChunkSparsityPattern::begin(const unsigned int r) const { Assert(r < n_rows(), ExcIndexRange(r, 0, n_rows())); - return iterator(this, r); + return {this, r}; } @@ -1129,8 +1129,8 @@ ChunkSparsityPattern::begin(const unsigned int r) const inline ChunkSparsityPattern::iterator ChunkSparsityPattern::end(const unsigned int r) const { - Assert(r < n_rows(), ExcIndexRange(r, 0, n_rows())) return iterator(this, - r + 1); + Assert(r < n_rows(), ExcIndexRange(r, 0, n_rows())); + return {this, r + 1}; } diff --git a/include/deal.II/lac/dynamic_sparsity_pattern.h b/include/deal.II/lac/dynamic_sparsity_pattern.h index 2feb05a52d16..b5f1dd36a1d5 100644 --- a/include/deal.II/lac/dynamic_sparsity_pattern.h +++ b/include/deal.II/lac/dynamic_sparsity_pattern.h @@ -1089,7 +1089,7 @@ DynamicSparsityPattern::begin() const inline DynamicSparsityPattern::iterator DynamicSparsityPattern::end() const { - return iterator(this); + return {this}; } @@ -1100,7 +1100,7 @@ DynamicSparsityPattern::begin(const size_type r) const Assert(r < n_rows(), ExcIndexRangeType(r, 0, n_rows())); if (!have_entries) - return iterator(this); + return {this}; if (rowset.size() > 0) { @@ -1131,7 +1131,7 @@ DynamicSparsityPattern::begin(const size_type r) const if (it == rowset.end()) return end(); else - return iterator(this, *it, 0); + return {this, *it, 0}; } // Without an index set we have to do a linear search starting at @@ -1145,9 +1145,9 @@ DynamicSparsityPattern::begin(const size_type r) const } if (row == n_rows()) - return iterator(this); + return {this}; else - return iterator(this, row, 0); + return {this, row, 0}; } @@ -1159,7 +1159,7 @@ DynamicSparsityPattern::end(const size_type r) const unsigned int row = r + 1; if (row == n_rows()) - return iterator(this); + return {this}; else return begin(row); } diff --git a/include/deal.II/lac/linear_operator.h b/include/deal.II/lac/linear_operator.h index 5278b34ee65b..e066190781cd 100644 --- a/include/deal.II/lac/linear_operator.h +++ b/include/deal.II/lac/linear_operator.h @@ -1022,7 +1022,7 @@ namespace internal inline EmptyPayload operator+(const EmptyPayload &, const EmptyPayload &) { - return EmptyPayload(); + return {}; } /** @@ -1031,7 +1031,7 @@ namespace internal */ inline EmptyPayload operator*(const EmptyPayload &, const EmptyPayload &) { - return EmptyPayload(); + return {}; } diff --git a/include/deal.II/lac/sparsity_pattern.h b/include/deal.II/lac/sparsity_pattern.h index 3f58fe141358..4182a1fd7349 100644 --- a/include/deal.II/lac/sparsity_pattern.h +++ b/include/deal.II/lac/sparsity_pattern.h @@ -1254,7 +1254,7 @@ inline SparsityPattern::iterator SparsityPattern::begin() const { if (n_rows() > 0) - return iterator(this, rowstart[0]); + return {this, rowstart[0]}; else return end(); } @@ -1265,9 +1265,9 @@ inline SparsityPattern::iterator SparsityPattern::end() const { if (n_rows() > 0) - return iterator(this, rowstart[rows]); + return {this, rowstart[rows]}; else - return iterator(nullptr, 0); + return {nullptr, 0}; } @@ -1277,7 +1277,7 @@ SparsityPattern::begin(const size_type r) const { Assert(r < n_rows(), ExcIndexRangeType(r, 0, n_rows())); - return iterator(this, rowstart[r]); + return {this, rowstart[r]}; } @@ -1287,7 +1287,7 @@ SparsityPattern::end(const size_type r) const { Assert(r < n_rows(), ExcIndexRangeType(r, 0, n_rows())); - return iterator(this, rowstart[r + 1]); + return {this, rowstart[r + 1]}; } diff --git a/include/deal.II/lac/trilinos_sparse_matrix.h b/include/deal.II/lac/trilinos_sparse_matrix.h index ed9f193523f5..25478951f673 100644 --- a/include/deal.II/lac/trilinos_sparse_matrix.h +++ b/include/deal.II/lac/trilinos_sparse_matrix.h @@ -2745,7 +2745,7 @@ namespace TrilinosWrappers Accessor::value() const { Assert(a_row < matrix->m(), ExcBeyondEndOfMatrix()); - return Reference(*this); + return {*this}; } diff --git a/include/deal.II/matrix_free/matrix_free.h b/include/deal.II/matrix_free/matrix_free.h index d38ed5055f00..15a1e5e32dc7 100644 --- a/include/deal.II/matrix_free/matrix_free.h +++ b/include/deal.II/matrix_free/matrix_free.h @@ -2032,14 +2032,13 @@ MatrixFree::create_cell_subrange_hp( if (dof_info[dof_handler_component].fe_index_conversion[0][0] == degree) return range; else - return std::pair(range.second, - range.second); + return {range.second, range.second}; } const unsigned int fe_index = dof_info[dof_handler_component].fe_index_from_degree(0, degree); if (fe_index >= dof_info[dof_handler_component].max_fe_index) - return std::pair(range.second, range.second); + return {range.second, range.second}; else return create_cell_subrange_hp_by_index(range, fe_index, diff --git a/source/base/data_out_base.cc b/source/base/data_out_base.cc index 998382526004..65336ef19154 100644 --- a/source/base/data_out_base.cc +++ b/source/base/data_out_base.cc @@ -7630,7 +7630,7 @@ DataOutInterface::create_xdmf_entry( } else { - return XDMFEntry(); + return {}; } } diff --git a/source/base/function_lib.cc b/source/base/function_lib.cc index 891cf67524d3..5ec40c443112 100644 --- a/source/base/function_lib.cc +++ b/source/base/function_lib.cc @@ -1435,7 +1435,7 @@ namespace Functions const unsigned int /*component*/) const { Assert(false, ExcNotImplemented()); - return Tensor<1, 2>(); + return {}; } diff --git a/source/base/hdf5.cc b/source/base/hdf5.cc index 2e4f3c02de5f..d8fe0dca80c1 100644 --- a/source/base/hdf5.cc +++ b/source/base/hdf5.cc @@ -1313,7 +1313,7 @@ namespace HDF5 Group Group::open_group(const std::string &name) const { - return Group(name, *this, mpi, GroupAccessMode::open); + return {name, *this, mpi, GroupAccessMode::open}; } @@ -1321,7 +1321,7 @@ namespace HDF5 Group Group::create_group(const std::string &name) const { - return Group(name, *this, mpi, GroupAccessMode::create); + return {name, *this, mpi, GroupAccessMode::create}; } @@ -1329,7 +1329,7 @@ namespace HDF5 DataSet Group::open_dataset(const std::string &name) const { - return DataSet(name, *hdf5_reference, mpi); + return {name, *hdf5_reference, mpi}; } @@ -1340,7 +1340,7 @@ namespace HDF5 const std::vector &dimensions) const { std::shared_ptr t_type = internal::get_hdf5_datatype(); - return DataSet(name, *hdf5_reference, dimensions, t_type, mpi); + return {name, *hdf5_reference, dimensions, t_type, mpi}; } diff --git a/source/dofs/dof_handler_policy.cc b/source/dofs/dof_handler_policy.cc index bdb9b68d537b..aa9b53c70372 100644 --- a/source/dofs/dof_handler_policy.cc +++ b/source/dofs/dof_handler_policy.cc @@ -4206,7 +4206,7 @@ namespace internal // multigrid is not currently implemented for shared triangulations Assert(false, ExcNotImplemented()); - return NumberCache(); + return {}; } diff --git a/source/fe/fe.cc b/source/fe/fe.cc index a45d0b0fd377..861777b58402 100644 --- a/source/fe/fe.cc +++ b/source/fe/fe.cc @@ -446,7 +446,7 @@ FiniteElement::component_mask(const BlockMask &block_mask) const // if we get a block mask that represents all blocks, then // do the same for the returned component mask if (block_mask.represents_the_all_selected_mask()) - return ComponentMask(); + return {}; AssertDimension(block_mask.size(), this->n_blocks()); @@ -502,7 +502,7 @@ FiniteElement::block_mask( // if we get a component mask that represents all component, then // do the same for the returned block mask if (component_mask.represents_the_all_selected_mask()) - return BlockMask(); + return {}; AssertDimension(component_mask.size(), this->n_components()); @@ -859,20 +859,18 @@ FiniteElement::interface_constraints_size() const switch (dim) { case 1: - return TableIndices<2>(0U, 0U); + return {0U, 0U}; case 2: - return TableIndices<2>(this->dofs_per_vertex + 2 * this->dofs_per_line, - this->dofs_per_face); + return {this->dofs_per_vertex + 2 * this->dofs_per_line, + this->dofs_per_face}; case 3: - return TableIndices<2>(5 * this->dofs_per_vertex + - 12 * this->dofs_per_line + - 4 * this->dofs_per_quad, - this->dofs_per_face); + return {5 * this->dofs_per_vertex + 12 * this->dofs_per_line + + 4 * this->dofs_per_quad, + this->dofs_per_face}; default: Assert(false, ExcNotImplemented()); } - return TableIndices<2>(numbers::invalid_unsigned_int, - numbers::invalid_unsigned_int); + return {numbers::invalid_unsigned_int, numbers::invalid_unsigned_int}; } diff --git a/source/fe/mapping_q_generic.cc b/source/fe/mapping_q_generic.cc index 44400569ddce..4dfaf968dc6c 100644 --- a/source/fe/mapping_q_generic.cc +++ b/source/fe/mapping_q_generic.cc @@ -174,7 +174,7 @@ namespace internal if (std::abs(xi_denominator0) > 1e-10 * max_x) { const double xi = (x + subexpr0) / xi_denominator0; - return Point<2>(xi, eta); + return {xi, static_cast(eta)}; } else { @@ -187,7 +187,7 @@ namespace internal if (std::abs(xi_denominator1) > 1e-10 * max_y) { const double xi = (subexpr1 + y) / xi_denominator1; - return Point<2>(xi, eta); + return {xi, static_cast(eta)}; } else // give up and try Newton iteration { @@ -200,8 +200,8 @@ namespace internal // bogus return to placate compiler. It should not be possible to get // here. Assert(false, ExcInternalError()); - return Point<2>(std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN()); + return {std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()}; } @@ -2517,7 +2517,7 @@ MappingQGeneric<1, 3>::transform_real_to_unit_cell_internal( const Point<1> &) const { Assert(false, ExcNotImplemented()); - return Point<1>(); + return {}; } diff --git a/source/grid/grid_tools.cc b/source/grid/grid_tools.cc index 2b50ee5f4056..201dfe03f9ee 100644 --- a/source/grid/grid_tools.cc +++ b/source/grid/grid_tools.cc @@ -815,8 +815,8 @@ namespace GridTools Point<2> operator()(const Point<2> &p) const { - return Point<2>(std::cos(angle) * p(0) - std::sin(angle) * p(1), - std::sin(angle) * p(0) + std::cos(angle) * p(1)); + return {std::cos(angle) * p(0) - std::sin(angle) * p(1), + std::sin(angle) * p(0) + std::cos(angle) * p(1)}; } private: @@ -836,17 +836,17 @@ namespace GridTools operator()(const Point<3> &p) const { if (axis == 0) - return Point<3>(p(0), - std::cos(angle) * p(1) - std::sin(angle) * p(2), - std::sin(angle) * p(1) + std::cos(angle) * p(2)); + return {p(0), + std::cos(angle) * p(1) - std::sin(angle) * p(2), + std::sin(angle) * p(1) + std::cos(angle) * p(2)}; else if (axis == 1) - return Point<3>(std::cos(angle) * p(0) + std::sin(angle) * p(2), - p(1), - -std::sin(angle) * p(0) + std::cos(angle) * p(2)); + return {std::cos(angle) * p(0) + std::sin(angle) * p(2), + p(1), + -std::sin(angle) * p(0) + std::cos(angle) * p(2)}; else - return Point<3>(std::cos(angle) * p(0) - std::sin(angle) * p(1), - std::sin(angle) * p(0) + std::cos(angle) * p(1), - p(2)); + return {std::cos(angle) * p(0) - std::sin(angle) * p(1), + std::sin(angle) * p(0) + std::cos(angle) * p(1), + p(2)}; } private: diff --git a/source/grid/manifold.cc b/source/grid/manifold.cc index 35d213df01a3..e668286c4a2e 100644 --- a/source/grid/manifold.cc +++ b/source/grid/manifold.cc @@ -379,7 +379,7 @@ Manifold<1, 1>::get_new_point_on_face( const Triangulation<1, 1>::face_iterator &) const { Assert(false, ExcImpossibleInDim(1)); - return Point<1>(); + return {}; } @@ -390,7 +390,7 @@ Manifold<1, 2>::get_new_point_on_face( const Triangulation<1, 2>::face_iterator &) const { Assert(false, ExcImpossibleInDim(1)); - return Point<2>(); + return {}; } @@ -401,7 +401,7 @@ Manifold<1, 3>::get_new_point_on_face( const Triangulation<1, 3>::face_iterator &) const { Assert(false, ExcImpossibleInDim(1)); - return Point<3>(); + return {}; } @@ -412,7 +412,7 @@ Manifold<1, 1>::get_new_point_on_quad( const Triangulation<1, 1>::quad_iterator &) const { Assert(false, ExcImpossibleInDim(1)); - return Point<1>(); + return {}; } @@ -423,7 +423,7 @@ Manifold<1, 2>::get_new_point_on_quad( const Triangulation<1, 2>::quad_iterator &) const { Assert(false, ExcImpossibleInDim(1)); - return Point<2>(); + return {}; } @@ -434,7 +434,7 @@ Manifold<1, 3>::get_new_point_on_quad( const Triangulation<1, 3>::quad_iterator &) const { Assert(false, ExcImpossibleInDim(1)); - return Point<3>(); + return {}; } @@ -492,7 +492,7 @@ namespace internal // the implementation below is bogus for this case anyway // (see the assert at the beginning of that function). Assert(false, ExcNotImplemented()); - return Tensor<1, 3>(); + return {}; } @@ -808,7 +808,7 @@ FlatManifold<1, 1>::normal_vector(const Triangulation<1, 1>::face_iterator &, const Point<1> &) const { Assert(false, ExcNotImplemented()); - return Tensor<1, 1>(); + return {}; } @@ -819,7 +819,7 @@ FlatManifold<1, 2>::normal_vector(const Triangulation<1, 2>::face_iterator &, const Point<2> &) const { Assert(false, ExcNotImplemented()); - return Tensor<1, 2>(); + return {}; } @@ -830,7 +830,7 @@ FlatManifold<1, 3>::normal_vector(const Triangulation<1, 3>::face_iterator &, const Point<3> &) const { Assert(false, ExcNotImplemented()); - return Tensor<1, 3>(); + return {}; } diff --git a/source/grid/manifold_lib.cc b/source/grid/manifold_lib.cc index c13d73f40537..4dd1c9a31d05 100644 --- a/source/grid/manifold_lib.cc +++ b/source/grid/manifold_lib.cc @@ -1268,7 +1268,7 @@ EllipticalManifold<2, 2>::pull_back(const Point<2> &space_point) const } const double eta = std::acos(cos_eta); const double pt1 = (std::signbit(y) ? 2.0 * numbers::PI - eta : eta); - return Point<2>(pt0, pt1); + return {pt0, pt1}; } @@ -1279,7 +1279,7 @@ EllipticalManifold::push_forward_gradient( const Point &) const { Assert(false, ExcNotImplemented()); - return DerivativeForm<1, spacedim, spacedim>(); + return {}; } @@ -1481,7 +1481,7 @@ TorusManifold::pull_back(const Point<3> &p) const double w = std::sqrt(std::pow(y - std::sin(phi) * R, 2.0) + std::pow(x - std::cos(phi) * R, 2.0) + z * z) / r; - return Point<3>(phi, theta, w); + return {phi, theta, w}; } @@ -1494,9 +1494,9 @@ TorusManifold::push_forward(const Point<3> &chart_point) const double theta = chart_point(1); double w = chart_point(2); - return Point<3>(std::cos(phi) * R + r * w * std::cos(theta) * std::cos(phi), - r * w * std::sin(theta), - std::sin(phi) * R + r * w * std::cos(theta) * std::sin(phi)); + return {std::cos(phi) * R + r * w * std::cos(theta) * std::cos(phi), + r * w * std::sin(theta), + std::sin(phi) * R + r * w * std::cos(theta) * std::sin(phi)}; } diff --git a/source/grid/tria_accessor.cc b/source/grid/tria_accessor.cc index 4e62fde8deb4..c7a1bfdee33c 100644 --- a/source/grid/tria_accessor.cc +++ b/source/grid/tria_accessor.cc @@ -210,7 +210,7 @@ namespace t9 * y[1] - t11 * y[0] + x[0] * t53 - t59 * x[2] + t59 * x[1] - t39 * x[0]; - return Point<2>(t27 * t37 / 3, t63 * t37 / 3); + return {t27 * t37 / 3, t63 * t37 / 3}; } @@ -1233,7 +1233,7 @@ namespace s2 = s3 * s4; const double unknown2 = s1 * s2; - return Point<3>(unknown0, unknown1, unknown2); + return {unknown0, unknown1, unknown2}; } @@ -2218,7 +2218,7 @@ CellAccessor::id() const Assert(ptr.level() == 0, ExcInternalError()); const unsigned int coarse_index = ptr.index(); - return CellId(coarse_index, n_child_indices, id.data()); + return {coarse_index, n_child_indices, id.data()}; } diff --git a/source/opencascade/manifold_lib.cc b/source/opencascade/manifold_lib.cc index c872b0d2fcbe..209043ef6b8a 100644 --- a/source/opencascade/manifold_lib.cc +++ b/source/opencascade/manifold_lib.cc @@ -404,7 +404,7 @@ namespace OpenCASCADE double u = proj_params.X(); double v = proj_params.Y(); - return Point<2>(u, v); + return {u, v}; } template From 24f226f508f08d459e4c9946d97f9f2cb87df7f9 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 29 Jan 2019 10:57:27 +0100 Subject: [PATCH 023/507] modernize-use-equals-default --- include/deal.II/grid/filtered_iterator.h | 13 ------------- include/deal.II/lac/dynamic_sparsity_pattern.h | 8 +------- include/deal.II/matrix_free/matrix_free.h | 2 +- 3 files changed, 2 insertions(+), 21 deletions(-) diff --git a/include/deal.II/grid/filtered_iterator.h b/include/deal.II/grid/filtered_iterator.h index c7b6b8e771e4..88f47c7a3bfb 100644 --- a/include/deal.II/grid/filtered_iterator.h +++ b/include/deal.II/grid/filtered_iterator.h @@ -567,11 +567,6 @@ class FilteredIterator : public BaseIterator */ FilteredIterator(const FilteredIterator &fi); - /** - * Destructor. - */ - ~FilteredIterator(); - /** * Assignment operator. Copy the iterator value of the argument, but as * discussed in the class documentation, the predicate of the argument is @@ -966,14 +961,6 @@ inline FilteredIterator::FilteredIterator( -template -inline FilteredIterator::~FilteredIterator() -{ - predicate.reset(); -} - - - template inline FilteredIterator & FilteredIterator::operator=(const FilteredIterator &fi) diff --git a/include/deal.II/lac/dynamic_sparsity_pattern.h b/include/deal.II/lac/dynamic_sparsity_pattern.h index b5f1dd36a1d5..ed2a200179cc 100644 --- a/include/deal.II/lac/dynamic_sparsity_pattern.h +++ b/include/deal.II/lac/dynamic_sparsity_pattern.h @@ -210,7 +210,7 @@ namespace DynamicSparsityPatternIterators * here only to be able to store iterators in STL containers such as * `std::vector`. */ - Iterator(); + Iterator() = default; /** * Prefix increment. @@ -886,12 +886,6 @@ namespace DynamicSparsityPatternIterators - inline Iterator::Iterator() - : accessor() - {} - - - inline Iterator & Iterator::operator++() { diff --git a/include/deal.II/matrix_free/matrix_free.h b/include/deal.II/matrix_free/matrix_free.h index 15a1e5e32dc7..a0134ebfe76d 100644 --- a/include/deal.II/matrix_free/matrix_free.h +++ b/include/deal.II/matrix_free/matrix_free.h @@ -2666,7 +2666,7 @@ namespace internal 3); } - ~VectorDataExchange() + ~VectorDataExchange() // NOLINT { # ifdef DEAL_II_WITH_MPI for (unsigned int i = 0; i < tmp_data.size(); ++i) From 551145b514900669ab799dc17a4f9ae23e31d377 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 29 Jan 2019 10:58:02 +0100 Subject: [PATCH 024/507] modernize-use-nullptr --- include/deal.II/numerics/error_estimator.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/deal.II/numerics/error_estimator.h b/include/deal.II/numerics/error_estimator.h index ecb9786ffef4..a9b3fa4a6087 100644 --- a/include/deal.II/numerics/error_estimator.h +++ b/include/deal.II/numerics/error_estimator.h @@ -398,7 +398,7 @@ class KellyErrorEstimator const std::vector &solutions, std::vector *> & errors, const ComponentMask & component_mask = ComponentMask(), - const Function * coefficients = 0, + const Function * coefficients = nullptr, const unsigned int n_threads = numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id = numbers::invalid_subdomain_id, const types::material_id material_id = numbers::invalid_material_id, @@ -419,7 +419,7 @@ class KellyErrorEstimator const std::vector &solutions, std::vector *> & errors, const ComponentMask & component_mask = ComponentMask(), - const Function * coefficients = 0, + const Function * coefficients = nullptr, const unsigned int n_threads = numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id = numbers::invalid_subdomain_id, const types::material_id material_id = numbers::invalid_material_id, @@ -442,7 +442,7 @@ class KellyErrorEstimator const InputVector & solution, Vector & error, const ComponentMask & component_mask = ComponentMask(), - const Function *coefficients = 0, + const Function *coefficients = nullptr, const unsigned int n_threads = numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id = numbers::invalid_subdomain_id, const types::material_id material_id = numbers::invalid_material_id, @@ -487,7 +487,7 @@ class KellyErrorEstimator const std::vector &solutions, std::vector *> & errors, const ComponentMask & component_mask = ComponentMask(), - const Function * coefficients = 0, + const Function * coefficients = nullptr, const unsigned int n_threads = numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id = numbers::invalid_subdomain_id, const types::material_id material_id = numbers::invalid_material_id, @@ -686,7 +686,7 @@ class KellyErrorEstimator<1, spacedim> const std::vector &solutions, std::vector *> & errors, const ComponentMask & component_mask = ComponentMask(), - const Function * coefficients = 0, + const Function * coefficients = nullptr, const unsigned int n_threads = numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id = numbers::invalid_subdomain_id, const types::material_id material_id = numbers::invalid_material_id, @@ -707,7 +707,7 @@ class KellyErrorEstimator<1, spacedim> const std::vector &solutions, std::vector *> & errors, const ComponentMask & component_mask = ComponentMask(), - const Function * coefficients = 0, + const Function * coefficients = nullptr, const unsigned int n_threads = numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id = numbers::invalid_subdomain_id, const types::material_id material_id = numbers::invalid_material_id, @@ -730,7 +730,7 @@ class KellyErrorEstimator<1, spacedim> const InputVector & solution, Vector & error, const ComponentMask & component_mask = ComponentMask(), - const Function *coefficients = 0, + const Function *coefficients = nullptr, const unsigned int n_threads = numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id = numbers::invalid_subdomain_id, const types::material_id material_id = numbers::invalid_material_id, @@ -752,7 +752,7 @@ class KellyErrorEstimator<1, spacedim> const InputVector & solution, Vector & error, const ComponentMask & component_mask = ComponentMask(), - const Function *coefficients = 0, + const Function *coefficients = nullptr, const unsigned int n_threads = numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id = numbers::invalid_subdomain_id, const types::material_id material_id = numbers::invalid_material_id, @@ -775,7 +775,7 @@ class KellyErrorEstimator<1, spacedim> const std::vector &solutions, std::vector *> & errors, const ComponentMask & component_mask = ComponentMask(), - const Function * coefficients = 0, + const Function * coefficients = nullptr, const unsigned int n_threads = numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id = numbers::invalid_subdomain_id, const types::material_id material_id = numbers::invalid_material_id, @@ -797,7 +797,7 @@ class KellyErrorEstimator<1, spacedim> const std::vector &solutions, std::vector *> & errors, const ComponentMask & component_mask = ComponentMask(), - const Function * coefficients = 0, + const Function * coefficients = nullptr, const unsigned int n_threads = numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id = numbers::invalid_subdomain_id, const types::material_id material_id = numbers::invalid_material_id, From 723f41aa2dd617dad4529463225c400cd2075bce Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 29 Jan 2019 10:59:11 +0100 Subject: [PATCH 025/507] performance-unnecessary-value-param --- source/base/hdf5.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/source/base/hdf5.cc b/source/base/hdf5.cc index d8fe0dca80c1..b8c958679012 100644 --- a/source/base/hdf5.cc +++ b/source/base/hdf5.cc @@ -518,16 +518,12 @@ namespace HDF5 template <> void HDF5Object::set_attribute(const std::string &attr_name, - const std::string value) + const std::string value) // NOLINT { // Writes a UTF8 variable string // // code inspired from // https://support.hdfgroup.org/ftp/HDF5/examples/misc-examples/vlstratt.c - // - // In the case of a variable length string, H5Awrite needs the address of a - // (char *). For this reason the std::string value has been copied to a C - // string. hid_t attr; hid_t aid; From 4975f4b31816fcd423d714df84f83977fb7a2015 Mon Sep 17 00:00:00 2001 From: Giovanni Alzetta Date: Wed, 9 Jan 2019 22:13:56 +0100 Subject: [PATCH 026/507] Added covering rtree and flag to GridTools::Cache --- .../changes/minor/20190111GiovanniAlzetta | 5 + include/deal.II/grid/grid_tools_cache.h | 33 + .../grid/grid_tools_cache_update_flags.h | 12 + source/grid/grid_tools_cache.cc | 41 + tests/grid/grid_tools_cache_04.cc | 120 ++ ...h_mpi=true.with_p4est=true.mpirun=1.output | 238 ++++ ...h_mpi=true.with_p4est=true.mpirun=4.output | 1007 +++++++++++++++++ 7 files changed, 1456 insertions(+) create mode 100644 doc/news/changes/minor/20190111GiovanniAlzetta create mode 100644 tests/grid/grid_tools_cache_04.cc create mode 100644 tests/grid/grid_tools_cache_04.with_mpi=true.with_p4est=true.mpirun=1.output create mode 100644 tests/grid/grid_tools_cache_04.with_mpi=true.with_p4est=true.mpirun=4.output 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/include/deal.II/grid/grid_tools_cache.h b/include/deal.II/grid/grid_tools_cache.h index ddbfc8444d1e..e348103f6dbd 100644 --- a/include/deal.II/grid/grid_tools_cache.h +++ b/include/deal.II/grid/grid_tools_cache.h @@ -150,6 +150,33 @@ namespace GridTools const Mapping & get_mapping() const; + + /** + * This function returns an object that allows identifying + * which process(es) in a parallel computation may own the + * cell that surrounds a given point. The elements of this + * object -- an Rtree -- are pairs of bounding boxes denoting + * areas that cover all or parts of the local portion of a + * parallel triangulation, and an unsigned int representing + * the process or subdomain that owns these cells. + * Given a point on a parallel::Triangulation, this tree + * allows to identify one, or few candidate processes, for + * which the point lies on a locally owned cell. + * + * Constructing or updating the rtree requires a call to + * GridTools::build_global_description_tree(), which exchanges + * bounding boxes between all processes using + * Utilities::MPI::all_gather(), a collective operation. + * Therefore this function must be called by all processes + * at the same time. + * + * While each box may only cover part of a process's locally + * owned part of the triangulation, the boxes associated with + * each process jointly cover the entire local portion. + */ + const RTree, unsigned int>> & + get_covering_rtree() const; + #ifdef DEAL_II_WITH_NANOFLANN /** * Return the cached vertex_kdtree object, constructed with the vertices of @@ -191,6 +218,12 @@ namespace GridTools mutable std::vector>> vertex_to_cell_centers; + /** + * An rtree object covering the whole mesh. + */ + mutable RTree, unsigned int>> + covering_rtree; + #ifdef DEAL_II_WITH_NANOFLANN /** * A KDTree object constructed with the vertices of the triangulation. diff --git a/include/deal.II/grid/grid_tools_cache_update_flags.h b/include/deal.II/grid/grid_tools_cache_update_flags.h index a119af38ab97..9ae073b7d17f 100644 --- a/include/deal.II/grid/grid_tools_cache_update_flags.h +++ b/include/deal.II/grid/grid_tools_cache_update_flags.h @@ -73,6 +73,16 @@ namespace GridTools */ update_cell_bounding_boxes_rtree = 0x020, + /** + * Update the covering rtree object, initialized with pairs + * of a bounding box and an unsigned int. The bounding + * boxes are used to describe approximately which portion + * of the mesh contains locally owned cells by the + * process of rank the second element of the pair. + * + */ + update_covering_rtree = 0x040, + /** * Update all objects. */ @@ -94,6 +104,8 @@ namespace GridTools s << "|vertex_to_cell_map"; if (u & update_vertex_to_cell_centers_directions) s << "|vertex_to_cells_centers_directions"; + if (u & update_covering_rtree) + s << "|covering_rtree"; #ifdef DEAL_II_WITH_NANOFLANN if (u & update_vertex_kdtree) s << "|vertex_kdtree"; diff --git a/source/grid/grid_tools_cache.cc b/source/grid/grid_tools_cache.cc index 96219c99966f..6c8b6af8a195 100644 --- a/source/grid/grid_tools_cache.cc +++ b/source/grid/grid_tools_cache.cc @@ -13,9 +13,15 @@ // // --------------------------------------------------------------------- +#include +#include + +#include #include #include +#include + DEAL_II_NAMESPACE_OPEN namespace GridTools @@ -146,6 +152,41 @@ namespace GridTools } return vertex_kdtree; } + + + + template + const RTree, unsigned int>> & + Cache::get_covering_rtree() const + { + if (update_flags & update_covering_rtree) + { + // TO DO: the locally owned portion of the domain + // might consists of more separate pieces: a single + // bounding box might not always be the best choice. + IteratorFilters::LocallyOwnedCell locally_owned_cell_predicate; + const BoundingBox bbox = + GridTools::compute_bounding_box(*tria, locally_owned_cell_predicate); + + + std::vector> bbox_v(1, bbox); + if (const auto tria_mpi = + dynamic_cast *>( + &(*tria))) + { + covering_rtree = GridTools::build_global_description_tree( + bbox_v, tria_mpi->get_communicator()); + } + else + { + covering_rtree = + GridTools::build_global_description_tree(bbox_v, MPI_COMM_SELF); + } + update_flags = update_flags & ~update_covering_rtree; + } + + return covering_rtree; + } #endif #include "grid_tools_cache.inst" diff --git a/tests/grid/grid_tools_cache_04.cc b/tests/grid/grid_tools_cache_04.cc new file mode 100644 index 000000000000..42116eca171f --- /dev/null +++ b/tests/grid/grid_tools_cache_04.cc @@ -0,0 +1,120 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2001 - 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. +// +// --------------------------------------------------------------------- + +// Validate grid_tools_cache for the creation of build global rtree + + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../tests.h" + +using namespace dealii; + +namespace bg = boost::geometry; +namespace bgi = boost::geometry::index; + + +template +void +test(unsigned int n_points) +{ + deallog << "Testing for dim = " << dim << std::endl; + + // Creating a grid in the square [0,1]x[0,1] + parallel::shared::Triangulation tria(MPI_COMM_WORLD); + GridGenerator::hyper_cube(tria); + tria.refine_global(std::max(8 - dim, 3)); + + + GridTools::Cache cache(tria); + + const auto &global_description = cache.get_covering_rtree(); + + // Creating the random points + std::vector> points; + + for (size_t i = 0; i < n_points; ++i) + points.push_back(random_point()); + + + + const auto cell_qpoint_map = + GridTools::compute_point_locations(cache, points); + const auto & cells = std::get<0>(cell_qpoint_map); + const auto & maps = std::get<2>(cell_qpoint_map); + unsigned int n_cells = cells.size(); + + for (unsigned int c = 0; c < n_cells; ++c) + { + // We know the owner as we're working on a shared triangulation + unsigned int cell_owner = cells[c]->subdomain_id(); + for (unsigned int idx : maps[c]) + { + std::vector, unsigned int>> test_results; + global_description.query(bgi::intersects(points[idx]), + std::back_inserter(test_results)); + bool found = false; + + // Printing and checking function output + for (const auto &ans : test_results) + { + const auto &bd_points = ans.first.get_boundary_points(); + deallog << "Bounding box: p1 " << bd_points.first << " p2 " + << bd_points.second << " rank owner: " << ans.second + << std::endl; + // Check if the guess made from the tree contains the answer + if (ans.second == cell_owner) + found = true; + } + + if (!found) + deallog << "Error point " << points[idx] << " was not found." + << std::endl; + } + } + deallog << "Test for dim " << dim << " finished." << std::endl; +} + + + +int +main(int argc, char **argv) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); +#ifdef DEAL_II_WITH_MPI + MPILogInitAll log; +#else + initlog(); + deallog.push("0"); +#endif + + test<1>(50); + test<2>(80); + test<3>(101); + + return 0; +} diff --git a/tests/grid/grid_tools_cache_04.with_mpi=true.with_p4est=true.mpirun=1.output b/tests/grid/grid_tools_cache_04.with_mpi=true.with_p4est=true.mpirun=1.output new file mode 100644 index 000000000000..2c5df042b4d6 --- /dev/null +++ b/tests/grid/grid_tools_cache_04.with_mpi=true.with_p4est=true.mpirun=1.output @@ -0,0 +1,238 @@ + +DEAL:0::Testing for dim = 1 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 1.00000 rank owner: 0 +DEAL:0::Test for dim 1 finished. +DEAL:0::Testing for dim = 2 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 1.00000 1.00000 rank owner: 0 +DEAL:0::Test for dim 2 finished. +DEAL:0::Testing for dim = 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 0 +DEAL:0::Test for dim 3 finished. diff --git a/tests/grid/grid_tools_cache_04.with_mpi=true.with_p4est=true.mpirun=4.output b/tests/grid/grid_tools_cache_04.with_mpi=true.with_p4est=true.mpirun=4.output new file mode 100644 index 000000000000..6f484f4f926c --- /dev/null +++ b/tests/grid/grid_tools_cache_04.with_mpi=true.with_p4est=true.mpirun=4.output @@ -0,0 +1,1007 @@ + +DEAL:0::Testing for dim = 1 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:0::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:0::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:0::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:0::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:0::Test for dim 1 finished. +DEAL:0::Testing for dim = 2 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:0::Test for dim 2 finished. +DEAL:0::Testing for dim = 3 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:0::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:0::Test for dim 3 finished. + +DEAL:1::Testing for dim = 1 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:1::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:1::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:1::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:1::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:1::Test for dim 1 finished. +DEAL:1::Testing for dim = 2 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:1::Test for dim 2 finished. +DEAL:1::Testing for dim = 3 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:1::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:1::Test for dim 3 finished. + + +DEAL:2::Testing for dim = 1 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:2::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:2::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:2::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:2::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:2::Test for dim 1 finished. +DEAL:2::Testing for dim = 2 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:2::Test for dim 2 finished. +DEAL:2::Testing for dim = 3 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:2::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:2::Test for dim 3 finished. + + +DEAL:3::Testing for dim = 1 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:3::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:3::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:3::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:3::Bounding box: p1 0.531250 p2 0.765625 rank owner: 3 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.257812 p2 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.765625 p2 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 p2 0.257812 rank owner: 1 +DEAL:3::Test for dim 1 finished. +DEAL:3::Testing for dim = 2 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.00000 p2 0.515625 0.531250 rank owner: 0 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.421875 0.531250 p2 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.531250 p2 0.421875 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.515625 0.00000 p2 1.00000 0.531250 rank owner: 1 +DEAL:3::Test for dim 2 finished. +DEAL:3::Testing for dim = 3 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.468750 0.00000 0.00000 p2 1.00000 0.531250 1.00000 rank owner: 3 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.00000 0.00000 p2 0.562500 0.531250 1.00000 rank owner: 1 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Bounding box: p1 0.531250 0.531250 0.00000 p2 1.00000 1.00000 1.00000 rank owner: 2 +DEAL:3::Bounding box: p1 0.00000 0.468750 0.00000 p2 0.562500 1.00000 1.00000 rank owner: 0 +DEAL:3::Test for dim 3 finished. + From d716983f2a91177d5a2364ec6ba5d8c1c8b25175 Mon Sep 17 00:00:00 2001 From: David Wells Date: Sun, 20 Jan 2019 22:32:32 -0500 Subject: [PATCH 027/507] Use AlignedVector to manage Vector's memory. Vector already requires that the underlying buffer be aligned and uses exactly the same function (posix_memalign) as AlignedVector to do it: we can simplify the implementation of Vector a lot by just using an AlignedVector to manage the data instead. --- include/deal.II/lac/vector.h | 102 ++----- include/deal.II/lac/vector.templates.h | 383 +++++++++---------------- tests/serialization/vector.output | 4 +- 3 files changed, 165 insertions(+), 324 deletions(-) diff --git a/include/deal.II/lac/vector.h b/include/deal.II/lac/vector.h index d44d28ee3b27..2dadf1da5e10 100644 --- a/include/deal.II/lac/vector.h +++ b/include/deal.II/lac/vector.h @@ -19,6 +19,7 @@ #include +#include #include #include #include @@ -29,14 +30,6 @@ #include #include -// boost::serialization::make_array used to be in array.hpp, but was -// moved to a different file in BOOST 1.64 -#include -#if BOOST_VERSION >= 106400 -# include -#else -# include -#endif #include #include @@ -152,6 +145,8 @@ class Vector : public Subscriptor * * We would like to make this constructor explicit, but standard containers * insist on using it implicitly. + * + * @dealiiOperationIsMultithreaded */ Vector(const Vector &v); @@ -159,19 +154,13 @@ class Vector : public Subscriptor * Move constructor. Creates a new vector by stealing the internal data of * the vector @p v. */ - Vector(Vector &&v) noexcept; + Vector(Vector &&v) noexcept = default; /** * Copy constructor taking a vector of another data type. This will fail if * there is no conversion path from @p OtherNumber to @p Number. Note that * you may lose accuracy when copying to a vector with data elements with * less accuracy. - * - * Older versions of gcc did not honor the @p explicit keyword on template - * constructors. In such cases, it is easy to accidentally write code that - * can be very inefficient, since the compiler starts performing hidden - * conversions. To avoid this, this function is disabled if we have detected - * a broken compiler during configuration. */ template explicit Vector(const Vector &v); @@ -365,7 +354,7 @@ class Vector : public Subscriptor * have after being newly default-constructed. */ Vector & - operator=(Vector &&v) noexcept; + operator=(Vector &&v) noexcept = default; /** * Copy the given vector. Resize the present vector if necessary. @@ -993,27 +982,9 @@ class Vector : public Subscriptor private: /** - * Dimension. Actual number of components contained in the vector. Get this - * number by calling size(). - */ - size_type vec_size; - - /** - * Amount of memory actually reserved for this vector. This number may be - * greater than @p vec_size if a @p reinit was called with less memory - * requirements than the vector needed last time. At present @p reinit does - * not free memory when the number of needed elements is reduced. - */ - size_type max_vec_size; - - /** - * Pointer to the array of elements of this vector. - * - * Because we allocate these arrays via Utilities::System::posix_memalign, - * we need to use a custom deleter for this object that does not call - * delete[], but instead calls @p free(). + * Array of elements owned by this vector. */ - std::unique_ptr values; + AlignedVector values; /** * For parallel loops with TBB, this member variable stores the affinity @@ -1022,25 +993,11 @@ class Vector : public Subscriptor mutable std::shared_ptr thread_loop_partitioner; - /** - * Allocate and align @p values along 64-byte boundaries. The size of the - * allocated memory is determined by @p max_vec_size . Copy first - * @p copy_n_el from the old values. - */ - void - allocate(const size_type copy_n_el = 0); - /** * Make all other vector types friends. */ template friend class Vector; - - /** - * LAPACK matrices need access to the data. - */ - template - friend class LAPACKFullMatrix; }; /*@}*/ @@ -1060,9 +1017,6 @@ Vector::lp_norm(const real_type) const; template inline Vector::Vector() - : vec_size(0) - , max_vec_size(0) - , values(nullptr, &free) { // virtual functions called in constructors and destructors never use the // override in a derived class @@ -1075,9 +1029,6 @@ inline Vector::Vector() template template Vector::Vector(const InputIterator first, const InputIterator last) - : vec_size(0) - , max_vec_size(0) - , values(nullptr, &free) { // allocate memory. do not initialize it, as we will copy over to it in a // second @@ -1089,9 +1040,6 @@ Vector::Vector(const InputIterator first, const InputIterator last) template inline Vector::Vector(const size_type n) - : vec_size(0) - , max_vec_size(0) - , values(nullptr, &free) { // virtual functions called in constructors and destructors never use the // override in a derived class @@ -1105,7 +1053,7 @@ template inline typename Vector::size_type Vector::size() const { - return vec_size; + return values.size(); } @@ -1122,7 +1070,7 @@ template inline typename Vector::pointer Vector::data() { - return values.get(); + return values.data(); } @@ -1131,7 +1079,7 @@ template inline typename Vector::const_pointer Vector::data() const { - return values.get(); + return values.data(); } @@ -1140,7 +1088,7 @@ template inline typename Vector::iterator Vector::begin() { - return values.get(); + return values.begin(); } @@ -1149,7 +1097,7 @@ template inline typename Vector::const_iterator Vector::begin() const { - return values.get(); + return values.begin(); } @@ -1158,7 +1106,7 @@ template inline typename Vector::iterator Vector::end() { - return values.get() + vec_size; + return values.end(); } @@ -1167,7 +1115,7 @@ template inline typename Vector::const_iterator Vector::end() const { - return values.get() + vec_size; + return values.end(); } @@ -1176,7 +1124,7 @@ template inline Number Vector::operator()(const size_type i) const { - Assert(i < vec_size, ExcIndexRange(i, 0, vec_size)); + Assert(i < size(), ExcIndexRange(i, 0, size())); return values[i]; } @@ -1186,7 +1134,7 @@ template inline Number & Vector::operator()(const size_type i) { - Assert(i < vec_size, ExcIndexRangeType(i, 0, vec_size)); + Assert(i < size(), ExcIndexRangeType(i, 0, size())); return values[i]; } @@ -1271,7 +1219,7 @@ Vector::add(const std::vector &indices, { Assert(indices.size() == values.size(), ExcDimensionMismatch(indices.size(), values.size())); - add(indices.size(), indices.data(), values.values.get()); + add(indices.size(), indices.data(), values.values.begin()); } @@ -1285,7 +1233,7 @@ Vector::add(const size_type n_indices, { for (size_type i = 0; i < n_indices; ++i) { - Assert(indices[i] < vec_size, ExcIndexRange(indices[i], 0, vec_size)); + Assert(indices[i] < size(), ExcIndexRange(indices[i], 0, size())); Assert( numbers::is_finite(values[i]), ExcMessage( @@ -1327,8 +1275,6 @@ template inline void Vector::swap(Vector &v) { - std::swap(vec_size, v.vec_size); - std::swap(max_vec_size, v.max_vec_size); std::swap(values, v.values); } @@ -1341,9 +1287,7 @@ Vector::save(Archive &ar, const unsigned int) const { // forward to serialization function in the base class. ar &static_cast(*this); - - ar &vec_size &max_vec_size; - ar & boost::serialization::make_array(values.get(), max_vec_size); + ar &values; } @@ -1353,15 +1297,9 @@ template inline void Vector::load(Archive &ar, const unsigned int) { - // get rid of previous content - values.reset(); - // the load stuff again from the archive ar &static_cast(*this); - ar &vec_size &max_vec_size; - - allocate(); - ar &boost::serialization::make_array(values.get(), max_vec_size); + ar &values; } #endif diff --git a/include/deal.II/lac/vector.templates.h b/include/deal.II/lac/vector.templates.h index e67ffd71ae18..87c126c8b8b4 100644 --- a/include/deal.II/lac/vector.templates.h +++ b/include/deal.II/lac/vector.templates.h @@ -46,15 +46,8 @@ DEAL_II_NAMESPACE_OPEN template Vector::Vector(const Vector &v) : Subscriptor() - , vec_size(v.size()) - , max_vec_size(v.size()) - , values(nullptr, &free) { - if (vec_size != 0) - { - allocate(); - *this = v; - } + *this = v; } @@ -73,34 +66,11 @@ Vector::apply_givens_rotation(const std::array &csr, -template -Vector::Vector(Vector &&v) noexcept - : Subscriptor(std::move(v)) - , vec_size(v.vec_size) - , max_vec_size(v.max_vec_size) - , values(std::move(v.values)) - , thread_loop_partitioner(std::move(v.thread_loop_partitioner)) -{ - v.vec_size = 0; - v.max_vec_size = 0; - v.values = nullptr; -} - - - template template Vector::Vector(const Vector &v) - : Subscriptor() - , vec_size(v.size()) - , max_vec_size(v.size()) - , values(nullptr, &free) { - if (vec_size != 0) - { - allocate(); - *this = v; - } + *this = v; } @@ -154,10 +124,6 @@ namespace internal template Vector::Vector(const PETScWrappers::VectorBase &v) - : Subscriptor() - , vec_size(0) - , max_vec_size(0) - , values(nullptr, &free) { if (v.size() != 0) { @@ -171,15 +137,10 @@ Vector::Vector(const PETScWrappers::VectorBase &v) template Vector::Vector(const TrilinosWrappers::MPI::Vector &v) - : Subscriptor() - , vec_size(v.size()) - , max_vec_size(v.size()) - , values(nullptr, &free) + : values(v.size()) { - if (vec_size != 0) + if (size() != 0) { - allocate(); - // Copy the distributed vector to // a local one at all processors // that know about the original vector. @@ -188,12 +149,12 @@ Vector::Vector(const TrilinosWrappers::MPI::Vector &v) // this, but it has not yet been // found. TrilinosWrappers::MPI::Vector localized_vector; - localized_vector.reinit(complete_index_set(vec_size), + localized_vector.reinit(complete_index_set(size()), v.get_mpi_communicator()); localized_vector.reinit(v, false, true); - Assert(localized_vector.size() == vec_size, - ExcDimensionMismatch(localized_vector.size(), vec_size)); + Assert(localized_vector.size() == size(), + ExcDimensionMismatch(localized_vector.size(), size())); // get a representation of the vector // and copy it @@ -202,7 +163,7 @@ Vector::Vector(const TrilinosWrappers::MPI::Vector &v) int ierr = localized_vector.trilinos_vector().ExtractView(&start_ptr); AssertThrow(ierr == 0, ExcTrilinosError(ierr)); - std::copy(start_ptr[0], start_ptr[0] + vec_size, begin()); + std::copy(start_ptr[0], start_ptr[0] + size(), begin()); } } @@ -217,16 +178,16 @@ Vector::operator=(const Vector &v) return *this; thread_loop_partitioner = v.thread_loop_partitioner; - if (vec_size != v.vec_size) + if (size() != v.size()) reinit(v, true); - if (vec_size > 0) + if (0 < size()) { dealii::internal::VectorOperations::Vector_copy copier( - v.values.get(), values.get()); + v.begin(), begin()); internal::VectorOperations::parallel_for(copier, 0, - vec_size, + size(), thread_loop_partitioner); } @@ -235,39 +196,20 @@ Vector::operator=(const Vector &v) -template -inline Vector & -Vector::operator=(Vector &&v) noexcept -{ - Subscriptor::operator=(std::move(v)); - - vec_size = v.vec_size; - max_vec_size = v.max_vec_size; - values = std::move(v.values); - thread_loop_partitioner = std::move(v.thread_loop_partitioner); - - v.vec_size = 0; - v.max_vec_size = 0; - - return *this; -} - - - template template inline Vector & Vector::operator=(const Vector &v) { thread_loop_partitioner = v.thread_loop_partitioner; - if (vec_size != v.vec_size) + if (size() != v.size()) reinit(v, true); dealii::internal::VectorOperations::Vector_copy copier( - v.values.get(), values.get()); + v.begin(), begin()); internal::VectorOperations::parallel_for(copier, 0, - vec_size, + size(), thread_loop_partitioner); return *this; @@ -279,35 +221,41 @@ template inline void Vector::reinit(const size_type n, const bool omit_zeroing_entries) { - if (n == 0) + const std::size_t old_size = size(); + + // avoid allocating if the new size is not larger than the old size + if (n <= size()) { - values.reset(); - max_vec_size = vec_size = 0; thread_loop_partitioner = std::make_shared(); + if (n == 0) + { + values.clear(); + } + else if (n != size()) + values.resize_fast(n); + + if (!omit_zeroing_entries) + values.fill(); return; } - if (n > max_vec_size) - { - max_vec_size = n; - allocate(); - } + // otherwise size() < n and we must allocate + AlignedVector new_values; + new_values.resize_fast(n); + if (!omit_zeroing_entries) + new_values.fill(); + new_values.swap(values); - if (vec_size != n) + if (old_size != size()) { - vec_size = n; - // only reset the partitioner if we actually expect a significant vector // size - if (vec_size >= + if (size() >= 4 * internal::VectorImplementation::minimum_parallel_grain_size) thread_loop_partitioner = std::make_shared(); } - - if (omit_zeroing_entries == false) - *this = Number(); } @@ -316,37 +264,26 @@ template inline void Vector::grow_or_shrink(const size_type n) { + const std::size_t old_size = size(); if (n == 0) { - values.reset(); - max_vec_size = vec_size = 0; + values.clear(); thread_loop_partitioner = std::make_shared(); return; } - const size_type s = std::min(vec_size, n); - if (n > max_vec_size) - { - max_vec_size = n; - allocate(s); - } + values.resize(n); - if (vec_size != n) + if (old_size != n) { - vec_size = n; - // only reset the partitioner if we actually expect a significant vector // size - if (vec_size >= + if (size() >= 4 * internal::VectorImplementation::minimum_parallel_grain_size) thread_loop_partitioner = std::make_shared(); } - - // pad with zeroes - for (size_type i = s; i < vec_size; ++i) - values[i] = Number(); } @@ -359,21 +296,7 @@ Vector::reinit(const Vector &v, { thread_loop_partitioner = v.thread_loop_partitioner; - if (v.vec_size == 0) - { - values.reset(); - max_vec_size = vec_size = 0; - return; - } - - if (v.vec_size > max_vec_size) - { - max_vec_size = v.vec_size; - allocate(); - } - vec_size = v.vec_size; - if (omit_zeroing_entries == false) - *this = Number(); + reinit(v.size(), omit_zeroing_entries); } @@ -382,9 +305,9 @@ template bool Vector::all_zero() const { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); - for (size_type i = 0; i < vec_size; ++i) + for (size_type i = 0; i < size(); ++i) if (values[i] != Number()) return false; return true; @@ -396,9 +319,9 @@ template bool Vector::is_non_negative() const { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); - for (size_type i = 0; i < vec_size; ++i) + for (size_type i = 0; i < size(); ++i) if (!internal::VectorOperations::is_non_negative(values[i])) return false; @@ -413,14 +336,14 @@ Vector::operator=(const Number s) { AssertIsFinite(s); if (s != Number()) - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); - if (vec_size > 0) + if (size() > 0) { - internal::VectorOperations::Vector_set setter(s, values.get()); + internal::VectorOperations::Vector_set setter(s, values.begin()); internal::VectorOperations::parallel_for(setter, 0, - vec_size, + size(), thread_loop_partitioner); } @@ -435,14 +358,14 @@ Vector::operator*=(const Number factor) { AssertIsFinite(factor); - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); internal::VectorOperations::Vectorization_multiply_factor - vector_multiply(values.get(), factor); + vector_multiply(values.begin(), factor); internal::VectorOperations::parallel_for(vector_multiply, 0, - vec_size, + size(), thread_loop_partitioner); return *this; @@ -456,14 +379,14 @@ Vector::add(const Number a, const Vector &v) { AssertIsFinite(a); - Assert(vec_size != 0, ExcEmptyObject()); - Assert(vec_size == v.vec_size, ExcDimensionMismatch(vec_size, v.vec_size)); + Assert(size() != 0, ExcEmptyObject()); + Assert(size() == v.size(), ExcDimensionMismatch(size(), v.size())); internal::VectorOperations::Vectorization_add_av vector_add_av( - values.get(), v.values.get(), a); + values.begin(), v.values.begin(), a); internal::VectorOperations::parallel_for(vector_add_av, 0, - vec_size, + size(), thread_loop_partitioner); } @@ -476,14 +399,14 @@ Vector::sadd(const Number x, const Number a, const Vector &v) AssertIsFinite(x); AssertIsFinite(a); - Assert(vec_size != 0, ExcEmptyObject()); - Assert(vec_size == v.vec_size, ExcDimensionMismatch(vec_size, v.vec_size)); + Assert(size() != 0, ExcEmptyObject()); + Assert(size() == v.size(), ExcDimensionMismatch(size(), v.size())); internal::VectorOperations::Vectorization_sadd_xav vector_sadd_xav( - values.get(), v.values.get(), a, x); + values.begin(), v.values.begin(), a, x); internal::VectorOperations::parallel_for(vector_sadd_xav, 0, - vec_size, + size(), thread_loop_partitioner); } @@ -493,18 +416,18 @@ template template Number Vector::operator*(const Vector &v) const { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); if (PointerComparison::equal(this, &v)) return norm_sqr(); - Assert(vec_size == v.size(), ExcDimensionMismatch(vec_size, v.size())); + Assert(size() == v.size(), ExcDimensionMismatch(size(), v.size())); Number sum; - internal::VectorOperations::Dot dot(values.get(), - v.values.get()); + internal::VectorOperations::Dot dot(values.begin(), + v.values.begin()); internal::VectorOperations::parallel_reduce( - dot, 0, vec_size, sum, thread_loop_partitioner); + dot, 0, size(), sum, thread_loop_partitioner); AssertIsFinite(sum); return sum; @@ -516,12 +439,12 @@ template typename Vector::real_type Vector::norm_sqr() const { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); real_type sum; - internal::VectorOperations::Norm2 norm2(values.get()); + internal::VectorOperations::Norm2 norm2(values.begin()); internal::VectorOperations::parallel_reduce( - norm2, 0, vec_size, sum, thread_loop_partitioner); + norm2, 0, size(), sum, thread_loop_partitioner); AssertIsFinite(sum); @@ -534,12 +457,12 @@ template Number Vector::mean_value() const { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); Number sum; - internal::VectorOperations::MeanValue mean(values.get()); + internal::VectorOperations::MeanValue mean(values.begin()); internal::VectorOperations::parallel_reduce( - mean, 0, vec_size, sum, thread_loop_partitioner); + mean, 0, size(), sum, thread_loop_partitioner); return sum / real_type(size()); } @@ -550,12 +473,12 @@ template typename Vector::real_type Vector::l1_norm() const { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); real_type sum; - internal::VectorOperations::Norm1 norm1(values.get()); + internal::VectorOperations::Norm1 norm1(values.begin()); internal::VectorOperations::parallel_reduce( - norm1, 0, vec_size, sum, thread_loop_partitioner); + norm1, 0, size(), sum, thread_loop_partitioner); return sum; } @@ -571,12 +494,12 @@ Vector::l2_norm() const // might still be finite. In that case, recompute it (this is a rare case, // so working on the vector twice is uncritical and paid off by the extended // precision) using the BLAS approach with a weight, see e.g. dnrm2.f. - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); real_type norm_square; - internal::VectorOperations::Norm2 norm2(values.get()); + internal::VectorOperations::Norm2 norm2(values.begin()); internal::VectorOperations::parallel_reduce( - norm2, 0, vec_size, norm_square, thread_loop_partitioner); + norm2, 0, size(), norm_square, thread_loop_partitioner); if (numbers::is_finite(norm_square) && norm_square >= std::numeric_limits::min()) return static_cast::real_type>( @@ -585,7 +508,7 @@ Vector::l2_norm() const { real_type scale = 0.; real_type sum = 1.; - for (size_type i = 0; i < vec_size; ++i) + for (size_type i = 0; i < size(); ++i) { if (values[i] != Number()) { @@ -612,7 +535,7 @@ template typename Vector::real_type Vector::lp_norm(const real_type p) const { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); if (p == 1.) return l1_norm(); @@ -620,9 +543,9 @@ Vector::lp_norm(const real_type p) const return l2_norm(); real_type sum; - internal::VectorOperations::NormP normp(values.get(), p); + internal::VectorOperations::NormP normp(values.begin(), p); internal::VectorOperations::parallel_reduce( - normp, 0, vec_size, sum, thread_loop_partitioner); + normp, 0, size(), sum, thread_loop_partitioner); if (numbers::is_finite(sum) && sum >= std::numeric_limits::min()) return std::pow(sum, static_cast(1. / p)); @@ -630,7 +553,7 @@ Vector::lp_norm(const real_type p) const { real_type scale = 0.; real_type sum = 1.; - for (size_type i = 0; i < vec_size; ++i) + for (size_type i = 0; i < size(); ++i) { if (values[i] != Number()) { @@ -655,11 +578,11 @@ template typename Vector::real_type Vector::linfty_norm() const { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); real_type max = 0.; - for (size_type i = 0; i < vec_size; ++i) + for (size_type i = 0; i < size(); ++i) max = std::max(numbers::NumberTraits::abs(values[i]), max); return max; @@ -673,17 +596,17 @@ Vector::add_and_dot(const Number a, const Vector &V, const Vector &W) { - Assert(vec_size != 0, ExcEmptyObject()); - AssertDimension(vec_size, V.size()); - AssertDimension(vec_size, W.size()); + Assert(size() != 0, ExcEmptyObject()); + AssertDimension(size(), V.size()); + AssertDimension(size(), W.size()); Number sum; - internal::VectorOperations::AddAndDot adder(this->values.get(), - V.values.get(), - W.values.get(), + internal::VectorOperations::AddAndDot adder(values.begin(), + V.values.begin(), + W.values.begin(), a); internal::VectorOperations::parallel_reduce( - adder, 0, vec_size, sum, thread_loop_partitioner); + adder, 0, size(), sum, thread_loop_partitioner); AssertIsFinite(sum); return sum; @@ -695,14 +618,14 @@ template Vector & Vector::operator+=(const Vector &v) { - Assert(vec_size != 0, ExcEmptyObject()); - Assert(vec_size == v.vec_size, ExcDimensionMismatch(vec_size, v.vec_size)); + Assert(size() != 0, ExcEmptyObject()); + Assert(size() == v.size(), ExcDimensionMismatch(size(), v.size())); internal::VectorOperations::Vectorization_add_v vector_add( - values.get(), v.values.get()); + values.begin(), v.values.begin()); internal::VectorOperations::parallel_for(vector_add, 0, - vec_size, + size(), thread_loop_partitioner); return *this; } @@ -713,14 +636,14 @@ template Vector & Vector::operator-=(const Vector &v) { - Assert(vec_size != 0, ExcEmptyObject()); - Assert(vec_size == v.vec_size, ExcDimensionMismatch(vec_size, v.vec_size)); + Assert(size() != 0, ExcEmptyObject()); + Assert(size() == v.size(), ExcDimensionMismatch(size(), v.size())); internal::VectorOperations::Vectorization_subtract_v vector_subtract( - values.get(), v.values.get()); + values.begin(), v.values.begin()); internal::VectorOperations::parallel_for(vector_subtract, 0, - vec_size, + size(), thread_loop_partitioner); return *this; @@ -732,13 +655,13 @@ template void Vector::add(const Number v) { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); internal::VectorOperations::Vectorization_add_factor vector_add( - values.get(), v); + values.begin(), v); internal::VectorOperations::parallel_for(vector_add, 0, - vec_size, + size(), thread_loop_partitioner); } @@ -754,15 +677,15 @@ Vector::add(const Number a, AssertIsFinite(a); AssertIsFinite(b); - Assert(vec_size != 0, ExcEmptyObject()); - Assert(vec_size == v.vec_size, ExcDimensionMismatch(vec_size, v.vec_size)); - Assert(vec_size == w.vec_size, ExcDimensionMismatch(vec_size, w.vec_size)); + Assert(size() != 0, ExcEmptyObject()); + Assert(size() == v.size(), ExcDimensionMismatch(size(), v.size())); + Assert(size() == w.size(), ExcDimensionMismatch(size(), w.size())); internal::VectorOperations::Vectorization_add_avpbw vector_add( - values.get(), v.values.get(), w.values.get(), a, b); + values.begin(), v.values.begin(), w.values.begin(), a, b); internal::VectorOperations::parallel_for(vector_add, 0, - vec_size, + size(), thread_loop_partitioner); } @@ -774,14 +697,14 @@ Vector::sadd(const Number x, const Vector &v) { AssertIsFinite(x); - Assert(vec_size != 0, ExcEmptyObject()); - Assert(vec_size == v.vec_size, ExcDimensionMismatch(vec_size, v.vec_size)); + Assert(size() != 0, ExcEmptyObject()); + Assert(size() == v.size(), ExcDimensionMismatch(size(), v.size())); internal::VectorOperations::Vectorization_sadd_xv vector_sadd( - values.get(), v.values.get(), x); + values.begin(), v.values.begin(), x); internal::VectorOperations::parallel_for(vector_sadd, 0, - vec_size, + size(), thread_loop_partitioner); } @@ -791,14 +714,14 @@ template void Vector::scale(const Vector &s) { - Assert(vec_size != 0, ExcEmptyObject()); - Assert(vec_size == s.vec_size, ExcDimensionMismatch(vec_size, s.vec_size)); + Assert(size() != 0, ExcEmptyObject()); + Assert(size() == s.size(), ExcDimensionMismatch(size(), s.size())); internal::VectorOperations::Vectorization_scale vector_scale( - values.get(), s.values.get()); + values.begin(), s.values.begin()); internal::VectorOperations::parallel_for(vector_scale, 0, - vec_size, + size(), thread_loop_partitioner); } @@ -809,10 +732,10 @@ template void Vector::scale(const Vector &s) { - Assert(vec_size != 0, ExcEmptyObject()); - Assert(vec_size == s.vec_size, ExcDimensionMismatch(vec_size, s.vec_size)); + Assert(size() != 0, ExcEmptyObject()); + Assert(size() == s.size(), ExcDimensionMismatch(size(), s.size())); - for (size_type i = 0; i < vec_size; ++i) + for (size_type i = 0; i < size(); ++i) values[i] *= Number(s.values[i]); } @@ -824,14 +747,14 @@ Vector::equ(const Number a, const Vector &u) { AssertIsFinite(a); - Assert(vec_size != 0, ExcEmptyObject()); - Assert(vec_size == u.vec_size, ExcDimensionMismatch(vec_size, u.vec_size)); + Assert(size() != 0, ExcEmptyObject()); + Assert(size() == u.size(), ExcDimensionMismatch(size(), u.size())); internal::VectorOperations::Vectorization_equ_au vector_equ( - values.get(), u.values.get(), a); + values.begin(), u.values.begin(), a); internal::VectorOperations::parallel_for(vector_equ, 0, - vec_size, + size(), thread_loop_partitioner); } @@ -844,8 +767,8 @@ Vector::equ(const Number a, const Vector &u) { AssertIsFinite(a); - Assert(vec_size != 0, ExcEmptyObject()); - Assert(vec_size == u.vec_size, ExcDimensionMismatch(vec_size, u.vec_size)); + Assert(size() != 0, ExcEmptyObject()); + Assert(size() == u.size(), ExcDimensionMismatch(size(), u.size())); // set the result vector to a*u. we have to // convert the elements of u to the type of @@ -853,7 +776,7 @@ Vector::equ(const Number a, const Vector &u) // because // operator*(complex,complex) // is not defined by default - for (size_type i = 0; i < vec_size; ++i) + for (size_type i = 0; i < size(); ++i) values[i] = a * Number(u.values[i]); } @@ -863,19 +786,18 @@ template void Vector::ratio(const Vector &a, const Vector &b) { - Assert(vec_size != 0, ExcEmptyObject()); - Assert(a.vec_size == b.vec_size, - ExcDimensionMismatch(a.vec_size, b.vec_size)); + Assert(size() != 0, ExcEmptyObject()); + Assert(a.size() == b.size(), ExcDimensionMismatch(a.size(), b.size())); // no need to reinit with zeros, since // we overwrite them anyway reinit(a.size(), true); internal::VectorOperations::Vectorization_ratio vector_ratio( - values.get(), a.values.get(), b.values.get()); + values.begin(), a.begin(), b.begin()); internal::VectorOperations::parallel_for(vector_ratio, 0, - vec_size, + size(), thread_loop_partitioner); } @@ -885,7 +807,7 @@ template Vector & Vector::operator=(const BlockVector &v) { - if (v.size() != vec_size) + if (v.size() != size()) reinit(v.size(), true); size_type this_index = 0; @@ -915,9 +837,9 @@ template Vector & Vector::operator=(const TrilinosWrappers::MPI::Vector &v) { - if (v.size() != vec_size) + if (v.size() != size()) reinit(v.size(), true); - if (vec_size != 0) + if (size() != 0) { // Copy the distributed vector to // a local one at all processors @@ -927,12 +849,12 @@ Vector::operator=(const TrilinosWrappers::MPI::Vector &v) // this, but it has not yet been // found. TrilinosWrappers::MPI::Vector localized_vector; - localized_vector.reinit(complete_index_set(vec_size), + localized_vector.reinit(complete_index_set(size()), v.get_mpi_communicator()); localized_vector.reinit(v, false, true); - Assert(localized_vector.size() == vec_size, - ExcDimensionMismatch(localized_vector.size(), vec_size)); + Assert(localized_vector.size() == size(), + ExcDimensionMismatch(localized_vector.size(), size())); // get a representation of the vector // and copy it @@ -941,7 +863,7 @@ Vector::operator=(const TrilinosWrappers::MPI::Vector &v) int ierr = localized_vector.trilinos_vector().ExtractView(&start_ptr); AssertThrow(ierr == 0, ExcTrilinosError(ierr)); - std::copy(start_ptr[0], start_ptr[0] + vec_size, begin()); + std::copy(start_ptr[0], start_ptr[0] + size(), begin()); } return *this; @@ -954,8 +876,7 @@ template bool Vector::operator==(const Vector &v) const { - Assert(vec_size != 0, ExcEmptyObject()); - Assert(vec_size == v.size(), ExcDimensionMismatch(vec_size, v.size())); + Assert(size() == v.size(), ExcDimensionMismatch(size(), v.size())); // compare the two vector. we have to // convert the elements of v to the type of @@ -963,7 +884,7 @@ Vector::operator==(const Vector &v) const // because // operator==(complex,complex) // is not defined by default - for (size_type i = 0; i < vec_size; ++i) + for (size_type i = 0; i < size(); ++i) if (values[i] != Number(v.values[i])) return false; @@ -976,7 +897,7 @@ template void Vector::print(const char *format) const { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); for (size_type j = 0; j < size(); ++j) internal::VectorOperations::print(values[j], format); @@ -992,7 +913,7 @@ Vector::print(std::ostream & out, const bool scientific, const bool across) const { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); AssertThrow(out, ExcIO()); std::ios::fmtflags old_flags = out.flags(); @@ -1026,7 +947,7 @@ Vector::print(LogStream & out, const unsigned int width, const bool across) const { - Assert(vec_size != 0, ExcEmptyObject()); + Assert(size() != 0, ExcEmptyObject()); if (across) for (size_type i = 0; i < size(); ++i) @@ -1121,28 +1042,10 @@ template std::size_t Vector::memory_consumption() const { - return sizeof(*this) + (max_vec_size * sizeof(Number)); + return sizeof(*this) + values.memory_consumption() - sizeof(values); } - -template -void -Vector::allocate(const size_type copy_n_el) -{ - // allocate memory with the proper alignment requirements of 64 bytes - Number *new_values; - Utilities::System::posix_memalign(reinterpret_cast(&new_values), - 64, - sizeof(Number) * max_vec_size); - // copy: - for (size_type i = 0; i < copy_n_el; ++i) - new_values[i] = values[i]; - values.reset(new_values); -} - - - DEAL_II_NAMESPACE_CLOSE #endif diff --git a/tests/serialization/vector.output b/tests/serialization/vector.output index 2fc4d411cf08..d51d6c2c0222 100644 --- a/tests/serialization/vector.output +++ b/tests/serialization/vector.output @@ -1,6 +1,6 @@ -DEAL::0 0 0 0 5 5 0 1 2 3 4 +DEAL::0 0 0 0 0 0 5 0 1 2 3 4 -DEAL::0 0 0 0 5 5 0 1 2 3 4 +DEAL::0 0 0 0 0 0 5 0 1 2 3 4 DEAL::OK From 80f73b5ecc2d658a3bbc5eb372105ac058428906 Mon Sep 17 00:00:00 2001 From: David Wells Date: Sat, 26 Jan 2019 19:23:24 -0500 Subject: [PATCH 028/507] Update the .gdbinit script. --- contrib/utilities/dotgdbinit.py | 50 +++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 15 deletions(-) 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'], From 174fe8cce2d9ec68185227ea190274695160a3f4 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 29 Jan 2019 23:23:50 +0100 Subject: [PATCH 029/507] Disable SIMD vectorization in CUDA device code --- include/deal.II/base/config.h.in | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/deal.II/base/config.h.in b/include/deal.II/base/config.h.in index 7801a2397f44..9da0d4818f2e 100644 --- a/include/deal.II/base/config.h.in +++ b/include/deal.II/base/config.h.in @@ -114,7 +114,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@ From aa56d092232c384222aff86578ee4b6f1a359bb9 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 29 Jan 2019 23:48:08 +0100 Subject: [PATCH 030/507] Add missing headers in CUDA header file --- include/deal.II/matrix_free/cuda_tensor_product_kernels.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/deal.II/matrix_free/cuda_tensor_product_kernels.h b/include/deal.II/matrix_free/cuda_tensor_product_kernels.h index 81c8fff6ab22..c27561646e1e 100644 --- a/include/deal.II/matrix_free/cuda_tensor_product_kernels.h +++ b/include/deal.II/matrix_free/cuda_tensor_product_kernels.h @@ -19,6 +19,10 @@ #include +#include + +#include + #ifdef DEAL_II_COMPILER_CUDA_AWARE DEAL_II_NAMESPACE_OPEN From bfd22d07ce53528ad4bdc36069d29cf165169458 Mon Sep 17 00:00:00 2001 From: Giovanni Alzetta Date: Tue, 29 Jan 2019 16:29:15 +0100 Subject: [PATCH 031/507] Generalizing GridGenerator::general_cell to tria --- .../changes/minor/20190130GiovanniAlzetta | 5 + include/deal.II/grid/grid_generator.h | 24 +++-- source/grid/grid_generator.cc | 10 +- source/grid/grid_generator.inst.in | 9 +- ...l.cc => grid_generator_general_cell_01.cc} | 0 ... => grid_generator_general_cell_01.output} | 0 tests/grid/grid_generator_general_cell_02.cc | 95 +++++++++++++++++++ .../grid_generator_general_cell_02.output | 87 +++++++++++++++++ 8 files changed, 211 insertions(+), 19 deletions(-) create mode 100644 doc/news/changes/minor/20190130GiovanniAlzetta rename tests/grid/{grid_generator_general_cell.cc => grid_generator_general_cell_01.cc} (100%) rename tests/grid/{grid_generator_general_cell.output => grid_generator_general_cell_01.output} (100%) create mode 100644 tests/grid/grid_generator_general_cell_02.cc create mode 100644 tests/grid/grid_generator_general_cell_02.output 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/include/deal.II/grid/grid_generator.h b/include/deal.II/grid/grid_generator.h index 354037d6f20a..0a4d52818f7d 100644 --- a/include/deal.II/grid/grid_generator.h +++ b/include/deal.II/grid/grid_generator.h @@ -462,11 +462,13 @@ namespace GridGenerator const bool colorize = false); /** - * A general quadrilateral in 2d or a general hexahedron in 3d. It is the - * responsibility of the user to provide the vertices in the right order (see - * the documentation of the GeometryInfo class) because the vertices are - * stored in the same order as they are given. It is also important to make - * sure that the volume of the cell is positive. + * A general @p dim -dimensional cell (a segment if dim is 1, a quadrilateral + * if @p dim is 2, or a hexahedron if @p dim is 3) immersed in a + * @p spacedim -dimensional space. It is the responsibility of the user to + * provide the vertices in the right order (see the documentation of the + * GeometryInfo class) because the vertices are stored in the same order as + * they are given. It is also important to make sure that the volume of the + * cell is positive. * * If the argument @p colorize is false, then all boundary indicators are * set to zero for 2d and 3d. If it is true, the boundary is colorized as in @@ -474,13 +476,17 @@ namespace GridGenerator * @ref GlossColorization "the glossary entry on colorization"). In 1d the * indicators are always colorized, see hyper_rectangle(). * + * @param tria The triangulation that will be created + * @param vertices The 2^dim vertices of the cell + * @param colorize If true, set different boundary ids. + * * @author Bruno Turcksin */ - template + template void - general_cell(Triangulation & tria, - const std::vector> &vertices, - const bool colorize = false); + general_cell(Triangulation & tria, + const std::vector> &vertices, + const bool colorize = false); /** * A parallelogram. The first corner point is the origin. The @p dim diff --git a/source/grid/grid_generator.cc b/source/grid/grid_generator.cc index a51cbe29a312..9738d7937287 100644 --- a/source/grid/grid_generator.cc +++ b/source/grid/grid_generator.cc @@ -749,11 +749,11 @@ namespace GridGenerator - template + template void - general_cell(Triangulation & tria, - const std::vector> &vertices, - const bool colorize) + general_cell(Triangulation & tria, + const std::vector> &vertices, + const bool colorize) { Assert(vertices.size() == dealii::GeometryInfo::vertices_per_cell, ExcMessage("Wrong number of vertices.")); @@ -761,7 +761,7 @@ namespace GridGenerator // First create a hyper_rectangle and then deform it. hyper_cube(tria, 0, 1, colorize); - typename Triangulation::active_cell_iterator cell = + typename Triangulation::active_cell_iterator cell = tria.begin_active(); for (unsigned int i = 0; i < GeometryInfo::vertices_per_cell; ++i) cell->vertex(i) = vertices[i]; diff --git a/source/grid/grid_generator.inst.in b/source/grid/grid_generator.inst.in index 0084a2851210..2253edee987a 100644 --- a/source/grid/grid_generator.inst.in +++ b/source/grid/grid_generator.inst.in @@ -106,6 +106,10 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) &cells_to_remove, Triangulation &result); + template void + general_cell(Triangulation &, + const std::vector> &, + const bool); #endif \} } @@ -153,11 +157,6 @@ for (deal_II_dimension : DIMENSIONS) const Point &, const bool); - template void - general_cell(Triangulation &, - const std::vector> &, - const bool); - template void simplex( Triangulation &, diff --git a/tests/grid/grid_generator_general_cell.cc b/tests/grid/grid_generator_general_cell_01.cc similarity index 100% rename from tests/grid/grid_generator_general_cell.cc rename to tests/grid/grid_generator_general_cell_01.cc diff --git a/tests/grid/grid_generator_general_cell.output b/tests/grid/grid_generator_general_cell_01.output similarity index 100% rename from tests/grid/grid_generator_general_cell.output rename to tests/grid/grid_generator_general_cell_01.output diff --git a/tests/grid/grid_generator_general_cell_02.cc b/tests/grid/grid_generator_general_cell_02.cc new file mode 100644 index 000000000000..cd60e7aec13d --- /dev/null +++ b/tests/grid/grid_generator_general_cell_02.cc @@ -0,0 +1,95 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 - 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. +// +// --------------------------------------------------------------------- + +// Test output for GridGenerator::general_cell() for dim != spacedim + +#include +#include +#include + +#include "../tests.h" + +void +dim_2_3(std::ostream &os) +{ + std::vector> vertices(4); + vertices[0](0) = -1.; + vertices[0](1) = -1.; + vertices[0](0) = 0.; + + vertices[1](0) = 1.; + vertices[1](1) = -1.5; + vertices[1](2) = 0.; + + vertices[2](0) = 1.5; + vertices[2](1) = 1.5; + vertices[2](2) = 0.; + + vertices[3](0) = 2.; + vertices[3](1) = 0.5; + vertices[3](2) = 0.; + + Triangulation<2, 3> tria; + GridGenerator::general_cell<2, 3>(tria, vertices); + + GridOut gout; + gout.write_vtk(tria, os); +} + +void +dim_1_3(std::ostream &os) +{ + std::vector> vertices(2); + vertices[0](0) = -1.; + vertices[0](1) = -1.; + vertices[0](2) = -1.; + vertices[1](0) = 1.; + vertices[1](1) = -1.5; + vertices[1](2) = -1.5; + + Triangulation<1, 3> tria; + GridGenerator::general_cell<1, 3>(tria, vertices); + + GridOut gout; + gout.write_vtk(tria, os); +} + +void +dim_1_2(std::ostream &os) +{ + std::vector> vertices(2); + vertices[0](0) = -1.; + vertices[0](1) = -1.; + + vertices[1](0) = 1.; + vertices[1](1) = -1.5; + + Triangulation<1, 2> tria; + GridGenerator::general_cell<1, 2>(tria, vertices); + + GridOut gout; + gout.write_vtk(tria, os); +} + + +int +main() +{ + initlog(true); + std::ostream &logfile = deallog.get_file_stream(); + dim_2_3(logfile); + dim_1_3(logfile); + dim_1_2(logfile); +} diff --git a/tests/grid/grid_generator_general_cell_02.output b/tests/grid/grid_generator_general_cell_02.output new file mode 100644 index 000000000000..8a44d1386273 --- /dev/null +++ b/tests/grid/grid_generator_general_cell_02.output @@ -0,0 +1,87 @@ + +# vtk DataFile Version 3.0 +Triangulation generated with deal.II +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 4 double +0.00000 -1.00000 0.00000 +1.00000 -1.50000 0.00000 +1.50000 1.50000 0.00000 +2.00000 0.500000 0.00000 + +CELLS 1 5 +4 0 1 3 2 + +CELL_TYPES 1 +9 + + + +CELL_DATA 1 +SCALARS MaterialID int 1 +LOOKUP_TABLE default +0 + + + +SCALARS ManifoldID int 1 +LOOKUP_TABLE default +-1 + + +# vtk DataFile Version 3.0 +Triangulation generated with deal.II +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 2 double +-1.00000 -1.00000 -1.00000 +1.00000 -1.50000 -1.50000 + +CELLS 1 3 +2 0 1 + +CELL_TYPES 1 +3 + + + +CELL_DATA 1 +SCALARS MaterialID int 1 +LOOKUP_TABLE default +0 + + + +SCALARS ManifoldID int 1 +LOOKUP_TABLE default +-1 + + +# vtk DataFile Version 3.0 +Triangulation generated with deal.II +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 2 double +-1.00000 -1.00000 0 +1.00000 -1.50000 0 + +CELLS 1 3 +2 0 1 + +CELL_TYPES 1 +3 + + + +CELL_DATA 1 +SCALARS MaterialID int 1 +LOOKUP_TABLE default +0 + + + +SCALARS ManifoldID int 1 +LOOKUP_TABLE default +-1 + + From 2f90725fe6839f1f3d636c4463c90ec0a51f41dc Mon Sep 17 00:00:00 2001 From: Pratik Nayak Date: Wed, 30 Jan 2019 12:47:50 +0100 Subject: [PATCH 032/507] Detect Ginkgo and compile the ginkgo files: CMake. --- cmake/configure/configure_2_ginkgo.cmake | 39 +++++++++++++ cmake/modules/FindGINKGO.cmake | 72 ++++++++++++++++++++++++ include/deal.II/base/config.h.in | 3 +- source/lac/CMakeLists.txt | 7 +++ tests/run_testsuite.cmake | 4 +- 5 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 cmake/configure/configure_2_ginkgo.cmake create mode 100644 cmake/modules/FindGINKGO.cmake 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/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/include/deal.II/base/config.h.in b/include/deal.II/base/config.h.in index 7801a2397f44..84e17b338438 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 diff --git a/source/lac/CMakeLists.txt b/source/lac/CMakeLists.txt index 2cecfbc24f36..a6ce60360fe8 100644 --- a/source/lac/CMakeLists.txt +++ b/source/lac/CMakeLists.txt @@ -112,6 +112,13 @@ IF(DEAL_II_WITH_SLEPC) ) ENDIF() +IF(DEAL_II_WITH_GINKGO) + SET(_unity_include_src + ${_unity_include_src} + ginkgo_solver.cc + ) +ENDIF() + # Also add Trilinos wrapper files IF(DEAL_II_WITH_TRILINOS) SET(_unity_include_src diff --git a/tests/run_testsuite.cmake b/tests/run_testsuite.cmake index 713c31b614c0..688ae9da6500 100644 --- a/tests/run_testsuite.cmake +++ b/tests/run_testsuite.cmake @@ -1,6 +1,6 @@ ## --------------------------------------------------------------------- ## -## Copyright (C) 2013 - 2016 by the deal.II authors +## Copyright (C) 2013 - 2018 by the deal.II authors ## ## This file is part of the deal.II library. ## @@ -273,7 +273,7 @@ FOREACH(_var ${_variables}) IF( _var MATCHES "^(TEST|DEAL_II|ALLOW|WITH|FORCE|COMPONENT)_" OR _var MATCHES "^(DOCUMENTATION|EXAMPLES)" OR _var MATCHES "^(ADOLC|ARPACK|BOOST|OPENCASCADE|MUPARSER|HDF5|METIS|MPI)_" OR - _var MATCHES "^(NETCDF|P4EST|PETSC|SCALAPACK|SLEPC|THREADS|TBB|TRILINOS)_" OR + _var MATCHES "^(GINKGO|NETCDF|P4EST|PETSC|SCALAPACK|SLEPC|THREADS|TBB|TRILINOS)_" OR _var MATCHES "^(UMFPACK|ZLIB|LAPACK|MUPARSER|CUDA)_" OR _var MATCHES "^(CMAKE|DEAL_II)_(C|CXX|Fortran|BUILD)_(COMPILER|FLAGS)" OR _var MATCHES "^CMAKE_BUILD_TYPE$" OR From b4957baf7539f67123fa3b19e1c9a0f5e0e72380 Mon Sep 17 00:00:00 2001 From: Pratik Nayak Date: Wed, 30 Jan 2019 12:49:04 +0100 Subject: [PATCH 033/507] Add documentation to readme.html and ginkgo.html files --- doc/external-libs/ginkgo.html | 96 +++++++++++++++++++++++++++++++++++ doc/readme.html | 16 ++++++ 2 files changed, 112 insertions(+) create mode 100644 doc/external-libs/ginkgo.html 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/readme.html b/doc/readme.html index 2294bfbfa659..406981e5f710 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -423,6 +423,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
From 7dc7cbab1214364fac2cfd5466099cd3f8bd6908 Mon Sep 17 00:00:00 2001 From: Pratik Nayak Date: Wed, 30 Jan 2019 12:49:36 +0100 Subject: [PATCH 034/507] Add initial tests for ginkgo --- tests/ginkgo/CMakeLists.txt | 6 ++++ tests/ginkgo/solver.cc | 67 +++++++++++++++++++++++++++++++++++++ tests/ginkgo/solver.output | 3 ++ 3 files changed, 76 insertions(+) create mode 100644 tests/ginkgo/CMakeLists.txt create mode 100644 tests/ginkgo/solver.cc create mode 100644 tests/ginkgo/solver.output diff --git a/tests/ginkgo/CMakeLists.txt b/tests/ginkgo/CMakeLists.txt new file mode 100644 index 000000000000..f549331a0595 --- /dev/null +++ b/tests/ginkgo/CMakeLists.txt @@ -0,0 +1,6 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) +INCLUDE(../setup_testsubproject.cmake) +PROJECT(testsuite CXX) +IF(DEAL_II_WITH_GINKGO) + DEAL_II_PICKUP_TESTS() +ENDIF() diff --git a/tests/ginkgo/solver.cc b/tests/ginkgo/solver.cc new file mode 100644 index 000000000000..560d9117c411 --- /dev/null +++ b/tests/ginkgo/solver.cc @@ -0,0 +1,67 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// test the Ginkgo CG solver + +#include +#include +#include +#include + +#include +#include + +#include "../testmatrix.h" +#include "../tests.h" + +int +main(int argc, char **argv) +{ + initlog(); + deallog << std::setprecision(4); + + { + SolverControl control(100, 1e-3); + + const unsigned int size = 32; + unsigned int dim = (size - 1) * (size - 1); + + deallog << "Size " << size << " Unknowns " << dim << std::endl; + + // Make matrix + FDMatrix testproblem(size, size); + SparsityPattern structure(dim, dim, 5); + testproblem.five_point_structure(structure); + structure.compress(); + SparseMatrix A(structure); + testproblem.five_point(A); + + Vector f(dim); + f = 1.; + Vector u(dim); + u = 0.; + + // std::shared_ptr exec = gko::CudaExecutor::create(0, + // gko::OmpExecutor::create()); + // std::shared_ptr exec = gko::OmpExecutor::create(); + std::shared_ptr exec = gko::ReferenceExecutor::create(); + GinkgoWrappers::SolverCG<> solver(control, exec); + + check_solver_within_range(solver.solve(A, u, f), + control.last_step(), + 35, + 39); + } +} diff --git a/tests/ginkgo/solver.output b/tests/ginkgo/solver.output new file mode 100644 index 000000000000..4ce62b0ef7c1 --- /dev/null +++ b/tests/ginkgo/solver.output @@ -0,0 +1,3 @@ + +DEAL::Size 32 Unknowns 961 +DEAL::Solver stopped within 35 - 39 iterations From 57381dfaaeb088cda88e1628a7336c56dfc6ba18 Mon Sep 17 00:00:00 2001 From: Pratik Nayak Date: Wed, 30 Jan 2019 12:50:06 +0100 Subject: [PATCH 035/507] Add the ginkgo source and include files. --- include/deal.II/lac/ginkgo_solver.h | 243 +++++++++++++++++++++ source/lac/ginkgo_solver.cc | 313 ++++++++++++++++++++++++++++ 2 files changed, 556 insertions(+) create mode 100644 include/deal.II/lac/ginkgo_solver.h create mode 100644 source/lac/ginkgo_solver.cc diff --git a/include/deal.II/lac/ginkgo_solver.h b/include/deal.II/lac/ginkgo_solver.h new file mode 100644 index 000000000000..3ac50c912836 --- /dev/null +++ b/include/deal.II/lac/ginkgo_solver.h @@ -0,0 +1,243 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_ginkgo_solver_h +# define dealii_ginkgo_solver_h + + +# include + +# ifdef DEAL_II_WITH_GINKGO + +# include +# include +# include +# include +# include + +# include + +# include + +DEAL_II_NAMESPACE_OPEN + +namespace GinkgoWrappers +{ + /** + * This class forms the base class for all of Ginkgo's iterative solvers. + * The various derived classes only take + * the additional data that is specific to them and solve the given linear + * system. The entire collection of solvers that Ginkgo implements is + * available at documentation + * and manual pages. + * + * @ingroup GinkgoWrappers + */ + template + class SolverBase + { + public: + /** + * Constructor. + * + * The @p executor defines the paradigm where the solution is computed. + * Ginkgo currently supports three different executor types: + * + * + OmpExecutor specifies that the data should be stored and the + * associated operations executed on an OpenMP-supporting device (e.g. host + * CPU); + * ``` + * auto omp = gko::create(); + * ``` + * + CudaExecutor specifies that the data should be stored and the + * operations executed on the NVIDIA GPU accelerator; + * ``` + * if(gko::CudaExecutor::get_num_devices() > 0 ) { + * auto cuda = gko::create(); + * } + * ``` + * + ReferenceExecutor executes a non-optimized reference implementation, + * which can be used to debug the library. + * ``` + * auto ref = gko::create(); + * ``` + * + * The following code snippet demonstrates the using of the OpenMP executor + * to create a solver which would use the OpenMP paradigm to the solve the + * system on the CPU. + * + * ``` + * auto omp = gko::create(); + * using cg = gko::solver::Cg<>; + * auto solver_gen = + * cg::build() + * .with_criteria( + * gko::stop::Iteration::build().with_max_iters(20u).on(omp), + * gko::stop::ResidualNormReduction<>::build() + * .with_reduction_factor(1e-6) + * .on(omp)) + * .on(omp); + * auto solver = solver_gen->generate(system_matrix); + * + * solver->apply(lend(rhs), lend(solution)); + * ``` + * + * + * The @p solver_control object is the same as for other + * deal.II iterative solvers. + */ + SolverBase(SolverControl & solver_control, + std::shared_ptr executor); + + /** + * Destructor. + */ + virtual ~SolverBase() = default; + + /** + * Initialize the matrix and copy over its data to Ginkgo's data structures. + */ + void + initialize(const SparseMatrix &matrix); + + /** + * Solve the linear system Ax=b. Dependent on the information + * provided by derived classes one of Ginkgo's linear solvers is + * chosen. + */ + void + apply(Vector &solution, const Vector &rhs); + + /** + * Solve the linear system Ax=b. Dependent on the information + * provided by derived classes one of Ginkgo's linear solvers is + * chosen. + */ + void + solve(const SparseMatrix &matrix, + Vector & solution, + const Vector & rhs); + + /** + * Access to the object that controls convergence. + */ + SolverControl & + control() const; + + + protected: + /** + * Reference to the object that controls convergence of the iterative + * solvers. + */ + SolverControl &solver_control; + + /** + * The Ginkgo generated solver factory object. + */ + std::shared_ptr solver_gen; + + /** + * The residual criterion object that controls the reduction of the residual + * based on the tolerance set in the solver_control member. + */ + std::shared_ptr::Factory> + residual_criterion; + + /** + * The Ginkgo convergence logger used to check for convergence and other + * solver data if needed. + */ + std::shared_ptr> convergence_logger; + + /** + * The Ginkgo combined factory object is used to create a combined stopping + * criterion to be passed to the solver. + */ + std::shared_ptr combined_factory; + + /** + * The execution paradigm in Ginkgo. The choices are between + * `gko::OmpExecutor`, `gko::CudaExecutor` and `gko::ReferenceExecutor` + * and more details can be found in Ginkgo's documentation. + */ + std::shared_ptr executor; + + private: + /** + * Initialize the Ginkgo logger object with event masks. Refer to + * Ginkgo's + * logging event masks. + */ + void + initialize_ginkgo_log(); + + /** + * Ginkgo matrix data structure. First template parameter is for storing the + * array of the non-zeros of the matrix. The second is for the row pointers + * and the column indices. + * + * @todo Templatize based on Matrix type. + */ + std::shared_ptr> system_matrix; + }; + + + /** + * An implementation of the solver interface using the Ginkgo CG solver. + * + * @ingroup GinkgoWrappers + */ + template + class SolverCG : public SolverBase + { + public: + /** + * A standardized data struct to pipe additional data to the solver. + */ + struct AdditionalData + {}; + + /** + * Constructor. + * + * @p solver_control The solver control object is then used to set the + * parameters and setup the CG solver from the CG factory which solves the + * linear system. + * + * @p executor The execution paradigm for the CG solver. + */ + SolverCG(SolverControl & solver_control, + std::shared_ptr executor, + const AdditionalData & data = AdditionalData()); + + protected: + /** + * Store a copy of the settings for this particular solver. + */ + const AdditionalData additional_data; + }; + + +} // namespace GinkgoWrappers + +DEAL_II_NAMESPACE_CLOSE + +# endif // DEAL_II_WITH_GINKGO + +#endif +/*---------------------------- ginkgo_solver.h ---------------------------*/ diff --git a/source/lac/ginkgo_solver.cc b/source/lac/ginkgo_solver.cc new file mode 100644 index 000000000000..b1e08892ee7d --- /dev/null +++ b/source/lac/ginkgo_solver.cc @@ -0,0 +1,313 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +#include +#include + +#include + +#ifdef DEAL_II_WITH_GINKGO + +# include + +# include + + +DEAL_II_NAMESPACE_OPEN + +namespace GinkgoWrappers +{ + template + SolverBase::SolverBase( + SolverControl & solver_control, + std::shared_ptr executor) + : solver_control(solver_control) + , executor(executor) + { + using ResidualCriterionFactory = gko::stop::ResidualNormReduction<>; + residual_criterion = ResidualCriterionFactory::build() + .with_reduction_factor(solver_control.tolerance()) + .on(executor); + + combined_factory = + gko::stop::Combined::build() + .with_criteria(residual_criterion, + gko::stop::Iteration::build() + .with_max_iters(solver_control.max_steps()) + .on(executor)) + .on(executor); + } + + template + void + SolverBase::initialize_ginkgo_log() + { + // Add the logger object. See the different masks available in Ginkgo's + // documentation + convergence_logger = gko::log::Convergence<>::create( + executor, gko::log::Logger::criterion_check_completed_mask); + } + + template + void + SolverBase::apply(Vector & solution, + const Vector &rhs) + { + // some shortcuts. + using val_array = gko::Array; + using vec = gko::matrix::Dense; + + Assert(system_matrix, ExcNotInitialized()); + Assert(executor, ExcNotInitialized()); + Assert(rhs.size() == solution.size(), + ExcDimensionMismatch(rhs.size(), solution.size())); + + // Generate the solver from the solver using the system matrix. + auto solver = solver_gen->generate(system_matrix); + + // Create the rhs vector in Ginkgo's format. + std::vector f(rhs.size()); + std::copy(rhs.begin(), rhs.begin() + rhs.size(), f.begin()); + auto b = + vec::create(executor, + gko::dim<2>(rhs.size(), 1), + val_array::view(executor->get_master(), rhs.size(), f.data()), + 1); + + // Create the solution vector in Ginkgo's format. + std::vector u(solution.size()); + std::copy(solution.begin(), solution.begin() + solution.size(), u.begin()); + auto x = vec::create(executor, + gko::dim<2>(solution.size(), 1), + val_array::view(executor->get_master(), + solution.size(), + u.data()), + 1); + + // Create the logger object to log some data from the solvers to confirm + // convergence. + initialize_ginkgo_log(); + + Assert(convergence_logger, ExcNotInitialized()); + // Add the convergence logger object to the combined factory to retrieve the + // solver and other data + combined_factory->add_logger(convergence_logger); + + // Finally, apply the solver to b and get the solution in x. + solver->apply(gko::lend(b), gko::lend(x)); + + // The convergence_logger object contains the residual vector after the + // solver has returned. use this vector to compute the residual norm of the + // solution. Get the residual norm from the logger. As the convergence + // logger returns a `linop`, it is necessary to convert it to a Dense + // matrix. Additionally, if the logger is logging on the gpu, it is + // necessary to copy the data to the host and hence the + // `residual_norm_d_master` + auto residual_norm = convergence_logger->get_residual_norm(); + auto residual_norm_d = + gko::as>(residual_norm); + auto residual_norm_d_master = + gko::matrix::Dense::create(executor->get_master(), + gko::dim<2>{1, 1}); + residual_norm_d_master->copy_from(residual_norm_d); + + // Get the number of iterations taken to converge to the solution. + auto num_iteration = convergence_logger->get_num_iterations(); + + // Ginkgo works with a relative residual norm through its + // ResidualNormReduction criterion. Therefore, to get the normalized + // residual, we divide by the norm of the rhs. + auto b_norm = gko::matrix::Dense::create(executor->get_master(), + gko::dim<2>{1, 1}); + if (executor != executor->get_master()) + { + auto b_master = vec::create(executor->get_master(), + gko::dim<2>(rhs.size(), 1), + val_array::view(executor->get_master(), + rhs.size(), + f.data()), + 1); + b_master->compute_norm2(b_norm.get()); + } + else + { + b->compute_norm2(b_norm.get()); + } + + Assert(b_norm.get()->at(0, 0) != 0.0, ExcDivideByZero()); + // Pass the number of iterations and residual norm to the solver_control + // object. As both `residual_norm_d_master` and `b_norm` are seen as Dense + // matrices, we use the `at` function to get the first value here. In case + // of multiple right hand sides, this will need to be modified. + const SolverControl::State state = + solver_control.check(num_iteration, + residual_norm_d_master->at(0, 0) / b_norm->at(0, 0)); + + // in case of failure: throw exception + if (state != SolverControl::success) + AssertThrow(false, + SolverControl::NoConvergence(solver_control.last_step(), + solver_control.last_value())); + + // Check if the solution is on a CUDA device, if so, copy it over to the + // host. + if (executor != executor->get_master()) + { + auto x_master = vec::create(executor->get_master(), + gko::dim<2>(solution.size(), 1), + val_array::view(executor, + solution.size(), + x->get_values()), + 1); + x.reset(x_master.release()); + } + // Finally copy over the solution vector to deal.II's solution vector. + std::copy(x->get_values(), + x->get_values() + solution.size(), + solution.begin()); + } + + + template + SolverControl & + SolverBase::control() const + { + return solver_control; + } + + + template + void + SolverBase::initialize( + const SparseMatrix &matrix) + { + // Needs to be a square matrix + Assert(matrix.m() == matrix.n(), ExcNotQuadratic()); + + using size_type = dealii::types::global_dof_index; + const size_type N = matrix.m(); + + using mtx = gko::matrix::Csr; + std::shared_ptr system_matrix_compute; + system_matrix_compute = mtx::create(executor->get_master(), + gko::dim<2>(N), + matrix.n_nonzero_elements()); + ValueType *mat_values = system_matrix_compute->get_values(); + IndexType *mat_row_ptrs = system_matrix_compute->get_row_ptrs(); + IndexType *mat_col_idxs = system_matrix_compute->get_col_idxs(); + + // Copy over the data from the matrix to the data structures Ginkgo needs. + // + // Final note: if the matrix has entries in the sparsity pattern that are + // actually occupied by entries that have a zero numerical value, then we + // keep them anyway. people are supposed to provide accurate sparsity + // patterns. + + // first fill row lengths array + mat_row_ptrs[0] = 0; + for (size_type row = 1; row <= N; ++row) + mat_row_ptrs[row] = + mat_row_ptrs[row - 1] + matrix.get_row_length(row - 1); + + // Copy over matrix elements. note that for sparse matrices, + // iterators are sorted so that they traverse each row from start to end + // before moving on to the next row. however, this isn't true for block + // matrices, so we have to do a bit of book keeping + { + // Have an array that for each row points to the first entry not yet + // written to + std::vector row_pointers(N + 1); + std::copy(system_matrix_compute->get_row_ptrs(), + system_matrix_compute->get_row_ptrs() + N + 1, + row_pointers.begin()); + + // Loop over the elements of the matrix row by row, as suggested in the + // documentation of the sparse matrix iterator class + for (size_type row = 0; row < N; ++row) + { + for (typename SparseMatrix::const_iterator p = + matrix.begin(row); + p != matrix.end(row); + ++p) + { + // Write entry into the first free one for this row + mat_col_idxs[row_pointers[row]] = p->column(); + mat_values[row_pointers[row]] = p->value(); + + // Then move pointer ahead + ++row_pointers[row]; + } + } + + // At the end, we should have written all rows completely + for (size_type i = 0; i < N - 1; ++i) + Assert(row_pointers[i] == mat_row_ptrs[i + 1], ExcInternalError()); + } + system_matrix = + mtx::create(executor, gko::dim<2>(N), matrix.n_nonzero_elements()); + system_matrix->copy_from(system_matrix_compute.get()); + } + + + template + void + SolverBase::solve(const SparseMatrix &matrix, + Vector & solution, + const Vector &rhs) + { + initialize(matrix); + apply(solution, rhs); + } + + + /* ---------------------- SolverCG ------------------------ */ + + template + SolverCG::SolverCG( + SolverControl & solver_control, + std::shared_ptr executor, + const AdditionalData & data) + : SolverBase(solver_control, executor) + , additional_data(data) + { + using cg = gko::solver::Cg; + this->solver_gen = + cg::build().with_criteria(this->combined_factory).on(executor); + } + + // Explicit instantiations in GinkgoWrappers +# define GKO_DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(_macro) \ + template _macro(float, int32_t); \ + template _macro(double, int32_t); \ + template _macro(float, int64_t); \ + template _macro(double, int64_t); + +# define DECLARE_SOLVER_BASE(ValueType, IndexType) \ + class SolverBase + GKO_DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_SOLVER_BASE); +# undef DECLARE_SOLVER_BASE + +# define DECLARE_SOLVER_CG(ValueType, IndexType) \ + class SolverCG + GKO_DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_SOLVER_CG); +# undef DECLARE_SOLVER_CG + +} // namespace GinkgoWrappers + + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_GINKGO From 145821cc0e91951c52f5e3c0f1536f633ebbc8c6 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Wed, 30 Jan 2019 14:20:29 +0100 Subject: [PATCH 036/507] Improve documentation of some functions --- .../deal.II/differentiation/ad/ad_drivers.h | 42 +++++++++++-------- .../deal.II/differentiation/ad/ad_helpers.h | 42 +++++++++++-------- 2 files changed, 50 insertions(+), 34 deletions(-) diff --git a/include/deal.II/differentiation/ad/ad_drivers.h b/include/deal.II/differentiation/ad/ad_drivers.h index 7f76fe846134..cdde7694598e 100644 --- a/include/deal.II/differentiation/ad/ad_drivers.h +++ b/include/deal.II/differentiation/ad/ad_drivers.h @@ -284,7 +284,7 @@ namespace Differentiation * evaluation point. * * This issue, known as "branch switching", can be clarified by means of - * a trivial example: + * a trivial, contrived example: * @code * ADNumberType func (ADNumberType x, ADNumberType y, ADNumberType z) * { @@ -296,13 +296,17 @@ namespace Differentiation * @endcode * During taping, the conditional statement may be either true or * false, and the result (with its sensitivities) returned by - * this function. For some other evaluation of the tape (i.e. for some - * different - * inputs @p x and @p y, the other branch of the conditional check may be - * chosen. The result of following this code path has not been recorded on - * the tape, and therefore cannot be evaluated. In such a case, it is - * therefore necessary to re-record the tape at the new evaluation point - * in order to resolve the new code branch. + * this function. + * The AD library doesn't just record the parse tree of the operations + * applied on the branch chosen at the time to taping, but also checks + * that the condition continues to be satisfied. For some other evaluation + * of the tape (i.e. for some different inputs @p x and @p y), the other + * branch of the conditional check may be chosen. The result of following + * this code path has not been recorded on the tape, and therefore cannot + * be evaluated. In such a case, the underlying AD library will be able to + * tell you that it is necessary to re-record the tape at the new + * evaluation point in order to resolve the new code branch. This function + * can be used to find out whether this is so. * * @note The chosen tape index must be greater than * Numbers::invalid_tape_index and less than @@ -315,13 +319,13 @@ namespace Differentiation /** * Return a flag that, when true, indicates that the retaping * of the dependent function is necessary for a reliable computation to be - * performed on the active tape. + * performed on the currently active tape. * This may be necessary if a sign comparison within branched operations * yields different results to those computed at the original tape * evaluation point. * * This issue, known as "branch switching", can be clarified by means of - * a trivial example: + * a trivial, contrived example: * @code * ADNumberType func (ADNumberType x, ADNumberType y, ADNumberType z) * { @@ -333,13 +337,17 @@ namespace Differentiation * @endcode * During taping, the conditional statement may be either true or * false, and the result (with its sensitivities) returned by - * this function. For some other evaluation of the tape (i.e. for some - * different - * inputs @p x and @p y, the other branch of the conditional check may be - * chosen. The result of following this code path has not been recorded on - * the tape, and therefore cannot be evaluated. In such a case, it is - * therefore necessary to re-record the tape at the new evaluation point - * in order to resolve the new code branch. + * this function. + * The AD library doesn't just record the parse tree of the operations + * applied on the branch chosen at the time to taping, but also checks + * that the condition continues to be satisfied. For some other evaluation + * of the tape (i.e. for some different inputs @p x and @p y), the other + * branch of the conditional check may be chosen. The result of following + * this code path has not been recorded on the tape, and therefore cannot + * be evaluated. In such a case, the underlying AD library will be able to + * tell you that it is necessary to re-record the tape at the new + * evaluation point in order to resolve the new code branch. This function + * can be used to find out whether this is so. */ bool last_action_requires_retaping() const; diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index f5cb753260e4..ff94ee962f1b 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -487,7 +487,7 @@ namespace Differentiation * evaluation point. * * This issue, known as "branch switching", can be clarified by means of - * a trivial example: + * a trivial, contrived example: * @code * ADNumberType func (ADNumberType x, ADNumberType y, ADNumberType z) * { @@ -499,13 +499,17 @@ namespace Differentiation * @endcode * During taping, the conditional statement may be either true or * false, and the result (with its sensitivities) returned by - * this function. For some other evaluation of the tape (i.e. for some - * different - * inputs @p x and @p y, the other branch of the conditional check may be - * chosen. The result of following this code path has not been recorded on - * the tape, and therefore cannot be evaluated. In such a case, it is - * therefore necessary to re-record the tape at the new evaluation point - * in order to resolve the new code branch. + * this function. + * The AD library doesn't just record the parse tree of the operations + * applied on the branch chosen at the time to taping, but also checks + * that the condition continues to be satisfied. For some other evaluation + * of the tape (i.e. for some different inputs @p x and @p y), the other + * branch of the conditional check may be chosen. The result of following + * this code path has not been recorded on the tape, and therefore cannot + * be evaluated. In such a case, the underlying AD library will be able to + * tell you that it is necessary to re-record the tape at the new + * evaluation point in order to resolve the new code branch. This function + * can be used to find out whether this is so. * * For the output of this function to be meaningful, it must be called * after activate_recorded_tape() is called and the new evaluation @@ -520,13 +524,13 @@ namespace Differentiation /** * Return a flag that, when true, indicates that the * retaping of the dependent function is necessary for a reliable - * computation to be performed on the active tape. + * computation to be performed on the currently active tape. * This may be necessary if a sign comparison within branched operations * yields different results to those computed at the original tape * evaluation point. * * This issue, known as "branch switching", can be clarified by means of - * a trivial example: + * a trivial, contrived example: * @code * ADNumberType func (ADNumberType x, ADNumberType y, ADNumberType z) * { @@ -538,13 +542,17 @@ namespace Differentiation * @endcode * During taping, the conditional statement may be either true or * false, and the result (with its sensitivities) returned by - * this function. For some other evaluation of the tape (i.e. for some - * different - * inputs @p x and @p y, the other branch of the conditional check may be - * chosen. The result of following this code path has not been recorded on - * the tape, and therefore cannot be evaluated. In such a case, it is - * therefore necessary to re-record the tape at the new evaluation point - * in order to resolve the new code branch. + * this function. + * The AD library doesn't just record the parse tree of the operations + * applied on the branch chosen at the time to taping, but also checks + * that the condition continues to be satisfied. For some other evaluation + * of the tape (i.e. for some different inputs @p x and @p y), the other + * branch of the conditional check may be chosen. The result of following + * this code path has not been recorded on the tape, and therefore cannot + * be evaluated. In such a case, the underlying AD library will be able to + * tell you that it is necessary to re-record the tape at the new + * evaluation point in order to resolve the new code branch. This function + * can be used to find out whether this is so. * * For the output of this function to be meaningful, it must be called * after activate_recorded_tape() is called and the new evaluation From a7cbf3c0ade5dee64c5849b450e37e2235bc281f Mon Sep 17 00:00:00 2001 From: Pratik Nayak Date: Wed, 30 Jan 2019 16:20:39 +0100 Subject: [PATCH 037/507] Add changelog entry and fix a typo. --- doc/news/changes/major/20190130ginkgo-developers | 7 +++++++ doc/readme.html | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 doc/news/changes/major/20190130ginkgo-developers 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/readme.html b/doc/readme.html index 406981e5f710..9d7cf59ead41 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -430,7 +430,7 @@

Optional interfaces to other software packages

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) + 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 From ad3df66bb2f18e4582bfe07eaba4a459e39d3999 Mon Sep 17 00:00:00 2001 From: Zhuoran Wang Date: Fri, 27 Apr 2018 16:31:49 +0000 Subject: [PATCH 038/507] Add step-61. This tutorial program adds a code that solves the Poisson equation using the weak Galerkin formulation. --- examples/step-61/CMakeLists.txt | 39 + examples/step-61/doc/builds-on | 1 + examples/step-61/doc/intro.dox | 279 ++++++ examples/step-61/doc/kind | 1 + examples/step-61/doc/results.dox | 88 ++ examples/step-61/doc/step-61.wg000_2d_2.png | Bin 0 -> 7590 bytes examples/step-61/doc/step-61.wg000_2d_4.png | Bin 0 -> 21571 bytes examples/step-61/doc/step-61.wg000_3d_2.png | Bin 0 -> 9996 bytes examples/step-61/doc/step-61.wg000_3d_4.png | Bin 0 -> 40641 bytes examples/step-61/doc/step-61.wg111_2d_4.png | Bin 0 -> 114303 bytes examples/step-61/doc/step-61.wg111_3d_4.png | Bin 0 -> 118587 bytes examples/step-61/doc/step-61.wg222_2d_5.png | Bin 0 -> 136893 bytes examples/step-61/doc/step-61.wg222_3d_5.png | Bin 0 -> 220122 bytes examples/step-61/doc/tooltip | 1 + examples/step-61/step-61.cc | 915 ++++++++++++++++++++ 15 files changed, 1324 insertions(+) create mode 100644 examples/step-61/CMakeLists.txt create mode 100644 examples/step-61/doc/builds-on create mode 100644 examples/step-61/doc/intro.dox create mode 100644 examples/step-61/doc/kind create mode 100644 examples/step-61/doc/results.dox create mode 100644 examples/step-61/doc/step-61.wg000_2d_2.png create mode 100644 examples/step-61/doc/step-61.wg000_2d_4.png create mode 100644 examples/step-61/doc/step-61.wg000_3d_2.png create mode 100644 examples/step-61/doc/step-61.wg000_3d_4.png create mode 100644 examples/step-61/doc/step-61.wg111_2d_4.png create mode 100644 examples/step-61/doc/step-61.wg111_3d_4.png create mode 100644 examples/step-61/doc/step-61.wg222_2d_5.png create mode 100644 examples/step-61/doc/step-61.wg222_3d_5.png create mode 100644 examples/step-61/doc/tooltip create mode 100644 examples/step-61/step-61.cc diff --git a/examples/step-61/CMakeLists.txt b/examples/step-61/CMakeLists.txt new file mode 100644 index 000000000000..83a33d091ac2 --- /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.0.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..f5ca096683c0 --- /dev/null +++ b/examples/step-61/doc/intro.dox @@ -0,0 +1,279 @@ +
+ + +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 large number of degrees of freedom (because, for +example, each vertex carries as many degrees of freedom as there are adjacent cells). +We also have to address the fact that, in general, 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 shape functions for these cell degrees of freedom are +discontinuous and only "live" on exactly one cell. + +For a given equation, say the second order Poisson equation, +the difference between the HDG and the WG method is how exactly one formulates +the problem that connects all of these different shape functions. 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. +It was 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., 2013, 103-115. +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 expected convergence rates can +be obtained with mesh refinement. + + +

WGFEM applied to the Poisson equation

+This program solves the Poisson equation +using the weak Galerkin finite element method: +@f{eqnarray*} + \nabla \cdot \left( -\mathbf{K} \nabla p \right) + = f, + \quad \mathbf{x} \in \Omega, \\ + p = p_D,\quad \mathbf{x} \in \Gamma^D, \\ + \mathbf{u} \cdot \mathbf{n} = u_N, + \quad \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)\sin(\pi y \right)$ on the unit square domain, +with homogenous Dirichelet boundary conditions and identity matrix $\mathbf{K}$. +Then we will calculate $L_2$ errors of pressure, velocity and flux. + + +

Weak Galerkin scheme

+ +Via integration by parts, the weak Galerkin scheme for the Poisson equation is +@f{equation*} +\mathcal{A}_h\left(p_h,q \right) = \mathcal{F} \left(q \right), +@f} +where +@f{equation*} +\mathcal{A}_h\left(p_h,q\right) + := \sum_{T \in \mathcal{T}_h} + \int_T \mathbf{K} \nabla_{w,d} p_h \cdot \nabla_{w,d} q \mathrm{d}x, +@f} +and +@f{equation*} +\mathcal{F}\left(q\right) + := \sum_{T \in \mathcal{T}_h} \int_T f \, q^\circ \mathrm{d}x + - \sum_{\gamma \in \Gamma_h^N} \int_\gamma u_N q^\partial \mathrm{d}x, +@f} +$q^\circ$ is the shape function of the polynomial space in the interior, +$q^\partial$ is the shape function of the polynomial space on faces, $ \nabla_{w,d} $ means the discrete weak gradient used to approximate the classical gradient. +We use FE_DGQ as the interior polynomial space, +FE_FaceQ as the face polynomial space, and Raviart-Thomas elements for the velocity +$\mathbf{u} = -{\mathbf{K}} \nabla_{w,d} p$. + +

Assembling the linear system

+ +First, we solve for the pressure. +We collect two local spaces together in one FESystem, +the first component in this finite element system denotes +the space for interior pressure, and the second denotes +the space for face pressure. +For the interior component, we use the polynomial space FE_DGQ. +For the face component, we use FE_FaceQ. + +We use shape functions defined on spaces FE_DGQ and FE_FaceQ to +approximate pressures, i.e., $p_h = \sum a_i \phi_i,$ +where $\phi_i$ are shape functions of FESystem. +We construct the local system by using discrete weak gradients of +shape functions of FE_DGQ and FE_FaceQ. +The discrete weak gradients of shape functions $\nabla_{w,d} \phi$ are defined as +$\nabla_{w,d} \phi = \sum_{i=1}^m c_i \mathbf{w}_i,$ +where $\mathbf{w}_i$ is the basis function of $RT(k)$. + +Using integration by parts, we have a small linear system +on each element $T$, +@f{equation*} +\int_{T} \left(\nabla_{w,d} \phi \right) \cdot \mathbf{w} \mathrm{d}x= +\int_{T^\partial} \phi^{\partial} \left(\mathbf{w} \cdot \mathbf{n}\right) \mathrm{d}x- +\int_{T^\circ} \phi^{\circ} \left(\nabla \cdot \mathbf{w}\right) \mathrm{d}x, +\quad \forall \mathbf{w} \in RT_{[k]}(E), +@f} + +@f{equation*} +\sum_{i=1}^m c_i \int_T \mathbf{w}_i \cdot \mathbf{w}_j \mathrm{d}x = +\int_{T^{\partial}} \phi_i^{\partial} +\left(\mathbf{w}_j \cdot \mathbf{n} \right) \mathrm{d}x - +\int_{T^{\circ}} \phi_i^{\circ} \left (\nabla \cdot \mathbf{w}_j \right)\mathrm{d}x, +@f} +which can be simplified to be +@f{equation*} +\mathbf{C}_{E}\mathbf{M}_{E} = \mathbf{F}_{E}, +@f} +where $\mathbf{C}_E$ is the matrix with unknown coefficients $c$, +$\mathbf{M}_E$ is the Gram matrix +$\left[ \int_T \mathbf{w}_i \cdot \mathbf{w}_j \right] \mathrm{d}x$, +$\mathbf{F}_E$ is the matrix of right hand side, +$\mathbf{w}$ and $\phi_i^{\circ}$ are in FEValues, +$\phi_i^{\partial}$ is in FEFaceValues. +Then we solve for $\mathbf{C}_E = \mathbf{F}_E \mathbf{M}_E^{-1}$. +Now, discrete weak gradients of shape functions are written as +linear combinations of basis functions of the $RT$ space. +In our code, we name $\mathbf{C}_E$ as cell_matrix_C, +$\mathbf{M}_E$ as cell_matrix_rt, +$\mathbf{F}_E$ as cell_matrix_F. + +The components of the local cell matrices $\mathbf{A}$ are +@f{equation*} +\mathbf{A}_{ij} = +\int_{T} \mathbf{K} \nabla_{w,d} \phi_i \cdot \nabla_{w,d} \phi_j \mathrm{d}x. +@f} +From previous steps, we know $\nabla_{w,d} \phi_i = \sum_{k=1}^m c_{ik} \mathbf{w}_k,$ +and $\nabla_{w,d} \phi_j = \sum_{l=1}^m c_{jl} \mathbf{w}_l.$ +Then combining the coefficients we have calculated, components of $\mathbf{A}$ are calculated as +@f{equation*} +\int_T \sum_{k,l = 1}^{m}c_{ik} c_{jl} \left(\mathbf{K} \mathbf{w}_i \cdot \mathbf{w}_j\right) \mathrm{d}x += \sum_{k,l = 1}^{m}c_{ik} c_{jl} \int_{T} \mathbf{K} \mathbf{w}_i \cdot \mathbf{w}_j \mathrm{d}x. +@f} + +Next, we use ConstraintMatrix::distribute_local_to_global to +distribute contributions from local matrices $\mathbf{A}$ to the system matrix. + +In the scheme +$\mathcal{A}_h\left(p_h,q \right) = \mathcal{F} \left( q \right),$ +we have system matrix and system right hand side, +we can solve for the coefficients of the system matrix. +The solution vector of the scheme represents the pressure values in interiors and on faces. + +

Post-processing and $L_2$-errors

+ +After we have calculated the numerical pressure $p$, +we use discrete weak gradients of $p$ to calculate the velocity on each element. + +On each element the gradient of the numerical pressure $\nabla p$ can be +approximated by discrete weak gradients $ \nabla_{w,d}\phi_i$, so +@f{equation*} +\nabla_{w,d} p_h = \sum_{i} a_i \nabla_{w,d}\phi_i. +@f} + +The numerical velocity $ \mathbf{u}_h = -\mathbf{K} \nabla_{w,d}p_h$ can be written as +@f{equation*} +\mathbf{u}_h = -\mathbf{K} \nabla_{w,d} p = +-\sum_{i} \sum_{j} a_ic_{ij}\mathbf{K}\mathbf{w}_j, +@f} +where $c_{ij}$ is the coefficient of Gram matrix, +$\mathbf{w}_j$ is the basis function of the $RT$ space. +$\mathbf{K} \mathbf{w}_j$ may not be in the $RT$ space. +So we need $L_2$-projection to project it back to the $RT$ space. + +We define the projection as +$ \mathbf{Q}_h \left( \mathbf{K}\mathbf{w}_j \right) = +\sum_{k} d_{jk}\mathbf{w}_k$. +For any $j$, +$\left( \mathbf{Q}_h \left( \mathbf{Kw}_j \right),\mathbf{w}_k \right)_E = +\left( \mathbf{Kw}_j,\mathbf{w}_k \right)_E.$ +So the numerical velocity becomes +@f{equation*} +\mathbf{u}_h = \mathbf{Q}_h \left( -\mathbf{K}\nabla_{w,d}p_h \right) = +-\sum_{i=0}^{4} \sum_{j=1}^{4}a_ib_{ij}\mathbf{Q}_h \left( \mathbf{K}\mathbf{w}_j \right), +@f} +and we have the following system to solve for the coefficients $d_{jk}$, +@f{equation*} + \left[ + \begin{matrix} + \left(\mathbf{w}_i,\mathbf{w}_j \right) + \end{matrix} + \right] + \left[ + \begin{matrix} + d_{jk} + \end{matrix} + \right] + = + \left[ + \begin{matrix} + \left( \mathbf{Kw}_j,\mathbf{w}_k \right) + \end{matrix} + \right]. +@f} +$ + \left[ + \begin{matrix} + d_{jk} + \end{matrix} + \right] +$ +is named cell_matrix_D, +$ +\left[ + \begin{matrix} + \left( \mathbf{Kw}_j,\mathbf{w}_k \right) + \end{matrix} + \right] +$ +is named cell_matrix_E. + +Then the elementwise velocity is +@f{equation*} +\mathbf{u}_h = -\sum_{i} \sum_{j}a_ic_{ij}\sum_{k}d_{jk}\mathbf{w}_k = +\sum_{k}- \left(\sum_{j} \sum_{i} a_ic_{ij}d_{jk} \right)\mathbf{w}_k, +@f} +where $-\sum_{j} \sum_{i} a_ic_{ij}d_{jk}$ is named +beta in the code. + +We calculate the $L_2$-errors of pressure, velocity and flux +by the following formulas, +@f{eqnarray*} +\|p-p_h^\circ\|^2 + = \sum_{T \in \mathcal{T}_h} \|p-p_h^\circ\|_{L^2(E)}^2, \\ + \|\mathbf{u}-\mathbf{u}_h\|^2 + = \sum_{T \in \mathcal{T}_h} \|\mathbf{u}-\mathbf{u}_h\|_{L^2(E)^2}^2,\\ +\|(\mathbf{u}-\mathbf{u}_h) \cdot \mathbf{n}\|^2 + = \sum_{T \in \mathcal{T}_h} \sum_{\gamma \subset T^\partial} + \frac{|T|}{|\gamma|} \|\mathbf{u} \cdot \mathbf{n} - \mathbf{u}_h \cdot \mathbf{n}\|_{L^2(\gamma)}^2, +@f} +where $| T |$ is the area of the element, +$\gamma$ are faces of the element, +$\mathbf{n}$ are unit normal vectors of each face. + +We will extract interior pressure solutions of each cell +from the global solution and calculate the $L_2$ error +by using function VectorTools::integrate_difference. 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..b71c57abb177 --- /dev/null +++ b/examples/step-61/doc/results.dox @@ -0,0 +1,88 @@ +

Results

+ +We run the test example $p = \sin(\pi x) \sin(\pi y)$ with homogenous Dirichelet boundary conditions in the domain $\Omega = (0,1)^2$. And $\mathbf{K}$ is the identity matrix. We test it on $\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]})$. We will visualize pressure values in interiors and on faces. We want to see the pressure maximum is around 1 and the minimum is around 0. With the mesh refinement, the convergence rates of pressure, velocity and flux should be around 1 on $\mbox{WG}(Q_0,Q_0;RT_{[0]})$ , 2 on $\mbox{WG}(Q_1,Q_1;RT_{[1]})$, and 3 on $\mbox{WG}(Q_2,Q_2;RT_{[2]})$. + +

Test results on $\mbox{WG}(Q_0,Q_0;RT_{[0]})$

+The following figures are interior pressures and face pressures implemented on $\mbox{WG}(Q_0,Q_0;RT_{[0]})$. The mesh is refined 2 times and 4 times separately. + + + + + + + + + + +
+ +From the figures, we can see that with the mesh refinement, the maximum and minimum are approaching to what we expect. +Since the mesh is a rectangular mesh and numbers of refinement are even, we have symmetric solutions. From the 3d figures, we can see that on $\mbox{WG}(Q_0,Q_0;RT_{[0]})$, pressure is a constant in the interior of the cell. + +

Convergence table

+ +We run the code with finer meshes and get the following convergence rates of pressure, +velocity and flux. + +@code +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 +@endcode +We can see that the convergence rates of $\mbox{WG}(Q_0,Q_0;RT_{[0]})$ are around 1. + + +

Test results on $\mbox{WG}(Q_1,Q_1;RT_{[1]})$

+ +The following figures are interior pressures and face pressures implemented on $\mbox{WG}(Q_1,Q_1;RT_{[1]})$. The mesh is refined 4 times. Compared to the previous figures on +$\mbox{WG}(Q_0,Q_0;RT_{[0]})$, on each cell, the result is not a constant. Because we use higher order polynomials to do approximation. So there are 4 pressure values in one interior, 2 pressure values on each face. We use data_out_face.build_patches (fe.degree) +to divide each cell interior into 4 subcells. + + + + + + +
+ +

Convergence table

+ +These are the convergence rates of pressure, velocity and flux on $\mbox{WG}(Q_1,Q_1;RT_{[1]})$ + +@code +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 +@endcode +The convergence rates of $WG(Q_1,Q_1;RT_{[1]})$ are around 2. + +

Test results on $WG(Q_2,Q_2;RT_{[2]})$

+ +These are interior pressures and face pressures implemented on $WG(Q_2,Q_2;RT_{[2]})$, with mesh size $h = 1/32$. + + + + + + +
+ +

Convergence table

+ +This is the convergence table of $L_2$ errors of pressure, velocity and flux on $\mbox{WG}(Q_2,Q_2;RT_{[2]})$ + +@code +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 +@endcode +The convergence rates of $\mbox{WG}(Q_2,Q_2;RT_{[2]})$ are around 3. diff --git a/examples/step-61/doc/step-61.wg000_2d_2.png b/examples/step-61/doc/step-61.wg000_2d_2.png new file mode 100644 index 0000000000000000000000000000000000000000..bf3be238e6caf7398be7df1c0ef2d9ebe5d0edbd GIT binary patch literal 7590 zcmeHMYfzI{8a`ZQxJQ@579VBuh-{;F#40 zaUr{;S8d1|(M4-#|13}oM!G6ZdZzNhwRpu3qdL`TZ3P&9#GX!hqKkTePAOoTjbf{D z{MW{7bn9rhb*hnPMLq=ZjFn>U6aB!>1No}V?;qAFG%m((_YbuRN_~B4Zf^a0<-@oKVe&ooqGBdWSE2 zyS?-l`0+#LvOpT>*|>jfISr(qiyK}CPV8ZByV?`DE-nJzgh1nZK977#(}uZ3KJwjp z@#<_ATsshebGNwu5e&f3A6N4&86Uv4RO~}*e(G;uasD!Y>k5AJfXpQo3D6Qob9?=2 z4<7(l?o1&-;@QJoHZJvs`8?&SZC9mT79qmDlZd?OBFoYDr{B zJcQ^a)QE`f0pJ%%o{wcTeLRvV>yG<%{nVR8q8T-ou#{97xl!cLa79*1^2D-d?a(oTgcR}nX^a8A~xkLx0@xNOcL==we^%v)%laEn+ z?}zMGxEq#XHj=~2m8m!+9Bm;C(3jX?(<&BUxOD}(RnGzx8q@vFs|ZY3Vd*maMYLlP zC<1gL7^8$pi;DsWS|$b}b>&E2j&x~9s*mL}t6k?cBEf=_P{0y9;?9Vf|?_~Pxvaf?k6|j7+D4z7*CL_ z1bU7LczR+_C;WeB}NW#(Ycmi7qt1y*)h^U{1M^t1OI2}m7 z{38KJgtHtJ1P=pe&#Ea}{_9m3J7m-Vu&B8y5W?t&n;L*X3UWzCjdl#Z{8N;(bQRPJ z*?Krc+85tMU;A_Qq_8o`=|l_J+MV1-0#P;sBz7M;{2>m-ZZmr@u#$%c&P)VGNW^+P z?Mj5{Ff>tV+ID6*Uy7t>JUWDPa2TU79J!b)zp!t(uvT1G**!fuSzyo=jCT1vUb$cX zNpgu+X4u8$+*0{8Sc7tAZ_^u-Z%Z2#*QA2kp?8YrCo9@bCG!j(Gt6H-TfiB+6g6R# zTkenQCVwa97{BeRO6Cp*Wjz_*In<~8Cg-2C#m0vtrr6ocKMYn$3bY5AN?mq`R==Y) z_qFiK`aVs;fTpOubL_a;a$w`9Y4wKEfrk4@rt5~r`Mv7mqUo25H(fLiMNLe`JhqsI zx2l=4JkzE1{o=nSgb$fxp%iJG)JeR6_z~~gK$k)KO{L-dqhh^Y*_9Af+s*l6Kew*?h9W?4#ncr> zKcw6KTKCky&77n+{#R7SF^sz!m$!6>`wJ!xu=4^UX7p;YbylvGlztLq{z&exo;OWs zLjBwYS7f|-L$TtXRrjG3a$EK$iHBE++A_HBgZFSf3cyyxD9jZ;RSujdjxC3h(&-UO zN}7c#hTq)wxescDNb%(4N~+$W9QPDG=}b-8{J~;JhDA$N+0IUHsY*W(3B)%r$7B-u zqh2hrHcb}eVoXKUE@I_eF{S)-CJU-d1`wiV4Hpqmz~bi2CL$a;3S9NYYF7V*YF?;3 zaUtPQ&{7;Bp{_8+hGzhYI>b>*T!GUH5+ZrAsz4oI zWEm+m8Ua}3RP98rqoQ|zg~~kWc`zA6k(G85jf~x9v-$bvQ^|~(LTF3jDUag>%1j(5 zqy%>4xy>SfLU5tr(3LlWK-4JVkweLE^hUHhViDE=d@Qg?;ZYqbwV^0W+eDygcHHedGIm692pl<_ED$o5I_9ur3o2eus`SS3<;EVYRch1fbE<%@ z9GzScL8^SF2%e$dNmJa}41JgDf|-OpqY$^Ez{ITbv);mQM!h&TMseCkh=jJ;HAD0u zx`%LrL$rY%HW!#wYzl$Qe4fE`_uMlF#vv`(v?0p{vo#4t_?X3+@kB-sC}QoYaskL? zI3N+{KEh5)?r=|TLY%y|&da*}ET#U0zU0oCNW` zZ9Eu7*2mU8B4KE|v(z2VC!E{#15`Cj?|=W)2nTP5-FQdpJ3KX!^e! zQ8tKs8?0*3-_N-f-~V;l5uQ9g&-5|0CW$#QYB=m1pVW(GyxYprX!v&WN^7SgA-s-$ zYBu?S)Ow^QSjPEn)s@P0NfbIY6}}hnRRHgDv$or+tfyNw13PucdGjisMJ}FKA|JFo z+QyaK3>Y;^>A0l26@8kRO>2@L-~-64{aH$jIbwg#A24QVPwwzh`d% literal 0 HcmV?d00001 diff --git a/examples/step-61/doc/step-61.wg000_2d_4.png b/examples/step-61/doc/step-61.wg000_2d_4.png new file mode 100644 index 0000000000000000000000000000000000000000..fe5e5bc9ff73f1314c5144bc729e80142692a506 GIT binary patch literal 21571 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 EA7~Kn!TNoymEwlY09A0sx)cP2 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 WG{tuJ@8jgG-ehWRa{oV%)Bg|J3Bq## literal 0 HcmV?d00001 diff --git a/examples/step-61/doc/step-61.wg111_2d_4.png b/examples/step-61/doc/step-61.wg111_2d_4.png new file mode 100644 index 0000000000000000000000000000000000000000..23258e0b02defbdf37c9d586e30519039396b6ef GIT binary patch literal 114303 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 F%n;zp>S`o1 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 z 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%0DD|Tv_ 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

ebw20>d$G2`uHOXjFJMoaYNWQb+W$jb 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°Krf_+whC=gWD!QX?^|Jdab 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 +#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 + +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; +}; + +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; +}; + +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(); +} + +// @sect3{The main function} + +// This is the main function. We can change the dimension here to run in 3d. +int main() +{ + deallog.depth_console(2); + WGDarcyEquation<2> WGDarcyEquationTest; + WGDarcyEquationTest.run(); + + return 0; +} From fc4d48b4ca8a7bd66098c0ef8c589dbb4c4eb5b8 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Fri, 25 Jan 2019 22:18:17 +0100 Subject: [PATCH 039/507] Add internal::MatrixFreeFunctions::DoFInfo::get_dof_indices_on_cell_batch() --- .../images/dofinfo_get_dof_indices.png | Bin 0 -> 6257 bytes doc/news/changes/minor/20190130DenisDavydov | 4 + include/deal.II/matrix_free/dof_info.h | 24 ++ .../deal.II/matrix_free/dof_info.templates.h | 67 ++++++ tests/matrix_free/dof_info_01.cc | 203 +++++++++++++++++ ...h_mpi=true.with_p4est=true.mpirun=1.output | 34 +++ tests/matrix_free/dof_info_02.cc | 205 ++++++++++++++++++ ...h_mpi=true.with_p4est=true.mpirun=1.output | 34 +++ 8 files changed, 571 insertions(+) create mode 100644 doc/doxygen/images/dofinfo_get_dof_indices.png create mode 100644 doc/news/changes/minor/20190130DenisDavydov create mode 100644 tests/matrix_free/dof_info_01.cc create mode 100644 tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output create mode 100644 tests/matrix_free/dof_info_02.cc create mode 100644 tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output 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 0000000000000000000000000000000000000000..8366cacc63304bf9d7684113dca14ee7c87603d7 GIT binary patch literal 6257 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 Ja)qY>{{fV@wLbs= literal 0 HcmV?d00001 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/include/deal.II/matrix_free/dof_info.h b/include/deal.II/matrix_free/dof_info.h index 6839cd1d353d..8f80cf23342c 100644 --- a/include/deal.II/matrix_free/dof_info.h +++ b/include/deal.II/matrix_free/dof_info.h @@ -102,6 +102,30 @@ namespace internal fe_index_from_degree(const unsigned int first_selected_component, const unsigned int fe_degree) const; + /** + * Populate the vector @p locall_indices with locally owned degrees of freedom + * stored on the cell block @p cell. + * If @p with_constraints is `true`, then the returned vector will contain indices + * required to resolve constraints. + * + * The image below illustrates the output of this function for cell blocks + * zero and one with zero Dirichlet boundary conditions at the bottom of + * the domain. Note that due to the presence of constraints, the DoFs + * returned by this function for the case `with_constraints = true` are + * not a simple union + * of per cell DoFs on the cell block @p cell. + * + * @image html dofinfo_get_dof_indices.png + * + * @note The returned indices may contain duplicates. The unique set can be + * obtain using `std::sort()` followed by `std::unique()` and + * `std::vector::erase()`. + */ + void + get_dof_indices_on_cell_batch(std::vector &locall_indices, + const unsigned int cell, + const bool with_constraints = true) const; + /** * This internal method takes the local indices on a cell and fills them * into this class. It resolves the constraints and distributes the diff --git a/include/deal.II/matrix_free/dof_info.templates.h b/include/deal.II/matrix_free/dof_info.templates.h index 153e6a8236fc..a2a7c6ae68f9 100644 --- a/include/deal.II/matrix_free/dof_info.templates.h +++ b/include/deal.II/matrix_free/dof_info.templates.h @@ -183,6 +183,73 @@ namespace internal + void + DoFInfo::get_dof_indices_on_cell_batch(std::vector &my_rows, + const unsigned int cell, + const bool apply_constraints) const + { + const unsigned int n_fe_components = start_components.back(); + const unsigned int fe_index = + dofs_per_cell.size() == 1 ? 0 : cell_active_fe_index[cell]; + const unsigned int dofs_this_cell = dofs_per_cell[fe_index]; + + const unsigned int n_vectorization = vectorization_length; + constexpr auto dof_access_index = dof_access_cell; + AssertIndexRange(cell, + n_vectorization_lanes_filled[dof_access_index].size()); + const unsigned int n_vectorization_actual = + n_vectorization_lanes_filled[dof_access_index][cell]; + + // we might have constraints, so the final number + // of indices is not known a priori. + // conservatively reserve the maximum without constraints + my_rows.reserve(n_vectorization * dofs_this_cell); + my_rows.resize(0); + unsigned int total_size = 0; + for (unsigned int v = 0; v < n_vectorization_actual; ++v) + { + const unsigned int ib = + (cell * n_vectorization + v) * n_fe_components; + const unsigned int ie = + (cell * n_vectorization + v + 1) * n_fe_components; + + // figure out constraints by comparing constraint_indicator row + // shift for this cell within the block as compared to the next + // one + const bool has_constraints = + row_starts[ib].second != row_starts[ib + n_fe_components].second; + + auto do_copy = [&](const unsigned int *begin, + const unsigned int *end) { + const unsigned int shift = total_size; + total_size += (end - begin); + my_rows.resize(total_size); + std::copy(begin, end, my_rows.begin() + shift); + }; + + if (!has_constraints || apply_constraints) + { + const unsigned int *begin = + dof_indices.data() + row_starts[ib].first; + const unsigned int *end = + dof_indices.data() + row_starts[ie].first; + do_copy(begin, end); + } + else + { + Assert(row_starts_plain_indices[cell * n_vectorization + v] != + numbers::invalid_unsigned_int, + ExcNotInitialized()); + const unsigned int *begin = + plain_dof_indices.data() + + row_starts_plain_indices[cell * n_vectorization + v]; + const unsigned int *end = begin + dofs_this_cell; + do_copy(begin, end); + } + } + } + + template void DoFInfo ::read_dof_indices( diff --git a/tests/matrix_free/dof_info_01.cc b/tests/matrix_free/dof_info_01.cc new file mode 100644 index 000000000000..462abcac7880 --- /dev/null +++ b/tests/matrix_free/dof_info_01.cc @@ -0,0 +1,203 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + + +// Tests DoFInfo::get_dof_indices() + +#include + +#include +#include + +#include + +#include +#include + +#include + +#include + +#include + +#include + +#include "../tests.h" + + + +template +void +test(const bool adaptive_ref = true) +{ + MPI_Comm mpi_communicator(MPI_COMM_WORLD); + const unsigned int this_mpi_core = + dealii::Utilities::MPI::this_mpi_process(mpi_communicator); + + parallel::distributed::Triangulation tria(mpi_communicator); + GridGenerator::hyper_cube(tria, 0, 1, true); + tria.refine_global(1); + if (adaptive_ref) + { + for (auto cell : tria.active_cell_iterators()) + if (cell->is_locally_owned()) + if (cell->center().norm() < 0.5) + cell->set_refine_flag(); + tria.execute_coarsening_and_refinement(); + for (auto cell : tria.active_cell_iterators()) + if (cell->is_locally_owned()) + if (cell->center()[0] < 0.2) + cell->set_refine_flag(); + tria.execute_coarsening_and_refinement(); + } + else + { + tria.refine_global(1); + } + + FE_Q fe(fe_degree); + DoFHandler dof(tria); + dof.distribute_dofs(fe); + + IndexSet owned_set = dof.locally_owned_dofs(); + IndexSet relevant_set; + DoFTools::extract_locally_relevant_dofs(dof, relevant_set); + + AffineConstraints constraints(relevant_set); + DoFTools::make_hanging_node_constraints(dof, constraints); + // constrain bottom part of the boundary (lower in y direction) + VectorTools::interpolate_boundary_values(dof, + 2, + Functions::ZeroFunction(), + constraints); + constraints.close(); + + deallog << "Testing " << dof.get_fe().get_name() << std::endl; + + std::shared_ptr> mf_data( + new MatrixFree()); + { + const QGauss<1> quad(fe_degree + 1); + typename MatrixFree::AdditionalData data; + data.tasks_parallel_scheme = MatrixFree::AdditionalData::none; + data.tasks_block_size = 7; + mf_data->reinit(dof, constraints, quad, data); + } + + const unsigned int n_cells = mf_data->n_macro_cells(); + const auto & dof_info = mf_data->get_dof_info(); + constexpr unsigned int n_vectorization = + VectorizedArray::n_array_elements; + + std::vector my_rows; + my_rows.reserve(fe.dofs_per_cell * n_vectorization); + + constexpr auto dof_access_index = + internal::MatrixFreeFunctions::DoFInfo::dof_access_cell; + + bool checked_interleaved = false; + for (unsigned int cell = 0; cell < n_cells; ++cell) + { + deallog << "Cell: " << cell << std::endl; + checked_interleaved |= + (dof_info.index_storage_variants[dof_access_index][cell] == + internal::MatrixFreeFunctions::DoFInfo::IndexStorageVariants:: + interleaved); + auto get_and_log = [&](const bool apply_constraints) { + dof_info.get_dof_indices_on_cell_batch(my_rows, + cell, + apply_constraints); + // sort and make unique to make visual inspection easier: + std::sort(my_rows.begin(), my_rows.end()); + my_rows.erase(std::unique(my_rows.begin(), my_rows.end()), + my_rows.end()); + for (auto el : my_rows) + deallog << " " << el; + deallog << std::endl; + }; + get_and_log(true); + get_and_log(false); + } + + // if we don't have adaptive refinement, we should have + // some cells interleaved (at least that is the intention of this + // part of the test) + Assert(checked_interleaved || adaptive_ref, ExcInternalError()); + + // output in Gnuplot + if (dim == 2) + { + std::map> support_points; + MappingQ1 mapping; + DoFTools::map_dofs_to_support_points(mapping, dof, support_points); + + const std::string prefix = + std::is_same::value ? "float_" : "double_"; + const std::string href = (adaptive_ref ? "" : "global_"); + const std::string base_filename = + prefix + href + "grid" + dealii::Utilities::int_to_string(dim) + "_" + + dealii::Utilities::int_to_string(fe_degree) + "_p" + + dealii::Utilities::int_to_string(this_mpi_core); + + const std::string filename = base_filename + ".gp"; + std::ofstream f(filename.c_str()); + + f << "set terminal png size 400,410 enhanced font \"Helvetica,8\"" + << std::endl + << "set output \"" << base_filename << ".png\"" << std::endl + << "set size square" << std::endl + << "set view equal xy" << std::endl + << "unset xtics" << std::endl + << "unset ytics" << std::endl + << "unset grid" << std::endl + << "unset border" << std::endl + << "plot '-' using 1:2 with lines notitle, '-' with labels tc rgb 'red' nopoint notitle, '-' with labels point pt 4 offset 1,1 notitle" + << std::endl; + GridOut().write_gnuplot(tria, f); + f << "e" << std::endl; + + // output cell blocks: + for (unsigned int cell = 0; cell < n_cells; ++cell) + for (unsigned int c = 0; c < mf_data->n_components_filled(cell); ++c) + { + const auto dof_cell = mf_data->get_cell_iterator(cell, c); + f << dof_cell->center() << " \"" << cell << "\"\n"; + } + + f << std::flush; + f << "e" << std::endl << std::endl; + + DoFTools::write_gnuplot_dof_support_point_info(f, support_points); + + f << "e" << std::endl; + } +} + + +int +main(int argc, char **argv) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization( + argc, argv, testing_max_num_threads()); + + MPILogInitAll mpi_init_log; + + deallog.push("2d"); + test<2, 1>(); + test<2, 1, float>(); + test<2, 1>(false); + deallog.pop(); +} diff --git a/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output b/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output new file mode 100644 index 000000000000..226a54f49664 --- /dev/null +++ b/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output @@ -0,0 +1,34 @@ + +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 7 18 19 21 22 +DEAL:0:2d:: 6 7 16 17 18 19 20 21 22 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 2 7 9 10 21 22 23 24 +DEAL:0:2d:: 0 6 7 8 10 21 22 23 24 25 26 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 2 3 7 9 10 11 12 24 +DEAL:0:2d:: 0 1 2 3 7 8 9 10 11 12 24 25 26 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 2 3 4 5 9 11 12 14 15 +DEAL:0:2d:: 2 3 4 5 9 11 12 13 14 15 +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 2 7 9 10 18 19 21 22 23 24 +DEAL:0:2d:: 0 6 7 8 10 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 2 3 4 5 7 9 10 11 12 14 15 24 +DEAL:0:2d:: 0 1 2 3 4 5 7 8 9 10 11 12 13 14 15 24 25 26 +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 2 3 5 6 7 8 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 8 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 5 8 10 12 13 14 +DEAL:0:2d:: 4 5 8 9 10 11 12 13 14 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 6 7 8 15 16 17 18 19 20 +DEAL:0:2d:: 6 7 8 15 16 17 18 19 20 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 8 13 14 17 20 21 22 23 24 +DEAL:0:2d:: 8 13 14 17 20 21 22 23 24 diff --git a/tests/matrix_free/dof_info_02.cc b/tests/matrix_free/dof_info_02.cc new file mode 100644 index 000000000000..a980641a68d4 --- /dev/null +++ b/tests/matrix_free/dof_info_02.cc @@ -0,0 +1,205 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + + +// Tests DoFInfo::get_dof_indices() for multi-component system + +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include + +#include + +#include "../tests.h" + + + +template +void +test(const bool adaptive_ref = true) +{ + MPI_Comm mpi_communicator(MPI_COMM_WORLD); + const unsigned int this_mpi_core = + dealii::Utilities::MPI::this_mpi_process(mpi_communicator); + + parallel::distributed::Triangulation tria(mpi_communicator); + GridGenerator::hyper_cube(tria, 0, 1, true); + tria.refine_global(1); + if (adaptive_ref) + { + for (auto cell : tria.active_cell_iterators()) + if (cell->is_locally_owned()) + if (cell->center().norm() < 0.5) + cell->set_refine_flag(); + tria.execute_coarsening_and_refinement(); + for (auto cell : tria.active_cell_iterators()) + if (cell->is_locally_owned()) + if (cell->center()[0] < 0.2) + cell->set_refine_flag(); + tria.execute_coarsening_and_refinement(); + } + else + { + tria.refine_global(1); + } + + FE_Q feq(fe_degree); + FESystem fe(feq, dim); + DoFHandler dof(tria); + dof.distribute_dofs(fe); + + IndexSet owned_set = dof.locally_owned_dofs(); + IndexSet relevant_set; + DoFTools::extract_locally_relevant_dofs(dof, relevant_set); + + AffineConstraints constraints(relevant_set); + DoFTools::make_hanging_node_constraints(dof, constraints); + // constrain bottom part of the boundary (lower in y direction) + VectorTools::interpolate_boundary_values(dof, + 2, + Functions::ZeroFunction(2), + constraints); + constraints.close(); + + deallog << "Testing " << dof.get_fe().get_name() << std::endl; + + std::shared_ptr> mf_data( + new MatrixFree()); + { + const QGauss<1> quad(fe_degree + 1); + typename MatrixFree::AdditionalData data; + data.tasks_parallel_scheme = MatrixFree::AdditionalData::none; + data.tasks_block_size = 7; + mf_data->reinit(dof, constraints, quad, data); + } + + const unsigned int n_cells = mf_data->n_macro_cells(); + const auto & dof_info = mf_data->get_dof_info(); + constexpr unsigned int n_vectorization = + VectorizedArray::n_array_elements; + + std::vector my_rows; + my_rows.reserve(fe.dofs_per_cell * n_vectorization); + + constexpr auto dof_access_index = + internal::MatrixFreeFunctions::DoFInfo::dof_access_cell; + + bool checked_interleaved = false; + for (unsigned int cell = 0; cell < n_cells; ++cell) + { + deallog << "Cell: " << cell << std::endl; + checked_interleaved |= + (dof_info.index_storage_variants[dof_access_index][cell] == + internal::MatrixFreeFunctions::DoFInfo::IndexStorageVariants:: + interleaved); + auto get_and_log = [&](const bool apply_constraints) { + dof_info.get_dof_indices_on_cell_batch(my_rows, + cell, + apply_constraints); + // sort and make unique to make visual inspection easier: + std::sort(my_rows.begin(), my_rows.end()); + my_rows.erase(std::unique(my_rows.begin(), my_rows.end()), + my_rows.end()); + for (auto el : my_rows) + deallog << " " << el; + deallog << std::endl; + }; + get_and_log(true); + get_and_log(false); + } + + // if we don't have adaptive refinement, we should have + // some cells interleaved (at least that is the intention of this + // part of the test) + Assert(checked_interleaved || adaptive_ref, ExcInternalError()); + + // output in Gnuplot + if (dim == 2) + { + std::map> support_points; + MappingQ1 mapping; + DoFTools::map_dofs_to_support_points(mapping, dof, support_points); + + const std::string prefix = + std::is_same::value ? "float_" : "double_"; + const std::string href = (adaptive_ref ? "" : "global_"); + const std::string base_filename = + prefix + href + "grid" + dealii::Utilities::int_to_string(dim) + "_" + + dealii::Utilities::int_to_string(fe_degree) + "_p" + + dealii::Utilities::int_to_string(this_mpi_core); + + const std::string filename = base_filename + ".gp"; + std::ofstream f(filename.c_str()); + + f << "set terminal png size 400,410 enhanced font \"Helvetica,8\"" + << std::endl + << "set output \"" << base_filename << ".png\"" << std::endl + << "set size square" << std::endl + << "set view equal xy" << std::endl + << "unset xtics" << std::endl + << "unset ytics" << std::endl + << "unset grid" << std::endl + << "unset border" << std::endl + << "plot '-' using 1:2 with lines notitle, '-' with labels tc rgb 'red' nopoint notitle, '-' with labels point pt 4 offset 1,1 notitle" + << std::endl; + GridOut().write_gnuplot(tria, f); + f << "e" << std::endl; + + // output cell blocks: + for (unsigned int cell = 0; cell < n_cells; ++cell) + for (unsigned int c = 0; c < mf_data->n_components_filled(cell); ++c) + { + const auto dof_cell = mf_data->get_cell_iterator(cell, c); + f << dof_cell->center() << " \"" << cell << "\"\n"; + } + + f << std::flush; + f << "e" << std::endl << std::endl; + + DoFTools::write_gnuplot_dof_support_point_info(f, support_points); + + f << "e" << std::endl; + } +} + + +int +main(int argc, char **argv) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization( + argc, argv, testing_max_num_threads()); + + MPILogInitAll mpi_init_log; + + deallog.push("2d"); + test<2, 1>(); + test<2, 1, float>(); + test<2, 1>(false); + deallog.pop(); +} diff --git a/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output b/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output new file mode 100644 index 000000000000..1da9dc63eaed --- /dev/null +++ b/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output @@ -0,0 +1,34 @@ + +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 14 15 36 37 38 39 42 43 44 45 +DEAL:0:2d:: 12 13 14 15 32 33 34 35 36 37 38 39 40 41 42 43 44 45 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 4 5 14 15 18 19 20 21 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 0 1 12 13 14 15 16 17 20 21 42 43 44 45 46 47 48 49 50 51 52 53 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 4 5 6 7 14 15 18 19 20 21 22 23 24 25 48 49 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 14 15 16 17 18 19 20 21 22 23 24 25 48 49 50 51 52 53 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 18 19 22 23 24 25 28 29 30 31 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 18 19 22 23 24 25 26 27 28 29 30 31 +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 4 5 14 15 18 19 20 21 36 37 38 39 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 0 1 12 13 14 15 16 17 20 21 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 14 15 18 19 20 21 22 23 24 25 28 29 30 31 48 49 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 8 9 10 11 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 48 49 50 51 52 53 +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 4 5 6 7 10 11 12 13 14 15 16 17 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 10 11 16 17 20 21 24 25 26 27 28 29 +DEAL:0:2d:: 8 9 10 11 16 17 18 19 20 21 22 23 24 25 26 27 28 29 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 12 13 14 15 16 17 30 31 32 33 34 35 36 37 38 39 40 41 +DEAL:0:2d:: 12 13 14 15 16 17 30 31 32 33 34 35 36 37 38 39 40 41 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 16 17 26 27 28 29 34 35 40 41 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 16 17 26 27 28 29 34 35 40 41 42 43 44 45 46 47 48 49 From 7d99efb93bb43ea9927ec1efeae9f0362ae2ad0a Mon Sep 17 00:00:00 2001 From: Rene Gassmoeller Date: Wed, 30 Jan 2019 16:42:20 -0800 Subject: [PATCH 040/507] Fix invalid memory access in particle properties after transfer --- include/deal.II/particles/particle.h | 10 +- source/particles/particle.cc | 7 +- source/particles/particle_handler.cc | 6 + tests/particles/particle_handler_08.cc | 183 ++++++++++++++++++ ...particle_handler_08.with_p4est=true.output | 139 +++++++++++++ 5 files changed, 342 insertions(+), 3 deletions(-) create mode 100644 tests/particles/particle_handler_08.cc create mode 100644 tests/particles/particle_handler_08.with_p4est=true.output diff --git a/include/deal.II/particles/particle.h b/include/deal.II/particles/particle.h index b4d3de0581b3..df6ebd17418e 100644 --- a/include/deal.II/particles/particle.h +++ b/include/deal.II/particles/particle.h @@ -256,7 +256,12 @@ namespace Particles set_properties(const ArrayView &new_properties); /** - * Get write-access to properties of this particle. + * Get write-access to properties of this particle. If the + * particle has no properties yet, but has access to a + * PropertyPool object it will allocate properties to + * allow writing into them. If it has no properties and + * has no access to a PropertyPool this function will + * throw an exception. * * @return An ArrayView of the properties of this particle. */ @@ -264,7 +269,8 @@ namespace Particles get_properties(); /** - * Get read-access to properties of this particle. + * Get read-access to properties of this particle. If the particle + * has no properties this function throws an exception. * * @return An ArrayView of the properties of this particle. */ diff --git a/source/particles/particle.cc b/source/particles/particle.cc index b5dea11fa8d0..03f90811b333 100644 --- a/source/particles/particle.cc +++ b/source/particles/particle.cc @@ -284,6 +284,8 @@ namespace Particles Particle::set_properties( const ArrayView &new_properties) { + Assert(property_pool != nullptr, ExcInternalError()); + if (properties == PropertyPool::invalid_handle) properties = property_pool->allocate_properties_array(); @@ -313,7 +315,7 @@ namespace Particles const ArrayView Particle::get_properties() const { - Assert(property_pool != nullptr, ExcInternalError()); + Assert(has_properties(), ExcInternalError()); return property_pool->get_properties(properties); } @@ -326,6 +328,9 @@ namespace Particles { Assert(property_pool != nullptr, ExcInternalError()); + if (properties == PropertyPool::invalid_handle) + properties = property_pool->allocate_properties_array(); + return property_pool->get_properties(properties); } diff --git a/source/particles/particle_handler.cc b/source/particles/particle_handler.cc index 84f61ff4da79..af3b69a03160 100644 --- a/source/particles/particle_handler.cc +++ b/source/particles/particle_handler.cc @@ -1200,6 +1200,12 @@ namespace Particles data_range.end(), /*allow_compression=*/true); + // Update the reference to the current property pool for all particles. + // This was not stored, because they might be transported across process + // domains. + for (auto &particle : loaded_particles_on_cell) + particle.set_property_pool(*property_pool); + switch (status) { case parallel::distributed::Triangulation::CELL_PERSIST: diff --git a/tests/particles/particle_handler_08.cc b/tests/particles/particle_handler_08.cc new file mode 100644 index 000000000000..d5cd3be2b643 --- /dev/null +++ b/tests/particles/particle_handler_08.cc @@ -0,0 +1,183 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2017 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. +// +// --------------------------------------------------------------------- + + + +// like particle_handler_05, but check that the properties of particles are +// correctly transferred during grid +// refinement/coarsening. Note that this in particular tests for a bug, where +// references to the property pool where lost during particle transfer. + +#include + +#include + +#include +#include + +#include + +#include "../tests.h" + +template +void +create_regular_particle_distribution( + Particles::ParticleHandler & particle_handler, + const parallel::distributed::Triangulation &tr, + const unsigned int particles_per_direction = 3) +{ + for (unsigned int i = 0; i < particles_per_direction; ++i) + for (unsigned int j = 0; j < particles_per_direction; ++j) + { + Point position; + Point reference_position; + unsigned int id = i * particles_per_direction + j; + + position[0] = static_cast(i) / + static_cast(particles_per_direction - 1); + position[1] = static_cast(j) / + static_cast(particles_per_direction - 1); + + if (dim > 2) + for (unsigned int k = 0; k < particles_per_direction; ++k) + { + position[2] = static_cast(j) / + static_cast(particles_per_direction - 1); + id = i * particles_per_direction * particles_per_direction + + j * particles_per_direction + k; + Particles::Particle particle(position, + reference_position, + id); + + typename parallel::distributed::Triangulation:: + active_cell_iterator cell = + GridTools::find_active_cell_around_point( + tr, particle.get_location()); + + Particles::ParticleIterator pit = + particle_handler.insert_particle(particle, cell); + + for (unsigned int i = 0; i < spacedim; ++i) + pit->get_properties()[i] = pit->get_location()[i]; + } + else + { + Particles::Particle particle(position, + reference_position, + id); + + typename parallel::distributed::Triangulation:: + active_cell_iterator cell = + GridTools::find_active_cell_around_point( + tr, particle.get_location()); + + Particles::ParticleIterator pit = + particle_handler.insert_particle(particle, cell); + + for (unsigned int i = 0; i < spacedim; ++i) + pit->get_properties()[i] = pit->get_location()[i]; + } + } +} + +template +void +test() +{ + { + parallel::distributed::Triangulation tr(MPI_COMM_WORLD); + + GridGenerator::hyper_cube(tr); + MappingQ mapping(1); + + const unsigned int n_properties = spacedim; + Particles::ParticleHandler particle_handler(tr, + mapping, + n_properties); + + // TODO: Move this into the Particle handler class. Unfortunately, there are + // some interactions with the SolutionTransfer class that prevent us from + // doing this at the moment. When doing this, check that transferring a + // solution and particles during the same refinement is possible (in + // particular that the order of serialization/deserialization is preserved). + tr.signals.pre_distributed_refinement.connect(std::bind( + &Particles::ParticleHandler::register_store_callback_function, + &particle_handler)); + + tr.signals.post_distributed_refinement.connect(std::bind( + &Particles::ParticleHandler::register_load_callback_function, + &particle_handler, + false)); + + create_regular_particle_distribution(particle_handler, tr); + + for (auto particle = particle_handler.begin(); + particle != particle_handler.end(); + ++particle) + deallog << "Before refinement particle id " << particle->get_id() + << " has first property " << particle->get_properties()[0] + << " and second property " << particle->get_properties()[1] + << std::endl; + + // Check that all particles are moved to children + tr.refine_global(1); + + for (auto particle = particle_handler.begin(); + particle != particle_handler.end(); + ++particle) + deallog << "After refinement particle id " << particle->get_id() + << " has first property " << particle->get_properties()[0] + << " and second property " << particle->get_properties()[1] + << std::endl; + + // Reverse the refinement and check again + for (auto cell = tr.begin_active(); cell != tr.end(); ++cell) + cell->set_coarsen_flag(); + + tr.execute_coarsening_and_refinement(); + + for (auto particle = particle_handler.begin(); + particle != particle_handler.end(); + ++particle) + deallog << "After coarsening particle id " << particle->get_id() + << " has first property " << particle->get_properties()[0] + << " and second property " << particle->get_properties()[1] + << std::endl; + } + + deallog << "OK" << std::endl; +} + + + +int +main(int argc, char *argv[]) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + MPILogInitAll all; + + deallog.push("2d/2d"); + test<2, 2>(); + deallog.pop(); + deallog.push("2d/3d"); + test<2, 3>(); + deallog.pop(); + deallog.push("3d/3d"); + test<3, 3>(); + deallog.pop(); +} diff --git a/tests/particles/particle_handler_08.with_p4est=true.output b/tests/particles/particle_handler_08.with_p4est=true.output new file mode 100644 index 000000000000..f54a16d67e73 --- /dev/null +++ b/tests/particles/particle_handler_08.with_p4est=true.output @@ -0,0 +1,139 @@ + +DEAL:0:2d/2d::Before refinement particle id 0 has first property 0.00000 and second property 0.00000 +DEAL:0:2d/2d::Before refinement particle id 1 has first property 0.00000 and second property 0.500000 +DEAL:0:2d/2d::Before refinement particle id 2 has first property 0.00000 and second property 1.00000 +DEAL:0:2d/2d::Before refinement particle id 3 has first property 0.500000 and second property 0.00000 +DEAL:0:2d/2d::Before refinement particle id 4 has first property 0.500000 and second property 0.500000 +DEAL:0:2d/2d::Before refinement particle id 5 has first property 0.500000 and second property 1.00000 +DEAL:0:2d/2d::Before refinement particle id 6 has first property 1.00000 and second property 0.00000 +DEAL:0:2d/2d::Before refinement particle id 7 has first property 1.00000 and second property 0.500000 +DEAL:0:2d/2d::Before refinement particle id 8 has first property 1.00000 and second property 1.00000 +DEAL:0:2d/2d::After refinement particle id 0 has first property 0.00000 and second property 0.00000 +DEAL:0:2d/2d::After refinement particle id 1 has first property 0.00000 and second property 0.500000 +DEAL:0:2d/2d::After refinement particle id 3 has first property 0.500000 and second property 0.00000 +DEAL:0:2d/2d::After refinement particle id 4 has first property 0.500000 and second property 0.500000 +DEAL:0:2d/2d::After refinement particle id 6 has first property 1.00000 and second property 0.00000 +DEAL:0:2d/2d::After refinement particle id 7 has first property 1.00000 and second property 0.500000 +DEAL:0:2d/2d::After refinement particle id 2 has first property 0.00000 and second property 1.00000 +DEAL:0:2d/2d::After refinement particle id 5 has first property 0.500000 and second property 1.00000 +DEAL:0:2d/2d::After refinement particle id 8 has first property 1.00000 and second property 1.00000 +DEAL:0:2d/2d::After coarsening particle id 0 has first property 0.00000 and second property 0.00000 +DEAL:0:2d/2d::After coarsening particle id 1 has first property 0.00000 and second property 0.500000 +DEAL:0:2d/2d::After coarsening particle id 3 has first property 0.500000 and second property 0.00000 +DEAL:0:2d/2d::After coarsening particle id 4 has first property 0.500000 and second property 0.500000 +DEAL:0:2d/2d::After coarsening particle id 6 has first property 1.00000 and second property 0.00000 +DEAL:0:2d/2d::After coarsening particle id 7 has first property 1.00000 and second property 0.500000 +DEAL:0:2d/2d::After coarsening particle id 2 has first property 0.00000 and second property 1.00000 +DEAL:0:2d/2d::After coarsening particle id 5 has first property 0.500000 and second property 1.00000 +DEAL:0:2d/2d::After coarsening particle id 8 has first property 1.00000 and second property 1.00000 +DEAL:0:2d/2d::OK +DEAL:0:2d/3d::Before refinement particle id 0 has first property 0.00000 and second property 0.00000 +DEAL:0:2d/3d::Before refinement particle id 1 has first property 0.00000 and second property 0.500000 +DEAL:0:2d/3d::Before refinement particle id 2 has first property 0.00000 and second property 1.00000 +DEAL:0:2d/3d::Before refinement particle id 3 has first property 0.500000 and second property 0.00000 +DEAL:0:2d/3d::Before refinement particle id 4 has first property 0.500000 and second property 0.500000 +DEAL:0:2d/3d::Before refinement particle id 5 has first property 0.500000 and second property 1.00000 +DEAL:0:2d/3d::Before refinement particle id 6 has first property 1.00000 and second property 0.00000 +DEAL:0:2d/3d::Before refinement particle id 7 has first property 1.00000 and second property 0.500000 +DEAL:0:2d/3d::Before refinement particle id 8 has first property 1.00000 and second property 1.00000 +DEAL:0:2d/3d::After refinement particle id 0 has first property 0.00000 and second property 0.00000 +DEAL:0:2d/3d::After refinement particle id 1 has first property 0.00000 and second property 0.500000 +DEAL:0:2d/3d::After refinement particle id 3 has first property 0.500000 and second property 0.00000 +DEAL:0:2d/3d::After refinement particle id 4 has first property 0.500000 and second property 0.500000 +DEAL:0:2d/3d::After refinement particle id 6 has first property 1.00000 and second property 0.00000 +DEAL:0:2d/3d::After refinement particle id 7 has first property 1.00000 and second property 0.500000 +DEAL:0:2d/3d::After refinement particle id 2 has first property 0.00000 and second property 1.00000 +DEAL:0:2d/3d::After refinement particle id 5 has first property 0.500000 and second property 1.00000 +DEAL:0:2d/3d::After refinement particle id 8 has first property 1.00000 and second property 1.00000 +DEAL:0:2d/3d::After coarsening particle id 0 has first property 0.00000 and second property 0.00000 +DEAL:0:2d/3d::After coarsening particle id 1 has first property 0.00000 and second property 0.500000 +DEAL:0:2d/3d::After coarsening particle id 3 has first property 0.500000 and second property 0.00000 +DEAL:0:2d/3d::After coarsening particle id 4 has first property 0.500000 and second property 0.500000 +DEAL:0:2d/3d::After coarsening particle id 6 has first property 1.00000 and second property 0.00000 +DEAL:0:2d/3d::After coarsening particle id 7 has first property 1.00000 and second property 0.500000 +DEAL:0:2d/3d::After coarsening particle id 2 has first property 0.00000 and second property 1.00000 +DEAL:0:2d/3d::After coarsening particle id 5 has first property 0.500000 and second property 1.00000 +DEAL:0:2d/3d::After coarsening particle id 8 has first property 1.00000 and second property 1.00000 +DEAL:0:2d/3d::OK +DEAL:0:3d/3d::Before refinement particle id 0 has first property 0.00000 and second property 0.00000 +DEAL:0:3d/3d::Before refinement particle id 1 has first property 0.00000 and second property 0.00000 +DEAL:0:3d/3d::Before refinement particle id 2 has first property 0.00000 and second property 0.00000 +DEAL:0:3d/3d::Before refinement particle id 3 has first property 0.00000 and second property 0.500000 +DEAL:0:3d/3d::Before refinement particle id 4 has first property 0.00000 and second property 0.500000 +DEAL:0:3d/3d::Before refinement particle id 5 has first property 0.00000 and second property 0.500000 +DEAL:0:3d/3d::Before refinement particle id 6 has first property 0.00000 and second property 1.00000 +DEAL:0:3d/3d::Before refinement particle id 7 has first property 0.00000 and second property 1.00000 +DEAL:0:3d/3d::Before refinement particle id 8 has first property 0.00000 and second property 1.00000 +DEAL:0:3d/3d::Before refinement particle id 9 has first property 0.500000 and second property 0.00000 +DEAL:0:3d/3d::Before refinement particle id 10 has first property 0.500000 and second property 0.00000 +DEAL:0:3d/3d::Before refinement particle id 11 has first property 0.500000 and second property 0.00000 +DEAL:0:3d/3d::Before refinement particle id 12 has first property 0.500000 and second property 0.500000 +DEAL:0:3d/3d::Before refinement particle id 13 has first property 0.500000 and second property 0.500000 +DEAL:0:3d/3d::Before refinement particle id 14 has first property 0.500000 and second property 0.500000 +DEAL:0:3d/3d::Before refinement particle id 15 has first property 0.500000 and second property 1.00000 +DEAL:0:3d/3d::Before refinement particle id 16 has first property 0.500000 and second property 1.00000 +DEAL:0:3d/3d::Before refinement particle id 17 has first property 0.500000 and second property 1.00000 +DEAL:0:3d/3d::Before refinement particle id 18 has first property 1.00000 and second property 0.00000 +DEAL:0:3d/3d::Before refinement particle id 19 has first property 1.00000 and second property 0.00000 +DEAL:0:3d/3d::Before refinement particle id 20 has first property 1.00000 and second property 0.00000 +DEAL:0:3d/3d::Before refinement particle id 21 has first property 1.00000 and second property 0.500000 +DEAL:0:3d/3d::Before refinement particle id 22 has first property 1.00000 and second property 0.500000 +DEAL:0:3d/3d::Before refinement particle id 23 has first property 1.00000 and second property 0.500000 +DEAL:0:3d/3d::Before refinement particle id 24 has first property 1.00000 and second property 1.00000 +DEAL:0:3d/3d::Before refinement particle id 25 has first property 1.00000 and second property 1.00000 +DEAL:0:3d/3d::Before refinement particle id 26 has first property 1.00000 and second property 1.00000 +DEAL:0:3d/3d::After refinement particle id 0 has first property 0.00000 and second property 0.00000 +DEAL:0:3d/3d::After refinement particle id 1 has first property 0.00000 and second property 0.00000 +DEAL:0:3d/3d::After refinement particle id 2 has first property 0.00000 and second property 0.00000 +DEAL:0:3d/3d::After refinement particle id 3 has first property 0.00000 and second property 0.500000 +DEAL:0:3d/3d::After refinement particle id 4 has first property 0.00000 and second property 0.500000 +DEAL:0:3d/3d::After refinement particle id 5 has first property 0.00000 and second property 0.500000 +DEAL:0:3d/3d::After refinement particle id 9 has first property 0.500000 and second property 0.00000 +DEAL:0:3d/3d::After refinement particle id 10 has first property 0.500000 and second property 0.00000 +DEAL:0:3d/3d::After refinement particle id 11 has first property 0.500000 and second property 0.00000 +DEAL:0:3d/3d::After refinement particle id 12 has first property 0.500000 and second property 0.500000 +DEAL:0:3d/3d::After refinement particle id 13 has first property 0.500000 and second property 0.500000 +DEAL:0:3d/3d::After refinement particle id 14 has first property 0.500000 and second property 0.500000 +DEAL:0:3d/3d::After refinement particle id 18 has first property 1.00000 and second property 0.00000 +DEAL:0:3d/3d::After refinement particle id 19 has first property 1.00000 and second property 0.00000 +DEAL:0:3d/3d::After refinement particle id 20 has first property 1.00000 and second property 0.00000 +DEAL:0:3d/3d::After refinement particle id 21 has first property 1.00000 and second property 0.500000 +DEAL:0:3d/3d::After refinement particle id 22 has first property 1.00000 and second property 0.500000 +DEAL:0:3d/3d::After refinement particle id 23 has first property 1.00000 and second property 0.500000 +DEAL:0:3d/3d::After refinement particle id 6 has first property 0.00000 and second property 1.00000 +DEAL:0:3d/3d::After refinement particle id 7 has first property 0.00000 and second property 1.00000 +DEAL:0:3d/3d::After refinement particle id 8 has first property 0.00000 and second property 1.00000 +DEAL:0:3d/3d::After refinement particle id 15 has first property 0.500000 and second property 1.00000 +DEAL:0:3d/3d::After refinement particle id 16 has first property 0.500000 and second property 1.00000 +DEAL:0:3d/3d::After refinement particle id 17 has first property 0.500000 and second property 1.00000 +DEAL:0:3d/3d::After refinement particle id 24 has first property 1.00000 and second property 1.00000 +DEAL:0:3d/3d::After refinement particle id 25 has first property 1.00000 and second property 1.00000 +DEAL:0:3d/3d::After refinement particle id 26 has first property 1.00000 and second property 1.00000 +DEAL:0:3d/3d::After coarsening particle id 0 has first property 0.00000 and second property 0.00000 +DEAL:0:3d/3d::After coarsening particle id 1 has first property 0.00000 and second property 0.00000 +DEAL:0:3d/3d::After coarsening particle id 2 has first property 0.00000 and second property 0.00000 +DEAL:0:3d/3d::After coarsening particle id 3 has first property 0.00000 and second property 0.500000 +DEAL:0:3d/3d::After coarsening particle id 4 has first property 0.00000 and second property 0.500000 +DEAL:0:3d/3d::After coarsening particle id 5 has first property 0.00000 and second property 0.500000 +DEAL:0:3d/3d::After coarsening particle id 9 has first property 0.500000 and second property 0.00000 +DEAL:0:3d/3d::After coarsening particle id 10 has first property 0.500000 and second property 0.00000 +DEAL:0:3d/3d::After coarsening particle id 11 has first property 0.500000 and second property 0.00000 +DEAL:0:3d/3d::After coarsening particle id 12 has first property 0.500000 and second property 0.500000 +DEAL:0:3d/3d::After coarsening particle id 13 has first property 0.500000 and second property 0.500000 +DEAL:0:3d/3d::After coarsening particle id 14 has first property 0.500000 and second property 0.500000 +DEAL:0:3d/3d::After coarsening particle id 18 has first property 1.00000 and second property 0.00000 +DEAL:0:3d/3d::After coarsening particle id 19 has first property 1.00000 and second property 0.00000 +DEAL:0:3d/3d::After coarsening particle id 20 has first property 1.00000 and second property 0.00000 +DEAL:0:3d/3d::After coarsening particle id 21 has first property 1.00000 and second property 0.500000 +DEAL:0:3d/3d::After coarsening particle id 22 has first property 1.00000 and second property 0.500000 +DEAL:0:3d/3d::After coarsening particle id 23 has first property 1.00000 and second property 0.500000 +DEAL:0:3d/3d::After coarsening particle id 6 has first property 0.00000 and second property 1.00000 +DEAL:0:3d/3d::After coarsening particle id 7 has first property 0.00000 and second property 1.00000 +DEAL:0:3d/3d::After coarsening particle id 8 has first property 0.00000 and second property 1.00000 +DEAL:0:3d/3d::After coarsening particle id 15 has first property 0.500000 and second property 1.00000 +DEAL:0:3d/3d::After coarsening particle id 16 has first property 0.500000 and second property 1.00000 +DEAL:0:3d/3d::After coarsening particle id 17 has first property 0.500000 and second property 1.00000 +DEAL:0:3d/3d::After coarsening particle id 24 has first property 1.00000 and second property 1.00000 +DEAL:0:3d/3d::After coarsening particle id 25 has first property 1.00000 and second property 1.00000 +DEAL:0:3d/3d::After coarsening particle id 26 has first property 1.00000 and second property 1.00000 +DEAL:0:3d/3d::OK From c811784bddae1708ba9a5481787c95120e5e3e2b Mon Sep 17 00:00:00 2001 From: Giovanni Alzetta Date: Thu, 10 Jan 2019 16:29:40 +0100 Subject: [PATCH 041/507] Added point constructor from boost point and test --- include/deal.II/base/point.h | 33 +++++++++++++++++++ tests/base/point_04.cc | 62 ++++++++++++++++++++++++++++++++++++ tests/base/point_04.output | 0 3 files changed, 95 insertions(+) create mode 100644 tests/base/point_04.cc create mode 100644 tests/base/point_04.output diff --git a/include/deal.II/base/point.h b/include/deal.II/base/point.h index 8bae4ecb0344..38a87c6f24f4 100644 --- a/include/deal.II/base/point.h +++ b/include/deal.II/base/point.h @@ -22,6 +22,8 @@ #include #include +#include + #include DEAL_II_NAMESPACE_OPEN @@ -143,6 +145,15 @@ class Point : public Tensor<1, dim, Number> */ Point(const Number x, const Number y, const Number z); + /** + * Convert a boost::geometry::point to a dealii::Point. + */ + template + Point(const boost::geometry::model:: + point &boost_pt, + typename std::enable_if<(dim == dummy_dim) && (dummy_dim != 0), + int>::type = 0); + /** * Return a unit vector in coordinate direction i, i.e., a vector * that is zero in all coordinates except for a single 1 in the ith @@ -358,6 +369,28 @@ inline Point::Point(const Number x, const Number y, const Number z) } + +template +template +inline Point::Point( + const boost::geometry::model:: + point &boost_pt, + typename std::enable_if<(dim == dummy_dim) && (dummy_dim != 0), int>::type) +{ + Assert(dim <= 3, ExcNotImplemented()); + this->values[0] = boost::geometry::get<0>(boost_pt); + constexpr unsigned int y_index = (dim < 2) ? 0 : 1; + constexpr unsigned int z_index = (dim < 3) ? 0 : 2; + + if (dim >= 2) + this->values[y_index] = boost::geometry::get(boost_pt); + + if (dim >= 3) + this->values[z_index] = boost::geometry::get(boost_pt); +} + + + template inline Point Point::unit_vector(unsigned int i) diff --git a/tests/base/point_04.cc b/tests/base/point_04.cc new file mode 100644 index 000000000000..7dbb62241b5f --- /dev/null +++ b/tests/base/point_04.cc @@ -0,0 +1,62 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2010 - 2017 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. +// +// --------------------------------------------------------------------- + + +// test for Point::operator() + +#include + +#include + +#include + +#include "../tests.h" + +namespace bg = boost::geometry; + +template +void +check() +{ + bg::model::point bg_point; + + constexpr unsigned int y_index = (spacedim < 2) ? 0 : 1; + constexpr unsigned int z_index = (spacedim < 3) ? 0 : 2; + + bg_point.set<0>(42.0); + + if (dim >= 2) + bg_point.set(42.0 + dim); + + if (dim >= 3) + bg_point.set(42.0 + dim + 1); + + Point p(bg_point); + + for (unsigned int i = 0; i < dim; ++i) + deallog << p(i) << ' '; + deallog << std::endl; +} + +int +main() +{ + initlog(); + deallog << std::setprecision(3); + + check<1>(); + check<2>(); + check<3>(); +} diff --git a/tests/base/point_04.output b/tests/base/point_04.output new file mode 100644 index 000000000000..e69de29bb2d1 From 4100f1edfdd6332dfc8f13fe32805f83275d6857 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Tue, 29 Jan 2019 09:25:31 -0700 Subject: [PATCH 042/507] Change the way the constructor template argument works. --- include/deal.II/base/point.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/deal.II/base/point.h b/include/deal.II/base/point.h index 38a87c6f24f4..d486ae36c858 100644 --- a/include/deal.II/base/point.h +++ b/include/deal.II/base/point.h @@ -148,9 +148,9 @@ class Point : public Tensor<1, dim, Number> /** * Convert a boost::geometry::point to a dealii::Point. */ - template + template Point(const boost::geometry::model:: - point &boost_pt, + point &boost_pt, typename std::enable_if<(dim == dummy_dim) && (dummy_dim != 0), int>::type = 0); @@ -374,7 +374,7 @@ template template inline Point::Point( const boost::geometry::model:: - point &boost_pt, + point &boost_pt, typename std::enable_if<(dim == dummy_dim) && (dummy_dim != 0), int>::type) { Assert(dim <= 3, ExcNotImplemented()); From 6c89f3783f74db28e1127a351494514a84463199 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Mon, 28 Jan 2019 14:17:53 -0700 Subject: [PATCH 043/507] [CI] introduce clang-tidy check - remove -fix - allow bundled/ by including two .clang-tidy files - add jenkins script --- .clang-tidy | 9 +++ bundled/.clang-tidy | 6 ++ contrib/ci/Jenkinsfile.tidy | 90 +++++++++++++++++++++++++++++ contrib/utilities/run_clang_tidy.sh | 43 +++++++------- 4 files changed, 125 insertions(+), 23 deletions(-) create mode 100644 .clang-tidy create mode 100644 bundled/.clang-tidy create mode 100644 contrib/ci/Jenkinsfile.tidy 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/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/contrib/ci/Jenkinsfile.tidy b/contrib/ci/Jenkinsfile.tidy new file mode 100644 index 000000000000..05c013482631 --- /dev/null +++ b/contrib/ci/Jenkinsfile.tidy @@ -0,0 +1,90 @@ +#!groovy + +/* +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 +*/ + +pipeline +{ + agent none + + stages + { + stage("check") + { + when { + allOf { + not {branch 'master'} + } + } + + agent + { + docker + { + image 'dealii/indent' + } + } + + 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') + { + agent + { + docker + { + image 'tjhei/candi-base-clang' + } + } + 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/run_clang_tidy.sh b/contrib/utilities/run_clang_tidy.sh index d292ef84a084..d013f5663947 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" "$@") -# 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 + From 274448a0012602f53d9029daf3480d79c5639f86 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Tue, 29 Jan 2019 12:44:47 -0700 Subject: [PATCH 044/507] convert for loops --- source/grid/grid_in.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/grid/grid_in.cc b/source/grid/grid_in.cc index c00da148814e..6a9a6fba5324 100644 --- a/source/grid/grid_in.cc +++ b/source/grid/grid_in.cc @@ -2075,8 +2075,8 @@ GridIn<2>::read_netcdf(const std::string &filename) n_bquads, vertices_per_quad); - for (unsigned int i = 0; i < vertex_indices.size(); ++i) - AssertThrow(vertex_indices[i] >= 0, ExcIO()); + for (const int idx : vertex_indices) + AssertThrow(idx >= 0, ExcIO()); // next we read // double points_xc(no_of_points) @@ -2237,8 +2237,8 @@ GridIn<3>::read_netcdf(const std::string &filename) // vector::iterator to int * vertex_indices_var->get(&*vertex_indices.begin(), n_cells, vertices_per_hex); - for (unsigned int i = 0; i < vertex_indices.size(); ++i) - AssertThrow(vertex_indices[i] >= 0, ExcIO()); + for (const int idx : vertex_indices) + AssertThrow(idx >= 0, ExcIO()); // next we read // double points_xc(no_of_points) @@ -2335,9 +2335,9 @@ GridIn<3>::read_netcdf(const std::string &filename) // types::boundary_id. Also, we don't // take numbers::internal_face_boundary_id // as it denotes an internal face - for (unsigned int i = 0; i < bmarker.size(); ++i) - Assert(0 <= bmarker[i] && static_cast(bmarker[i]) != - numbers::internal_face_boundary_id, + for (const int id : bmarker) + Assert(0 <= id && static_cast(id) != + numbers::internal_face_boundary_id, ExcIO()); // finally we setup the boundary From 1e94813d078896e77e318f8ec92977073e40580e Mon Sep 17 00:00:00 2001 From: Rene Gassmoeller Date: Thu, 31 Jan 2019 11:45:03 -0800 Subject: [PATCH 045/507] Fix serialization of variable data attachements --- source/distributed/tria.cc | 1 + tests/mpi/p4est_save_07.cc | 205 ++++++++++++++++++ ...st_save_07.with_p4est=true.mpirun=5.output | 122 +++++++++++ ...st_save_07.with_petsc=true.mpirun=4.output | 10 + 4 files changed, 338 insertions(+) create mode 100644 tests/mpi/p4est_save_07.cc create mode 100644 tests/mpi/p4est_save_07.with_p4est=true.mpirun=5.output create mode 100644 tests/mpi/p4est_save_07.with_petsc=true.mpirun=4.output diff --git a/source/distributed/tria.cc b/source/distributed/tria.cc index 99068c23dac9..5fe3afb1c834 100644 --- a/source/distributed/tria.cc +++ b/source/distributed/tria.cc @@ -2751,6 +2751,7 @@ namespace parallel tria->cell_attached_data.n_attached_data_sets = 0; tria->cell_attached_data.pack_callbacks_fixed.clear(); + tria->cell_attached_data.pack_callbacks_variable.clear(); } } diff --git a/tests/mpi/p4est_save_07.cc b/tests/mpi/p4est_save_07.cc new file mode 100644 index 000000000000..e409ce4fecb5 --- /dev/null +++ b/tests/mpi/p4est_save_07.cc @@ -0,0 +1,205 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2009 - 2017 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. +// +// --------------------------------------------------------------------- + + + +// save and load a triangulation with a different number of cpus +// with variable size data attach +// this is a variation of p4est_save_05, but it saves the triangulation +// multiple times before loading to catch a bug that was not properly +// clearing variables upon save (i.e. multiple saves before a load would +// cause corrupted checkpoints for variable data size attachments). + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "../tests.h" + + + +template +std::vector +pack_function( + const typename parallel::distributed::Triangulation::cell_iterator + &cell, + const typename parallel::distributed::Triangulation::CellStatus + status) +{ + static unsigned int some_number = 1; + std::vector some_vector(some_number); + for (unsigned int i = 0; i < some_number; ++i) + some_vector[i] = i; + + std::vector buffer; + buffer.reserve(some_number * sizeof(unsigned int)); + for (auto vector_it = some_vector.cbegin(); vector_it != some_vector.cend(); + ++vector_it) + { + Utilities::pack(*vector_it, buffer, /*allow_compression=*/false); + } + + deallog << "packing cell " << cell->id() + << " with data size=" << buffer.size() << " accumulated data=" + << std::accumulate(some_vector.begin(), some_vector.end(), 0) + << std::endl; + + Assert((status == + parallel::distributed::Triangulation::CELL_PERSIST), + ExcInternalError()); + + ++some_number; + return buffer; +} + + + +template +void +unpack_function( + const typename parallel::distributed::Triangulation::cell_iterator + &cell, + const typename parallel::distributed::Triangulation::CellStatus + status, + const boost::iterator_range::const_iterator> &data_range) +{ + const unsigned int data_in_bytes = + std::distance(data_range.begin(), data_range.end()); + + std::vector intdatavector(data_in_bytes / sizeof(unsigned int)); + + auto vector_it = intdatavector.begin(); + auto data_it = data_range.begin(); + for (; data_it != data_range.end(); + ++vector_it, data_it += sizeof(unsigned int)) + { + *vector_it = + Utilities::unpack(data_it, + data_it + sizeof(unsigned int), + /*allow_compression=*/false); + } + + deallog << "unpacking cell " << cell->id() << " with data size=" + << std::distance(data_range.begin(), data_range.end()) + << " accumulated data=" + << std::accumulate(intdatavector.begin(), intdatavector.end(), 0) + << std::endl; + + Assert((status == + parallel::distributed::Triangulation::CELL_PERSIST), + ExcInternalError()); +} + + + +template +void +save(MPI_Comm com_small, parallel::distributed::Triangulation &tr) +{ + deallog << "writing with " << Utilities::MPI::n_mpi_processes(com_small) + << std::endl; + + unsigned int handle = + tr.register_data_attach(pack_function, + /*returns_variable_size_data=*/true); + + tr.save("file"); + deallog << "#cells = " << tr.n_global_active_cells() << std::endl; + deallog << "Checksum: " << tr.get_checksum() << std::endl; +} + + + +template +void +test() +{ + unsigned int myid = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); + MPI_Comm com_all = MPI_COMM_WORLD; + MPI_Comm com_small; + + // split the communicator in proc 0,1,2 and 3,4 + MPI_Comm_split(com_all, (myid < 3) ? 0 : 1, myid, &com_small); + + // write with small com + if (myid < 3) + { + parallel::distributed::Triangulation tr(com_small); + GridGenerator::subdivided_hyper_cube(tr, 2); + tr.refine_global(1); + + typename Triangulation::active_cell_iterator cell; + for (cell = tr.begin_active(); cell != tr.end(); ++cell) + { + if (cell->is_locally_owned()) + { + if (cell->id().to_string() == "0_1:0") + cell->set_refine_flag(); + else if (cell->parent()->id().to_string() == "3_0:") + cell->set_coarsen_flag(); + } + } + tr.execute_coarsening_and_refinement(); + + // save two times into the same file, overwrite it the second time + save(com_small, tr); + save(com_small, tr); + } + + MPI_Barrier(MPI_COMM_WORLD); + + deallog << "reading with " << Utilities::MPI::n_mpi_processes(com_all) + << std::endl; + + { + parallel::distributed::Triangulation tr(com_all); + + GridGenerator::subdivided_hyper_cube(tr, 2); + tr.load("file"); + + unsigned int handle = + tr.register_data_attach(pack_function, + /*returns_variable_size_data=*/true); + + tr.notify_ready_to_unpack(handle, unpack_function); + + deallog << "#cells = " << tr.n_global_active_cells() << std::endl; + deallog << "Checksum: " << tr.get_checksum() << std::endl; + + // now check if saving again succeeds. This checks for the correct number of + // attached data packs in tr and caught the bug. + save(com_all, tr); + } + + if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0) + deallog << "OK" << std::endl; +} + + +int +main(int argc, char *argv[]) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + MPILogInitAll log; + + test<2>(); +} diff --git a/tests/mpi/p4est_save_07.with_p4est=true.mpirun=5.output b/tests/mpi/p4est_save_07.with_p4est=true.mpirun=5.output new file mode 100644 index 000000000000..06bf11bda4e5 --- /dev/null +++ b/tests/mpi/p4est_save_07.with_p4est=true.mpirun=5.output @@ -0,0 +1,122 @@ + +DEAL:0::writing with 3 +DEAL:0::packing cell 0_2:00 with data size=4 accumulated data=0 +DEAL:0::packing cell 0_2:01 with data size=8 accumulated data=1 +DEAL:0::packing cell 0_2:02 with data size=12 accumulated data=3 +DEAL:0::packing cell 0_2:03 with data size=16 accumulated data=6 +DEAL:0::packing cell 0_1:1 with data size=20 accumulated data=10 +DEAL:0::#cells = 16 +DEAL:0::Checksum: 2822439380 +DEAL:0::writing with 3 +DEAL:0::packing cell 0_2:00 with data size=24 accumulated data=15 +DEAL:0::packing cell 0_2:01 with data size=28 accumulated data=21 +DEAL:0::packing cell 0_2:02 with data size=32 accumulated data=28 +DEAL:0::packing cell 0_2:03 with data size=36 accumulated data=36 +DEAL:0::packing cell 0_1:1 with data size=40 accumulated data=45 +DEAL:0::#cells = 16 +DEAL:0::Checksum: 2822439380 +DEAL:0::reading with 5 +DEAL:0::unpacking cell 0_2:00 with data size=24 accumulated data=15 +DEAL:0::unpacking cell 0_2:01 with data size=28 accumulated data=21 +DEAL:0::unpacking cell 0_2:02 with data size=32 accumulated data=28 +DEAL:0::unpacking cell 0_2:03 with data size=36 accumulated data=36 +DEAL:0::#cells = 16 +DEAL:0::Checksum: 2822439380 +DEAL:0::writing with 5 +DEAL:0::packing cell 0_2:00 with data size=44 accumulated data=55 +DEAL:0::packing cell 0_2:01 with data size=48 accumulated data=66 +DEAL:0::packing cell 0_2:02 with data size=52 accumulated data=78 +DEAL:0::packing cell 0_2:03 with data size=56 accumulated data=91 +DEAL:0::#cells = 16 +DEAL:0::Checksum: 2822439380 +DEAL:0::OK + +DEAL:1::writing with 3 +DEAL:1::packing cell 0_1:2 with data size=4 accumulated data=0 +DEAL:1::packing cell 0_1:3 with data size=8 accumulated data=1 +DEAL:1::packing cell 1_1:0 with data size=12 accumulated data=3 +DEAL:1::packing cell 1_1:1 with data size=16 accumulated data=6 +DEAL:1::packing cell 1_1:2 with data size=20 accumulated data=10 +DEAL:1::packing cell 1_1:3 with data size=24 accumulated data=15 +DEAL:1::#cells = 16 +DEAL:1::Checksum: 0 +DEAL:1::writing with 3 +DEAL:1::packing cell 0_1:2 with data size=28 accumulated data=21 +DEAL:1::packing cell 0_1:3 with data size=32 accumulated data=28 +DEAL:1::packing cell 1_1:0 with data size=36 accumulated data=36 +DEAL:1::packing cell 1_1:1 with data size=40 accumulated data=45 +DEAL:1::packing cell 1_1:2 with data size=44 accumulated data=55 +DEAL:1::packing cell 1_1:3 with data size=48 accumulated data=66 +DEAL:1::#cells = 16 +DEAL:1::Checksum: 0 +DEAL:1::reading with 5 +DEAL:1::unpacking cell 0_1:1 with data size=40 accumulated data=45 +DEAL:1::unpacking cell 0_1:2 with data size=28 accumulated data=21 +DEAL:1::#cells = 16 +DEAL:1::Checksum: 0 +DEAL:1::writing with 5 +DEAL:1::packing cell 0_1:1 with data size=52 accumulated data=78 +DEAL:1::packing cell 0_1:2 with data size=56 accumulated data=91 +DEAL:1::#cells = 16 +DEAL:1::Checksum: 0 + + +DEAL:2::writing with 3 +DEAL:2::packing cell 2_1:0 with data size=4 accumulated data=0 +DEAL:2::packing cell 2_1:1 with data size=8 accumulated data=1 +DEAL:2::packing cell 2_1:2 with data size=12 accumulated data=3 +DEAL:2::packing cell 2_1:3 with data size=16 accumulated data=6 +DEAL:2::packing cell 3_0: with data size=20 accumulated data=10 +DEAL:2::#cells = 16 +DEAL:2::Checksum: 0 +DEAL:2::writing with 3 +DEAL:2::packing cell 2_1:0 with data size=24 accumulated data=15 +DEAL:2::packing cell 2_1:1 with data size=28 accumulated data=21 +DEAL:2::packing cell 2_1:2 with data size=32 accumulated data=28 +DEAL:2::packing cell 2_1:3 with data size=36 accumulated data=36 +DEAL:2::packing cell 3_0: with data size=40 accumulated data=45 +DEAL:2::#cells = 16 +DEAL:2::Checksum: 0 +DEAL:2::reading with 5 +DEAL:2::unpacking cell 0_1:3 with data size=32 accumulated data=28 +DEAL:2::unpacking cell 1_1:0 with data size=36 accumulated data=36 +DEAL:2::unpacking cell 1_1:1 with data size=40 accumulated data=45 +DEAL:2::unpacking cell 1_1:2 with data size=44 accumulated data=55 +DEAL:2::unpacking cell 1_1:3 with data size=48 accumulated data=66 +DEAL:2::#cells = 16 +DEAL:2::Checksum: 0 +DEAL:2::writing with 5 +DEAL:2::packing cell 0_1:3 with data size=44 accumulated data=55 +DEAL:2::packing cell 1_1:0 with data size=48 accumulated data=66 +DEAL:2::packing cell 1_1:1 with data size=52 accumulated data=78 +DEAL:2::packing cell 1_1:2 with data size=56 accumulated data=91 +DEAL:2::packing cell 1_1:3 with data size=60 accumulated data=105 +DEAL:2::#cells = 16 +DEAL:2::Checksum: 0 + + +DEAL:3::reading with 5 +DEAL:3::#cells = 16 +DEAL:3::Checksum: 0 +DEAL:3::writing with 5 +DEAL:3::#cells = 16 +DEAL:3::Checksum: 0 + + +DEAL:4::reading with 5 +DEAL:4::unpacking cell 2_1:0 with data size=24 accumulated data=15 +DEAL:4::unpacking cell 2_1:1 with data size=28 accumulated data=21 +DEAL:4::unpacking cell 2_1:2 with data size=32 accumulated data=28 +DEAL:4::unpacking cell 2_1:3 with data size=36 accumulated data=36 +DEAL:4::unpacking cell 3_0: with data size=40 accumulated data=45 +DEAL:4::#cells = 16 +DEAL:4::Checksum: 0 +DEAL:4::writing with 5 +DEAL:4::packing cell 2_1:0 with data size=4 accumulated data=0 +DEAL:4::packing cell 2_1:1 with data size=8 accumulated data=1 +DEAL:4::packing cell 2_1:2 with data size=12 accumulated data=3 +DEAL:4::packing cell 2_1:3 with data size=16 accumulated data=6 +DEAL:4::packing cell 3_0: with data size=20 accumulated data=10 +DEAL:4::#cells = 16 +DEAL:4::Checksum: 0 + diff --git a/tests/mpi/p4est_save_07.with_petsc=true.mpirun=4.output b/tests/mpi/p4est_save_07.with_petsc=true.mpirun=4.output new file mode 100644 index 000000000000..bf97dfd8ef1a --- /dev/null +++ b/tests/mpi/p4est_save_07.with_petsc=true.mpirun=4.output @@ -0,0 +1,10 @@ + +DEAL:0:2d::hyper_cube +DEAL:0:2d::#cells = 19 +DEAL:0:2d::cells(0) = 10 +DEAL:0:2d::Checksum: 136119115 +DEAL:0:2d::#cells = 19 +DEAL:0:2d::cells(0) = 10 +DEAL:0:2d::Checksum: 136119115 +DEAL:0:2d::sum: 435.000 870.000 +DEAL:0:2d::OK From 197cb40c92db95ebf2c3a657b783ca543899ac4c Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 31 Jan 2019 23:47:38 +0100 Subject: [PATCH 046/507] Be explicit about initialization of static const Tensor variables --- include/deal.II/base/patterns.h | 2 +- include/deal.II/base/tensor_function.templates.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/deal.II/base/patterns.h b/include/deal.II/base/patterns.h index 2789bf843407..d4ea6babc0b2 100644 --- a/include/deal.II/base/patterns.h +++ b/include/deal.II/base/patterns.h @@ -1521,7 +1521,7 @@ namespace Patterns std::is_same::value || std::is_same::value) str << static_cast(value); else if (std::is_same::value) - str << (value ? "true" : "false"); + str << (static_cast(value) ? "true" : "false"); else str << value; AssertThrow(p->match(str.str()), ExcNoMatch(str.str(), p.get())); diff --git a/include/deal.II/base/tensor_function.templates.h b/include/deal.II/base/tensor_function.templates.h index cb53e448c14d..d760d22070bf 100644 --- a/include/deal.II/base/tensor_function.templates.h +++ b/include/deal.II/base/tensor_function.templates.h @@ -123,7 +123,7 @@ template typename TensorFunction::gradient_type ConstantTensorFunction::gradient(const Point &) const { - static const Tensor zero; + static const Tensor zero{}; return zero; } @@ -140,7 +140,7 @@ ConstantTensorFunction::gradient_list( Assert(gradients.size() == points.size(), ExcDimensionMismatch(gradients.size(), points.size())); - static const Tensor zero; + static const Tensor zero{}; for (unsigned int i = 0; i < gradients.size(); ++i) gradients[i] = zero; From c2c8f2bd282863ed710fc5a0c504cdfc554d143c Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 1 Feb 2019 14:12:29 +0100 Subject: [PATCH 047/507] Fix compiling with MSVC --- include/deal.II/base/subscriptor.h | 5 +++++ include/deal.II/base/vectorization.h | 4 ++-- source/base/vectorization.cc | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/deal.II/base/subscriptor.h b/include/deal.II/base/subscriptor.h index 431f8c03e412..aae53ff17d17 100644 --- a/include/deal.II/base/subscriptor.h +++ b/include/deal.II/base/subscriptor.h @@ -340,6 +340,11 @@ Subscriptor::list_subscribers(StreamType &stream) const << it.first << '\"' << std::endl; } +// forward declare template specialization +template <> +void +Subscriptor::subscribe(std::atomic *const validity, + const char * id) const; DEAL_II_NAMESPACE_CLOSE #endif diff --git a/include/deal.II/base/vectorization.h b/include/deal.II/base/vectorization.h index 3f82e165c52e..1b8c47005c3c 100644 --- a/include/deal.II/base/vectorization.h +++ b/include/deal.II/base/vectorization.h @@ -178,7 +178,7 @@ class VectorizedArray * case, there is only one element. Specializations use SIMD intrinsics and * can work on multiple elements at the same time. */ - static const unsigned int n_array_elements; + static const unsigned int n_array_elements = 1; // POD means that there should be no user-defined constructors, destructors // and copy functions (the standard is somewhat relaxed in C++2011, though). @@ -453,7 +453,7 @@ class VectorizedArray // We need to have a separate declaration for static const members template -const unsigned int VectorizedArray::n_array_elements = 1; +const unsigned int VectorizedArray::n_array_elements; diff --git a/source/base/vectorization.cc b/source/base/vectorization.cc index 1cc3fe6de667..88ffb1f6bce9 100644 --- a/source/base/vectorization.cc +++ b/source/base/vectorization.cc @@ -17,7 +17,7 @@ DEAL_II_NAMESPACE_OPEN -#if DEAL_II_COMPILER_VECTORIZATION_LEVEL >= 1 +#if DEAL_II_COMPILER_VECTORIZATION_LEVEL >= 1 && !defined(DEAL_II_MSVC) const unsigned int VectorizedArray::n_array_elements; const unsigned int VectorizedArray::n_array_elements; #endif From 7bb7d7bbe8af22f094e70fc01b9f4c4c4fb86963 Mon Sep 17 00:00:00 2001 From: Rene Gassmoeller Date: Thu, 31 Jan 2019 10:24:06 -0800 Subject: [PATCH 048/507] Ensure particle property initialization --- source/particles/particle.cc | 10 ++++- tests/particles/particle_07.cc | 64 ++++++++++++++++++++++++++++++ tests/particles/particle_07.output | 2 + 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 tests/particles/particle_07.cc create mode 100644 tests/particles/particle_07.output diff --git a/source/particles/particle.cc b/source/particles/particle.cc index 03f90811b333..b426aac4ccdb 100644 --- a/source/particles/particle.cc +++ b/source/particles/particle.cc @@ -328,8 +328,16 @@ namespace Particles { Assert(property_pool != nullptr, ExcInternalError()); + // If this particle has no properties yet, allocate and initialize them. if (properties == PropertyPool::invalid_handle) - properties = property_pool->allocate_properties_array(); + { + properties = property_pool->allocate_properties_array(); + + ArrayView my_properties = + property_pool->get_properties(properties); + + std::fill(my_properties.begin(), my_properties.end(), 0.0); + } return property_pool->get_properties(properties); } diff --git a/tests/particles/particle_07.cc b/tests/particles/particle_07.cc new file mode 100644 index 000000000000..0df754f23fdf --- /dev/null +++ b/tests/particles/particle_07.cc @@ -0,0 +1,64 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2017 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. +// +// --------------------------------------------------------------------- + + + +// Like particle_03, but test property initialization. + +#include + +#include + +#include "../tests.h" + + +template +void +test() +{ + { + const unsigned int n_properties_per_particle = 3; + Particles::PropertyPool pool(n_properties_per_particle); + + Point<2> position; + position(0) = 0.3; + position(1) = 0.5; + + Point<2> reference_position; + reference_position(0) = 0.2; + reference_position(1) = 0.4; + + const types::particle_index index(7); + + std::vector properties = {0.15, 0.45, 0.75}; + + Particles::Particle<2> particle(position, reference_position, index); + particle.set_property_pool(pool); + + for (unsigned int i = 0; i < n_properties_per_particle; ++i) + AssertThrow(particle.get_properties()[i] == 0.0, ExcInternalError()); + } + + deallog << "OK" << std::endl; +} + + + +int +main() +{ + initlog(); + test<2>(); +} diff --git a/tests/particles/particle_07.output b/tests/particles/particle_07.output new file mode 100644 index 000000000000..0fd8fc12f0b4 --- /dev/null +++ b/tests/particles/particle_07.output @@ -0,0 +1,2 @@ + +DEAL::OK From a5e1a72930e4b8f7b791125dbb1ea35f9a480092 Mon Sep 17 00:00:00 2001 From: Daniel Garcia-Sanchez Date: Sat, 2 Feb 2019 14:26:44 +0100 Subject: [PATCH 049/507] Remove unused variable warning --- source/grid/grid_in.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/grid/grid_in.cc b/source/grid/grid_in.cc index aaa1b79d945c..ad18740f2849 100644 --- a/source/grid/grid_in.cc +++ b/source/grid/grid_in.cc @@ -2436,9 +2436,12 @@ GridIn<3>::read_netcdf(const std::string &filename) // take numbers::internal_face_boundary_id // as it denotes an internal face for (const int id : bmarker) - Assert(0 <= id && static_cast(id) != - numbers::internal_face_boundary_id, - ExcIO()); + { + Assert(0 <= id && static_cast(id) != + numbers::internal_face_boundary_id, + ExcIO()); + (void)id; + } // finally we setup the boundary // information From 40538ad31a71495649d174b0f7be5f7135d0a905 Mon Sep 17 00:00:00 2001 From: David Wells Date: Sat, 2 Feb 2019 10:00:38 -0500 Subject: [PATCH 050/507] Avoid calling a deprecated MPI function. This was deprecated a long time ago (1996) and is not present in the latest version of openMPI (4.0): see https://www.open-mpi.org/faq/?category=mpi-removed Credit goes to Pratik Nayak for finding this issue. --- source/base/mpi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/base/mpi.cc b/source/base/mpi.cc index bd1f7f9846a2..b8cd45e7c26a 100644 --- a/source/base/mpi.cc +++ b/source/base/mpi.cc @@ -448,7 +448,7 @@ namespace Utilities MPI_Aint displacements[] = {0, offsetof(MinMaxAvg, min_index)}; MPI_Datatype types[] = {MPI_DOUBLE, MPI_INT}; - ierr = MPI_Type_struct(2, lengths, displacements, types, &type); + ierr = MPI_Type_create_struct(2, lengths, displacements, types, &type); AssertThrowMPI(ierr); ierr = MPI_Type_commit(&type); From c08769422a8c0775fde64452a9ef57d345fc3892 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Fri, 1 Feb 2019 08:04:58 -0700 Subject: [PATCH 051/507] Simplify some code. --- include/deal.II/base/tensor_function.templates.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/deal.II/base/tensor_function.templates.h b/include/deal.II/base/tensor_function.templates.h index d760d22070bf..11c2f54cb73a 100644 --- a/include/deal.II/base/tensor_function.templates.h +++ b/include/deal.II/base/tensor_function.templates.h @@ -123,9 +123,8 @@ template typename TensorFunction::gradient_type ConstantTensorFunction::gradient(const Point &) const { - static const Tensor zero{}; - - return zero; + // Return a zero (=default initialized) tensor + return {}; } @@ -140,10 +139,10 @@ ConstantTensorFunction::gradient_list( Assert(gradients.size() == points.size(), ExcDimensionMismatch(gradients.size(), points.size())); - static const Tensor zero{}; - - for (unsigned int i = 0; i < gradients.size(); ++i) - gradients[i] = zero; + // Return an array of zero tensors. + std::fill(gradients.begin(), + gradients.end(), + typename TensorFunction::gradient_type()); } From 7d5993168d1ce1d8e12b743f924faa16827f6842 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 2 Feb 2019 13:05:31 +0100 Subject: [PATCH 052/507] Fix p4est test --- ...5.output => p4est_save_05.mpirun=5.output} | 0 tests/mpi/p4est_save_07.mpirun=4.output | 114 ++++++++++++++++++ ...5.output => p4est_save_07.mpirun=5.output} | 0 ...st_save_07.with_petsc=true.mpirun=4.output | 10 -- 4 files changed, 114 insertions(+), 10 deletions(-) rename tests/mpi/{p4est_save_05.with_p4est=true.mpirun=5.output => p4est_save_05.mpirun=5.output} (100%) create mode 100644 tests/mpi/p4est_save_07.mpirun=4.output rename tests/mpi/{p4est_save_07.with_p4est=true.mpirun=5.output => p4est_save_07.mpirun=5.output} (100%) delete mode 100644 tests/mpi/p4est_save_07.with_petsc=true.mpirun=4.output diff --git a/tests/mpi/p4est_save_05.with_p4est=true.mpirun=5.output b/tests/mpi/p4est_save_05.mpirun=5.output similarity index 100% rename from tests/mpi/p4est_save_05.with_p4est=true.mpirun=5.output rename to tests/mpi/p4est_save_05.mpirun=5.output diff --git a/tests/mpi/p4est_save_07.mpirun=4.output b/tests/mpi/p4est_save_07.mpirun=4.output new file mode 100644 index 000000000000..92b527f8aa94 --- /dev/null +++ b/tests/mpi/p4est_save_07.mpirun=4.output @@ -0,0 +1,114 @@ + +DEAL:0::writing with 3 +DEAL:0::packing cell 0_2:00 with data size=4 accumulated data=0 +DEAL:0::packing cell 0_2:01 with data size=8 accumulated data=1 +DEAL:0::packing cell 0_2:02 with data size=12 accumulated data=3 +DEAL:0::packing cell 0_2:03 with data size=16 accumulated data=6 +DEAL:0::packing cell 0_1:1 with data size=20 accumulated data=10 +DEAL:0::#cells = 16 +DEAL:0::Checksum: 2822439380 +DEAL:0::writing with 3 +DEAL:0::packing cell 0_2:00 with data size=24 accumulated data=15 +DEAL:0::packing cell 0_2:01 with data size=28 accumulated data=21 +DEAL:0::packing cell 0_2:02 with data size=32 accumulated data=28 +DEAL:0::packing cell 0_2:03 with data size=36 accumulated data=36 +DEAL:0::packing cell 0_1:1 with data size=40 accumulated data=45 +DEAL:0::#cells = 16 +DEAL:0::Checksum: 2822439380 +DEAL:0::reading with 4 +DEAL:0::unpacking cell 0_2:00 with data size=24 accumulated data=15 +DEAL:0::unpacking cell 0_2:01 with data size=28 accumulated data=21 +DEAL:0::unpacking cell 0_2:02 with data size=32 accumulated data=28 +DEAL:0::unpacking cell 0_2:03 with data size=36 accumulated data=36 +DEAL:0::#cells = 16 +DEAL:0::Checksum: 2822439380 +DEAL:0::writing with 4 +DEAL:0::packing cell 0_2:00 with data size=44 accumulated data=55 +DEAL:0::packing cell 0_2:01 with data size=48 accumulated data=66 +DEAL:0::packing cell 0_2:02 with data size=52 accumulated data=78 +DEAL:0::packing cell 0_2:03 with data size=56 accumulated data=91 +DEAL:0::#cells = 16 +DEAL:0::Checksum: 2822439380 +DEAL:0::OK + +DEAL:1::writing with 3 +DEAL:1::packing cell 0_1:2 with data size=4 accumulated data=0 +DEAL:1::packing cell 0_1:3 with data size=8 accumulated data=1 +DEAL:1::packing cell 1_1:0 with data size=12 accumulated data=3 +DEAL:1::packing cell 1_1:1 with data size=16 accumulated data=6 +DEAL:1::packing cell 1_1:2 with data size=20 accumulated data=10 +DEAL:1::packing cell 1_1:3 with data size=24 accumulated data=15 +DEAL:1::#cells = 16 +DEAL:1::Checksum: 0 +DEAL:1::writing with 3 +DEAL:1::packing cell 0_1:2 with data size=28 accumulated data=21 +DEAL:1::packing cell 0_1:3 with data size=32 accumulated data=28 +DEAL:1::packing cell 1_1:0 with data size=36 accumulated data=36 +DEAL:1::packing cell 1_1:1 with data size=40 accumulated data=45 +DEAL:1::packing cell 1_1:2 with data size=44 accumulated data=55 +DEAL:1::packing cell 1_1:3 with data size=48 accumulated data=66 +DEAL:1::#cells = 16 +DEAL:1::Checksum: 0 +DEAL:1::reading with 4 +DEAL:1::unpacking cell 0_1:1 with data size=40 accumulated data=45 +DEAL:1::unpacking cell 0_1:2 with data size=28 accumulated data=21 +DEAL:1::unpacking cell 0_1:3 with data size=32 accumulated data=28 +DEAL:1::#cells = 16 +DEAL:1::Checksum: 0 +DEAL:1::writing with 4 +DEAL:1::packing cell 0_1:1 with data size=52 accumulated data=78 +DEAL:1::packing cell 0_1:2 with data size=56 accumulated data=91 +DEAL:1::packing cell 0_1:3 with data size=60 accumulated data=105 +DEAL:1::#cells = 16 +DEAL:1::Checksum: 0 + + +DEAL:2::writing with 3 +DEAL:2::packing cell 2_1:0 with data size=4 accumulated data=0 +DEAL:2::packing cell 2_1:1 with data size=8 accumulated data=1 +DEAL:2::packing cell 2_1:2 with data size=12 accumulated data=3 +DEAL:2::packing cell 2_1:3 with data size=16 accumulated data=6 +DEAL:2::packing cell 3_0: with data size=20 accumulated data=10 +DEAL:2::#cells = 16 +DEAL:2::Checksum: 0 +DEAL:2::writing with 3 +DEAL:2::packing cell 2_1:0 with data size=24 accumulated data=15 +DEAL:2::packing cell 2_1:1 with data size=28 accumulated data=21 +DEAL:2::packing cell 2_1:2 with data size=32 accumulated data=28 +DEAL:2::packing cell 2_1:3 with data size=36 accumulated data=36 +DEAL:2::packing cell 3_0: with data size=40 accumulated data=45 +DEAL:2::#cells = 16 +DEAL:2::Checksum: 0 +DEAL:2::reading with 4 +DEAL:2::unpacking cell 1_1:0 with data size=36 accumulated data=36 +DEAL:2::unpacking cell 1_1:1 with data size=40 accumulated data=45 +DEAL:2::unpacking cell 1_1:2 with data size=44 accumulated data=55 +DEAL:2::unpacking cell 1_1:3 with data size=48 accumulated data=66 +DEAL:2::#cells = 16 +DEAL:2::Checksum: 0 +DEAL:2::writing with 4 +DEAL:2::packing cell 1_1:0 with data size=44 accumulated data=55 +DEAL:2::packing cell 1_1:1 with data size=48 accumulated data=66 +DEAL:2::packing cell 1_1:2 with data size=52 accumulated data=78 +DEAL:2::packing cell 1_1:3 with data size=56 accumulated data=91 +DEAL:2::#cells = 16 +DEAL:2::Checksum: 0 + + +DEAL:3::reading with 4 +DEAL:3::unpacking cell 2_1:0 with data size=24 accumulated data=15 +DEAL:3::unpacking cell 2_1:1 with data size=28 accumulated data=21 +DEAL:3::unpacking cell 2_1:2 with data size=32 accumulated data=28 +DEAL:3::unpacking cell 2_1:3 with data size=36 accumulated data=36 +DEAL:3::unpacking cell 3_0: with data size=40 accumulated data=45 +DEAL:3::#cells = 16 +DEAL:3::Checksum: 0 +DEAL:3::writing with 4 +DEAL:3::packing cell 2_1:0 with data size=4 accumulated data=0 +DEAL:3::packing cell 2_1:1 with data size=8 accumulated data=1 +DEAL:3::packing cell 2_1:2 with data size=12 accumulated data=3 +DEAL:3::packing cell 2_1:3 with data size=16 accumulated data=6 +DEAL:3::packing cell 3_0: with data size=20 accumulated data=10 +DEAL:3::#cells = 16 +DEAL:3::Checksum: 0 + diff --git a/tests/mpi/p4est_save_07.with_p4est=true.mpirun=5.output b/tests/mpi/p4est_save_07.mpirun=5.output similarity index 100% rename from tests/mpi/p4est_save_07.with_p4est=true.mpirun=5.output rename to tests/mpi/p4est_save_07.mpirun=5.output diff --git a/tests/mpi/p4est_save_07.with_petsc=true.mpirun=4.output b/tests/mpi/p4est_save_07.with_petsc=true.mpirun=4.output deleted file mode 100644 index bf97dfd8ef1a..000000000000 --- a/tests/mpi/p4est_save_07.with_petsc=true.mpirun=4.output +++ /dev/null @@ -1,10 +0,0 @@ - -DEAL:0:2d::hyper_cube -DEAL:0:2d::#cells = 19 -DEAL:0:2d::cells(0) = 10 -DEAL:0:2d::Checksum: 136119115 -DEAL:0:2d::#cells = 19 -DEAL:0:2d::cells(0) = 10 -DEAL:0:2d::Checksum: 136119115 -DEAL:0:2d::sum: 435.000 870.000 -DEAL:0:2d::OK From 78b5898a7afc8417e5696d239373372a6de57069 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 2 Feb 2019 18:45:12 +0100 Subject: [PATCH 053/507] Document the minimal supported MPI version --- doc/news/changes/minor/20190202Arndt | 3 +++ doc/readme.html | 1 + 2 files changed, 4 insertions(+) create mode 100644 doc/news/changes/minor/20190202Arndt 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/readme.html b/doc/readme.html index 9d7cf59ead41..f938801714e6 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -312,6 +312,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.

From 9df0fcfeb3477ca73a718eafdc1b661150ce4372 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 3 Feb 2019 12:06:36 +0100 Subject: [PATCH 054/507] Fix building TBB with nvcc_wrapper --- include/deal.II/base/function_parser.h | 8 ------ include/deal.II/base/thread_management.h | 9 ------ source/matrix_free/task_info.cc | 36 +++++++++++------------- 3 files changed, 17 insertions(+), 36 deletions(-) diff --git a/include/deal.II/base/function_parser.h b/include/deal.II/base/function_parser.h index fc03c246d249..d8f07a35481b 100644 --- a/include/deal.II/base/function_parser.h +++ b/include/deal.II/base/function_parser.h @@ -379,16 +379,8 @@ class FunctionParser : public AutoDerivativeFunction * storing a unique_ptr so that we don't need to include the definition of * mu::Parser in this header. */ -# if TBB_VERSION_MAJOR >= 4 mutable Threads::ThreadLocalStorage>> fp; -# else - // older TBBs have a bug in which they want to return thread-local - // objects by value. this doesn't work for std::unique_ptr, so use a - // std::shared_ptr - mutable Threads::ThreadLocalStorage>> - fp; -# endif /** * An array to keep track of all the constants, required to initialize fp in diff --git a/include/deal.II/base/thread_management.h b/include/deal.II/base/thread_management.h index b3993b51b790..931e7f30d705 100644 --- a/include/deal.II/base/thread_management.h +++ b/include/deal.II/base/thread_management.h @@ -1353,16 +1353,7 @@ namespace Threads tbb::task *worker = new (task->allocate_child()) TaskEntryPoint(*this); - // in earlier versions of the TBB, task::spawn was a regular - // member function; however, in later versions, it was converted - // into a static function. we could always call it as a regular member - // function of *task, but that appears to confuse the NVidia nvcc - // compiler. consequently, the following work-around: -# if TBB_VERSION_MAJOR >= 4 tbb::task::spawn(*worker); -# else - task->spawn(*worker); -# endif } diff --git a/source/matrix_free/task_info.cc b/source/matrix_free/task_info.cc index a1617d4c3dc0..33bee62a3cc6 100644 --- a/source/matrix_free/task_info.cc +++ b/source/matrix_free/task_info.cc @@ -118,7 +118,7 @@ namespace internal work(); if (is_blocked == true) - dummy->spawn(*dummy); + tbb::empty_task::spawn(*dummy); return nullptr; } @@ -172,7 +172,7 @@ namespace internal worker[j]->set_ref_count(2); blocked_worker[j - 1]->dummy = new (worker[j]->allocate_child()) tbb::empty_task; - worker[j - 1]->spawn(*blocked_worker[j - 1]); + tbb::task::spawn(*blocked_worker[j - 1]); } else worker[j]->set_ref_count(1); @@ -195,13 +195,13 @@ namespace internal 2 * j + 1, task_info, false); - worker[j]->spawn(*worker[evens]); + tbb::task::spawn(*worker[evens]); } else { tbb::empty_task *child = new (worker[j]->allocate_child()) tbb::empty_task(); - worker[j]->spawn(*child); + tbb::task::spawn(*child); } } } @@ -209,7 +209,7 @@ namespace internal root->wait_for_all(); root->destroy(*root); if (is_blocked == true) - dummy->spawn(*dummy); + tbb::empty_task::spawn(*dummy); return nullptr; } @@ -289,7 +289,7 @@ namespace internal parallel_for(tbb::blocked_range(0, n_chunks, 1), CellWork(worker, task_info, partition)); if (is_blocked == true) - dummy->spawn(*dummy); + tbb::empty_task::spawn(*dummy); return nullptr; } @@ -364,9 +364,9 @@ namespace internal blocked_worker[j - 1]->dummy = new (worker[j]->allocate_child()) tbb::empty_task; if (j > 1) - worker[j - 1]->spawn(*blocked_worker[j - 1]); + tbb::task::spawn(*blocked_worker[j - 1]); else - worker_compr->spawn(*blocked_worker[j - 1]); + tbb::task::spawn(*blocked_worker[j - 1]); } else { @@ -376,7 +376,7 @@ namespace internal MPICommunication *worker_dist = new (worker[j]->allocate_child()) MPICommunication(funct, false); - worker_dist->spawn(*worker_dist); + tbb::task::spawn(*worker_dist); } if (j < evens - 1) { @@ -392,13 +392,13 @@ namespace internal 2 * j + 1, *this, false); - worker[j]->spawn(*worker[evens]); + tbb::task::spawn(*worker[evens]); } else { tbb::empty_task *child = new (worker[j]->allocate_child()) tbb::empty_task(); - worker[j]->spawn(*child); + tbb::task::spawn(*child); } } } @@ -467,14 +467,12 @@ namespace internal tbb::empty_task; worker_index++; if (spawn_index_child == -1) - worker[spawn_index]->spawn( - *blocked_worker[(part - 1) / 2]); + tbb::task::spawn(*blocked_worker[(part - 1) / 2]); else { Assert(spawn_index_child >= 0, ExcInternalError()); - worker[spawn_index]->spawn( - *worker[spawn_index_child]); + tbb::task::spawn(*worker[spawn_index_child]); } spawn_index = spawn_index_new; spawn_index_child = -2; @@ -484,7 +482,7 @@ namespace internal MPICommunication *worker_dist = new (worker[worker_index]->allocate_child()) MPICommunication(funct, false); - worker_dist->spawn(*worker_dist); + tbb::task::spawn(*worker_dist); worker_index++; } part += 1; @@ -539,14 +537,14 @@ namespace internal tbb::empty_task *final = new (worker[worker_index - 1]->allocate_child()) tbb::empty_task; - worker[spawn_index]->spawn(*final); + tbb::task::spawn(*final); spawn_index_child = worker_index - 1; } } if (evens == odds) { Assert(spawn_index_child >= 0, ExcInternalError()); - worker[spawn_index]->spawn(*worker[spawn_index_child]); + tbb::task::spawn(*worker[spawn_index_child]); } root->wait_for_all(); root->destroy(*root); @@ -568,7 +566,7 @@ namespace internal color::PartitionWork *worker = new (root->allocate_child()) color::PartitionWork(funct, color, *this, false); - root->spawn(*worker); + tbb::empty_task::spawn(*worker); root->wait_for_all(); root->destroy(*root); } From 6261c20ca19fa3f9ba370bf8c84a963e9bfc4578 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 3 Feb 2019 14:04:33 +0100 Subject: [PATCH 055/507] Remove unused variables --- source/matrix_free/task_info.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/matrix_free/task_info.cc b/source/matrix_free/task_info.cc index 33bee62a3cc6..1fd323d2cfa6 100644 --- a/source/matrix_free/task_info.cc +++ b/source/matrix_free/task_info.cc @@ -423,7 +423,6 @@ namespace internal std::vector blocked_worker( n_blocked_workers); unsigned int worker_index = 0, slice_index = 0; - unsigned int spawn_index = 0; int spawn_index_child = -2; MPICommunication *worker_compr = new (root->allocate_child()) MPICommunication(funct, true); @@ -432,7 +431,6 @@ namespace internal part < partition_row_index.size() - 1; part++) { - const unsigned int spawn_index_new = worker_index; if (part == 0) worker[worker_index] = new (worker_compr->allocate_child()) @@ -474,7 +472,6 @@ namespace internal ExcInternalError()); tbb::task::spawn(*worker[spawn_index_child]); } - spawn_index = spawn_index_new; spawn_index_child = -2; } else From 0f9ec68aaf5b9b3d750b90b5817a3cd689bba555 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Sun, 3 Feb 2019 12:06:59 -0600 Subject: [PATCH 056/507] CMake: Bugfix: Guard DEAL_II_HAVE_OPENMP_SIMD test We also have to guard the DEAL_II_HAVE_OPENMP_SIMD test with DEAL_II_ALLOW_PLATFORM_INTROSPECTION. If the latter is set to false our cmake configuration does not attempt to determine any specifics of the unerlying CPU or architecture (and instead relies on the user specifying everything by hand). This is necessary for scenarios where deal.II gets compiled on a different machine than the one it will be run on eventually. In reference to #7663. --- cmake/checks/check_01_cpu_features.cmake | 54 +++++++++++++++--------- 1 file changed, 33 insertions(+), 21 deletions(-) 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) From 7c3223347d55c131c4daf797b3ba579007e56dca Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 4 Feb 2019 02:08:20 +0100 Subject: [PATCH 057/507] Fix MPI support for older versions --- include/deal.II/lac/scalapack.h | 3 +++ source/lac/scalapack.cc | 20 ++++++++++++++++---- source/lac/sparsity_tools.cc | 30 ++++++++++++++++-------------- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/include/deal.II/lac/scalapack.h b/include/deal.II/lac/scalapack.h index e44ef1ffe48c..ebc212f622fd 100644 --- a/include/deal.II/lac/scalapack.h +++ b/include/deal.II/lac/scalapack.h @@ -203,6 +203,8 @@ class ScaLAPACKMatrix : protected TransposeTable * The user has to ensure that all processes call this with identical @p rank. * The @p rank refers to a process of the MPI communicator used to create the process grid * of the distributed matrix. + * + * @note This function requires MPI-3.0 support */ void copy_from(const LAPACKFullMatrix &matrix, @@ -213,6 +215,7 @@ class ScaLAPACKMatrix : protected TransposeTable * * @note This function should only be used for relatively small matrix * dimensions. It is primarily intended for debugging purposes. + * This function requires MPI-3.0 support */ void copy_to(FullMatrix &matrix) const; diff --git a/source/lac/scalapack.cc b/source/lac/scalapack.cc index 9a5f1bb15735..8651557833d8 100644 --- a/source/lac/scalapack.cc +++ b/source/lac/scalapack.cc @@ -361,18 +361,19 @@ void ScaLAPACKMatrix::copy_from(const LAPACKFullMatrix &B, const unsigned int rank) { +# if DEAL_II_MPI_VERSION_GTE(3, 0) if (n_rows * n_columns == 0) return; const unsigned int this_mpi_process( Utilities::MPI::this_mpi_process(this->grid->mpi_communicator)); -# ifdef DEBUG +# ifdef DEBUG Assert(Utilities::MPI::max(rank, this->grid->mpi_communicator) == rank, ExcMessage("All processes have to call routine with identical rank")); Assert(Utilities::MPI::min(rank, this->grid->mpi_communicator) == rank, ExcMessage("All processes have to call routine with identical rank")); -# endif +# endif // root process has to be active in the grid of A if (this_mpi_process == rank) @@ -484,6 +485,11 @@ ScaLAPACKMatrix::copy_from(const LAPACKFullMatrix &B, MPI_Comm_free(&communicator_B); state = LAPACKSupport::matrix; +# else + (void)B; + (void)rank; + AssertThrow(false, ExcNotImplemented()); +# endif } @@ -528,18 +534,19 @@ void ScaLAPACKMatrix::copy_to(LAPACKFullMatrix &B, const unsigned int rank) const { +# if DEAL_II_MPI_VERSION_GTE(3, 0) if (n_rows * n_columns == 0) return; const unsigned int this_mpi_process( Utilities::MPI::this_mpi_process(this->grid->mpi_communicator)); -# ifdef DEBUG +# ifdef DEBUG Assert(Utilities::MPI::max(rank, this->grid->mpi_communicator) == rank, ExcMessage("All processes have to call routine with identical rank")); Assert(Utilities::MPI::min(rank, this->grid->mpi_communicator) == rank, ExcMessage("All processes have to call routine with identical rank")); -# endif +# endif if (this_mpi_process == rank) { @@ -650,6 +657,11 @@ ScaLAPACKMatrix::copy_to(LAPACKFullMatrix &B, MPI_Group_free(&group_B); if (MPI_COMM_NULL != communicator_B) MPI_Comm_free(&communicator_B); +# else + (void)B; + (void)rank; + AssertThrow(false, ExcNotImplemented()); +# endif } diff --git a/source/lac/sparsity_tools.cc b/source/lac/sparsity_tools.cc index e6698f28aa2c..e04c9e54f4fa 100644 --- a/source/lac/sparsity_tools.cc +++ b/source/lac/sparsity_tools.cc @@ -994,13 +994,14 @@ namespace SparsityTools unsigned int idx = 0; for (const auto &sparsity_line : send_data) { - const int ierr = MPI_Isend(sparsity_line.second.data(), - sparsity_line.second.size(), - DEAL_II_DOF_INDEX_MPI_TYPE, - sparsity_line.first, - 124, - mpi_comm, - &requests[idx++]); + const int ierr = + MPI_Isend(DEAL_II_MPI_CONST_CAST(sparsity_line.second.data()), + sparsity_line.second.size(), + DEAL_II_DOF_INDEX_MPI_TYPE, + sparsity_line.first, + 124, + mpi_comm, + &requests[idx++]); AssertThrowMPI(ierr); } } @@ -1138,13 +1139,14 @@ namespace SparsityTools unsigned int idx = 0; for (const auto &sparsity_line : send_data) { - const int ierr = MPI_Isend(sparsity_line.second.data(), - sparsity_line.second.size(), - DEAL_II_DOF_INDEX_MPI_TYPE, - sparsity_line.first, - 124, - mpi_comm, - &requests[idx++]); + const int ierr = + MPI_Isend(DEAL_II_MPI_CONST_CAST(sparsity_line.second.data()), + sparsity_line.second.size(), + DEAL_II_DOF_INDEX_MPI_TYPE, + sparsity_line.first, + 124, + mpi_comm, + &requests[idx++]); AssertThrowMPI(ierr); } } From ddbb09b90e85afb1f0e1f039500036fec4681e24 Mon Sep 17 00:00:00 2001 From: Stefan Meggendorfer Date: Mon, 4 Feb 2019 14:56:57 +0100 Subject: [PATCH 058/507] MappingQGeneric: use of MatrixFree only for higher order elements --- source/fe/mapping_q_generic.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/fe/mapping_q_generic.cc b/source/fe/mapping_q_generic.cc index 4dfaf968dc6c..d7d8e96d88f2 100644 --- a/source/fe/mapping_q_generic.cc +++ b/source/fe/mapping_q_generic.cc @@ -730,6 +730,10 @@ MappingQGeneric::InternalData::initialize( tensor_product_quadrature = q.is_tensor_product(); + // use of MatrixFree only for higher order elements + if (polynomial_degree < 2) + tensor_product_quadrature = false; + if (dim > 1) { // find out if the one-dimensional formula is the same From 4112d6b0a296ce9bdaa8c4639faa15c41a41ef82 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 4 Feb 2019 17:12:06 +0100 Subject: [PATCH 059/507] More output files for matrix_free/dof_info_01/2 --- ...=true.with_p4est=true.mpirun=1.output.vec0 | 148 ++++++++++++++++++ ...=true.with_p4est=true.mpirun=1.output.vec1 | 64 ++++++++ ...=true.with_p4est=true.mpirun=1.output.vec3 | 19 +++ ...=true.with_p4est=true.mpirun=1.output.vec0 | 148 ++++++++++++++++++ ...=true.with_p4est=true.mpirun=1.output.vec1 | 64 ++++++++ ...=true.with_p4est=true.mpirun=1.output.vec3 | 19 +++ 6 files changed, 462 insertions(+) create mode 100644 tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec0 create mode 100644 tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec1 create mode 100644 tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec3 create mode 100644 tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec0 create mode 100644 tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec1 create mode 100644 tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec3 diff --git a/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec0 b/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec0 new file mode 100644 index 000000000000..f2547ea76df9 --- /dev/null +++ b/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec0 @@ -0,0 +1,148 @@ + +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 18 19 +DEAL:0:2d:: 16 17 18 19 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 7 19 +DEAL:0:2d:: 6 17 19 20 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 18 19 21 22 +DEAL:0:2d:: 18 19 21 22 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 7 19 22 +DEAL:0:2d:: 7 19 20 22 +DEAL:0:2d::Cell: 4 +DEAL:0:2d:: 2 7 +DEAL:0:2d:: 0 6 7 8 +DEAL:0:2d::Cell: 5 +DEAL:0:2d:: 21 22 23 24 +DEAL:0:2d:: 21 22 23 24 +DEAL:0:2d::Cell: 6 +DEAL:0:2d:: 7 9 22 24 +DEAL:0:2d:: 7 22 24 25 +DEAL:0:2d::Cell: 7 +DEAL:0:2d:: 9 10 23 24 +DEAL:0:2d:: 10 23 24 26 +DEAL:0:2d::Cell: 8 +DEAL:0:2d:: 7 9 10 24 +DEAL:0:2d:: 9 24 25 26 +DEAL:0:2d::Cell: 9 +DEAL:0:2d:: 2 7 9 +DEAL:0:2d:: 2 7 8 9 +DEAL:0:2d::Cell: 10 +DEAL:0:2d:: 2 3 +DEAL:0:2d:: 0 1 2 3 +DEAL:0:2d::Cell: 11 +DEAL:0:2d:: 9 10 11 12 +DEAL:0:2d:: 9 10 11 12 +DEAL:0:2d::Cell: 12 +DEAL:0:2d:: 2 4 9 12 +DEAL:0:2d:: 2 9 12 13 +DEAL:0:2d::Cell: 13 +DEAL:0:2d:: 11 12 14 15 +DEAL:0:2d:: 11 12 14 15 +DEAL:0:2d::Cell: 14 +DEAL:0:2d:: 2 4 12 15 +DEAL:0:2d:: 4 12 13 15 +DEAL:0:2d::Cell: 15 +DEAL:0:2d:: 2 3 4 5 +DEAL:0:2d:: 2 3 4 5 +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 18 19 +DEAL:0:2d:: 16 17 18 19 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 7 19 +DEAL:0:2d:: 6 17 19 20 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 18 19 21 22 +DEAL:0:2d:: 18 19 21 22 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 7 19 22 +DEAL:0:2d:: 7 19 20 22 +DEAL:0:2d::Cell: 4 +DEAL:0:2d:: 2 7 +DEAL:0:2d:: 0 6 7 8 +DEAL:0:2d::Cell: 5 +DEAL:0:2d:: 21 22 23 24 +DEAL:0:2d:: 21 22 23 24 +DEAL:0:2d::Cell: 6 +DEAL:0:2d:: 7 9 22 24 +DEAL:0:2d:: 7 22 24 25 +DEAL:0:2d::Cell: 7 +DEAL:0:2d:: 9 10 23 24 +DEAL:0:2d:: 10 23 24 26 +DEAL:0:2d::Cell: 8 +DEAL:0:2d:: 7 9 10 24 +DEAL:0:2d:: 9 24 25 26 +DEAL:0:2d::Cell: 9 +DEAL:0:2d:: 2 7 9 +DEAL:0:2d:: 2 7 8 9 +DEAL:0:2d::Cell: 10 +DEAL:0:2d:: 2 3 +DEAL:0:2d:: 0 1 2 3 +DEAL:0:2d::Cell: 11 +DEAL:0:2d:: 9 10 11 12 +DEAL:0:2d:: 9 10 11 12 +DEAL:0:2d::Cell: 12 +DEAL:0:2d:: 2 4 9 12 +DEAL:0:2d:: 2 9 12 13 +DEAL:0:2d::Cell: 13 +DEAL:0:2d:: 11 12 14 15 +DEAL:0:2d:: 11 12 14 15 +DEAL:0:2d::Cell: 14 +DEAL:0:2d:: 2 4 12 15 +DEAL:0:2d:: 4 12 13 15 +DEAL:0:2d::Cell: 15 +DEAL:0:2d:: 2 3 4 5 +DEAL:0:2d:: 2 3 4 5 +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 2 3 +DEAL:0:2d:: 0 1 2 3 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 3 5 +DEAL:0:2d:: 1 3 4 5 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 2 3 6 7 +DEAL:0:2d:: 2 3 6 7 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 3 5 7 8 +DEAL:0:2d:: 3 5 7 8 +DEAL:0:2d::Cell: 4 +DEAL:0:2d:: 5 10 +DEAL:0:2d:: 4 5 9 10 +DEAL:0:2d::Cell: 5 +DEAL:0:2d:: 10 12 +DEAL:0:2d:: 9 10 11 12 +DEAL:0:2d::Cell: 6 +DEAL:0:2d:: 5 8 10 13 +DEAL:0:2d:: 5 8 10 13 +DEAL:0:2d::Cell: 7 +DEAL:0:2d:: 10 12 13 14 +DEAL:0:2d:: 10 12 13 14 +DEAL:0:2d::Cell: 8 +DEAL:0:2d:: 6 7 15 16 +DEAL:0:2d:: 6 7 15 16 +DEAL:0:2d::Cell: 9 +DEAL:0:2d:: 7 8 16 17 +DEAL:0:2d:: 7 8 16 17 +DEAL:0:2d::Cell: 10 +DEAL:0:2d:: 15 16 18 19 +DEAL:0:2d:: 15 16 18 19 +DEAL:0:2d::Cell: 11 +DEAL:0:2d:: 16 17 19 20 +DEAL:0:2d:: 16 17 19 20 +DEAL:0:2d::Cell: 12 +DEAL:0:2d:: 8 13 17 21 +DEAL:0:2d:: 8 13 17 21 +DEAL:0:2d::Cell: 13 +DEAL:0:2d:: 13 14 21 22 +DEAL:0:2d:: 13 14 21 22 +DEAL:0:2d::Cell: 14 +DEAL:0:2d:: 17 20 21 23 +DEAL:0:2d:: 17 20 21 23 +DEAL:0:2d::Cell: 15 +DEAL:0:2d:: 21 22 23 24 +DEAL:0:2d:: 21 22 23 24 diff --git a/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec1 b/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec1 new file mode 100644 index 000000000000..96b8f2351b79 --- /dev/null +++ b/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec1 @@ -0,0 +1,64 @@ + +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 7 18 19 +DEAL:0:2d:: 6 16 17 18 19 20 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 7 18 19 21 22 +DEAL:0:2d:: 7 18 19 20 21 22 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 2 7 21 22 23 24 +DEAL:0:2d:: 0 6 7 8 21 22 23 24 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 7 9 10 22 23 24 +DEAL:0:2d:: 7 10 22 23 24 25 26 +DEAL:0:2d::Cell: 4 +DEAL:0:2d:: 2 7 9 10 24 +DEAL:0:2d:: 2 7 8 9 24 25 26 +DEAL:0:2d::Cell: 5 +DEAL:0:2d:: 2 3 9 10 11 12 +DEAL:0:2d:: 0 1 2 3 9 10 11 12 +DEAL:0:2d::Cell: 6 +DEAL:0:2d:: 2 4 9 11 12 14 15 +DEAL:0:2d:: 2 9 11 12 13 14 15 +DEAL:0:2d::Cell: 7 +DEAL:0:2d:: 2 3 4 5 12 15 +DEAL:0:2d:: 2 3 4 5 12 13 15 +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 7 18 19 21 22 +DEAL:0:2d:: 6 7 16 17 18 19 20 21 22 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 2 7 9 10 21 22 23 24 +DEAL:0:2d:: 0 6 7 8 10 21 22 23 24 25 26 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 2 3 7 9 10 11 12 24 +DEAL:0:2d:: 0 1 2 3 7 8 9 10 11 12 24 25 26 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 2 3 4 5 9 11 12 14 15 +DEAL:0:2d:: 2 3 4 5 9 11 12 13 14 15 +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 2 3 5 +DEAL:0:2d:: 0 1 2 3 4 5 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 2 3 5 6 7 8 +DEAL:0:2d:: 2 3 5 6 7 8 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 5 10 12 +DEAL:0:2d:: 4 5 9 10 11 12 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 5 8 10 12 13 14 +DEAL:0:2d:: 5 8 10 12 13 14 +DEAL:0:2d::Cell: 4 +DEAL:0:2d:: 6 7 8 15 16 17 +DEAL:0:2d:: 6 7 8 15 16 17 +DEAL:0:2d::Cell: 5 +DEAL:0:2d:: 15 16 17 18 19 20 +DEAL:0:2d:: 15 16 17 18 19 20 +DEAL:0:2d::Cell: 6 +DEAL:0:2d:: 8 13 14 17 21 22 +DEAL:0:2d:: 8 13 14 17 21 22 +DEAL:0:2d::Cell: 7 +DEAL:0:2d:: 17 20 21 22 23 24 +DEAL:0:2d:: 17 20 21 22 23 24 diff --git a/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec3 b/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec3 new file mode 100644 index 000000000000..2d2edc3e8920 --- /dev/null +++ b/tests/matrix_free/dof_info_01.with_mpi=true.with_p4est=true.mpirun=1.output.vec3 @@ -0,0 +1,19 @@ + +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 2 7 9 10 18 19 21 22 23 24 +DEAL:0:2d:: 0 6 7 8 10 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 2 3 4 5 7 9 10 11 12 14 15 24 +DEAL:0:2d:: 0 1 2 3 4 5 7 8 9 10 11 12 13 14 15 24 25 26 +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 2 3 4 5 7 9 10 11 12 14 15 18 19 21 22 23 24 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0:2d::Testing FE_Q<2>(1) +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 2 3 5 6 7 8 10 12 13 14 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 6 7 8 13 14 15 16 17 18 19 20 21 22 23 24 +DEAL:0:2d:: 6 7 8 13 14 15 16 17 18 19 20 21 22 23 24 diff --git a/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec0 b/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec0 new file mode 100644 index 000000000000..f4dfc08d467d --- /dev/null +++ b/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec0 @@ -0,0 +1,148 @@ + +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 36 37 38 39 +DEAL:0:2d:: 32 33 34 35 36 37 38 39 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 14 15 38 39 +DEAL:0:2d:: 12 13 34 35 38 39 40 41 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 36 37 38 39 42 43 44 45 +DEAL:0:2d:: 36 37 38 39 42 43 44 45 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 14 15 38 39 44 45 +DEAL:0:2d:: 14 15 38 39 40 41 44 45 +DEAL:0:2d::Cell: 4 +DEAL:0:2d:: 4 5 14 15 +DEAL:0:2d:: 0 1 12 13 14 15 16 17 +DEAL:0:2d::Cell: 5 +DEAL:0:2d:: 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 42 43 44 45 46 47 48 49 +DEAL:0:2d::Cell: 6 +DEAL:0:2d:: 14 15 18 19 44 45 48 49 +DEAL:0:2d:: 14 15 44 45 48 49 50 51 +DEAL:0:2d::Cell: 7 +DEAL:0:2d:: 18 19 20 21 46 47 48 49 +DEAL:0:2d:: 20 21 46 47 48 49 52 53 +DEAL:0:2d::Cell: 8 +DEAL:0:2d:: 14 15 18 19 20 21 48 49 +DEAL:0:2d:: 18 19 48 49 50 51 52 53 +DEAL:0:2d::Cell: 9 +DEAL:0:2d:: 4 5 14 15 18 19 +DEAL:0:2d:: 4 5 14 15 16 17 18 19 +DEAL:0:2d::Cell: 10 +DEAL:0:2d:: 4 5 6 7 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 +DEAL:0:2d::Cell: 11 +DEAL:0:2d:: 18 19 20 21 22 23 24 25 +DEAL:0:2d:: 18 19 20 21 22 23 24 25 +DEAL:0:2d::Cell: 12 +DEAL:0:2d:: 4 5 8 9 18 19 24 25 +DEAL:0:2d:: 4 5 18 19 24 25 26 27 +DEAL:0:2d::Cell: 13 +DEAL:0:2d:: 22 23 24 25 28 29 30 31 +DEAL:0:2d:: 22 23 24 25 28 29 30 31 +DEAL:0:2d::Cell: 14 +DEAL:0:2d:: 4 5 8 9 24 25 30 31 +DEAL:0:2d:: 8 9 24 25 26 27 30 31 +DEAL:0:2d::Cell: 15 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 36 37 38 39 +DEAL:0:2d:: 32 33 34 35 36 37 38 39 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 14 15 38 39 +DEAL:0:2d:: 12 13 34 35 38 39 40 41 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 36 37 38 39 42 43 44 45 +DEAL:0:2d:: 36 37 38 39 42 43 44 45 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 14 15 38 39 44 45 +DEAL:0:2d:: 14 15 38 39 40 41 44 45 +DEAL:0:2d::Cell: 4 +DEAL:0:2d:: 4 5 14 15 +DEAL:0:2d:: 0 1 12 13 14 15 16 17 +DEAL:0:2d::Cell: 5 +DEAL:0:2d:: 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 42 43 44 45 46 47 48 49 +DEAL:0:2d::Cell: 6 +DEAL:0:2d:: 14 15 18 19 44 45 48 49 +DEAL:0:2d:: 14 15 44 45 48 49 50 51 +DEAL:0:2d::Cell: 7 +DEAL:0:2d:: 18 19 20 21 46 47 48 49 +DEAL:0:2d:: 20 21 46 47 48 49 52 53 +DEAL:0:2d::Cell: 8 +DEAL:0:2d:: 14 15 18 19 20 21 48 49 +DEAL:0:2d:: 18 19 48 49 50 51 52 53 +DEAL:0:2d::Cell: 9 +DEAL:0:2d:: 4 5 14 15 18 19 +DEAL:0:2d:: 4 5 14 15 16 17 18 19 +DEAL:0:2d::Cell: 10 +DEAL:0:2d:: 4 5 6 7 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 +DEAL:0:2d::Cell: 11 +DEAL:0:2d:: 18 19 20 21 22 23 24 25 +DEAL:0:2d:: 18 19 20 21 22 23 24 25 +DEAL:0:2d::Cell: 12 +DEAL:0:2d:: 4 5 8 9 18 19 24 25 +DEAL:0:2d:: 4 5 18 19 24 25 26 27 +DEAL:0:2d::Cell: 13 +DEAL:0:2d:: 22 23 24 25 28 29 30 31 +DEAL:0:2d:: 22 23 24 25 28 29 30 31 +DEAL:0:2d::Cell: 14 +DEAL:0:2d:: 4 5 8 9 24 25 30 31 +DEAL:0:2d:: 8 9 24 25 26 27 30 31 +DEAL:0:2d::Cell: 15 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 4 5 6 7 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 6 7 10 11 +DEAL:0:2d:: 2 3 6 7 8 9 10 11 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 4 5 6 7 12 13 14 15 +DEAL:0:2d:: 4 5 6 7 12 13 14 15 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 6 7 10 11 14 15 16 17 +DEAL:0:2d:: 6 7 10 11 14 15 16 17 +DEAL:0:2d::Cell: 4 +DEAL:0:2d:: 10 11 20 21 +DEAL:0:2d:: 8 9 10 11 18 19 20 21 +DEAL:0:2d::Cell: 5 +DEAL:0:2d:: 20 21 24 25 +DEAL:0:2d:: 18 19 20 21 22 23 24 25 +DEAL:0:2d::Cell: 6 +DEAL:0:2d:: 10 11 16 17 20 21 26 27 +DEAL:0:2d:: 10 11 16 17 20 21 26 27 +DEAL:0:2d::Cell: 7 +DEAL:0:2d:: 20 21 24 25 26 27 28 29 +DEAL:0:2d:: 20 21 24 25 26 27 28 29 +DEAL:0:2d::Cell: 8 +DEAL:0:2d:: 12 13 14 15 30 31 32 33 +DEAL:0:2d:: 12 13 14 15 30 31 32 33 +DEAL:0:2d::Cell: 9 +DEAL:0:2d:: 14 15 16 17 32 33 34 35 +DEAL:0:2d:: 14 15 16 17 32 33 34 35 +DEAL:0:2d::Cell: 10 +DEAL:0:2d:: 30 31 32 33 36 37 38 39 +DEAL:0:2d:: 30 31 32 33 36 37 38 39 +DEAL:0:2d::Cell: 11 +DEAL:0:2d:: 32 33 34 35 38 39 40 41 +DEAL:0:2d:: 32 33 34 35 38 39 40 41 +DEAL:0:2d::Cell: 12 +DEAL:0:2d:: 16 17 26 27 34 35 42 43 +DEAL:0:2d:: 16 17 26 27 34 35 42 43 +DEAL:0:2d::Cell: 13 +DEAL:0:2d:: 26 27 28 29 42 43 44 45 +DEAL:0:2d:: 26 27 28 29 42 43 44 45 +DEAL:0:2d::Cell: 14 +DEAL:0:2d:: 34 35 40 41 42 43 46 47 +DEAL:0:2d:: 34 35 40 41 42 43 46 47 +DEAL:0:2d::Cell: 15 +DEAL:0:2d:: 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 42 43 44 45 46 47 48 49 diff --git a/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec1 b/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec1 new file mode 100644 index 000000000000..3dc9c8420fbb --- /dev/null +++ b/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec1 @@ -0,0 +1,64 @@ + +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 14 15 36 37 38 39 +DEAL:0:2d:: 12 13 32 33 34 35 36 37 38 39 40 41 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 14 15 36 37 38 39 42 43 44 45 +DEAL:0:2d:: 14 15 36 37 38 39 40 41 42 43 44 45 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 4 5 14 15 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 0 1 12 13 14 15 16 17 42 43 44 45 46 47 48 49 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 14 15 18 19 20 21 44 45 46 47 48 49 +DEAL:0:2d:: 14 15 20 21 44 45 46 47 48 49 50 51 52 53 +DEAL:0:2d::Cell: 4 +DEAL:0:2d:: 4 5 14 15 18 19 20 21 48 49 +DEAL:0:2d:: 4 5 14 15 16 17 18 19 48 49 50 51 52 53 +DEAL:0:2d::Cell: 5 +DEAL:0:2d:: 4 5 6 7 18 19 20 21 22 23 24 25 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 18 19 20 21 22 23 24 25 +DEAL:0:2d::Cell: 6 +DEAL:0:2d:: 4 5 8 9 18 19 22 23 24 25 28 29 30 31 +DEAL:0:2d:: 4 5 18 19 22 23 24 25 26 27 28 29 30 31 +DEAL:0:2d::Cell: 7 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 24 25 30 31 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 24 25 26 27 30 31 +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 14 15 36 37 38 39 42 43 44 45 +DEAL:0:2d:: 12 13 14 15 32 33 34 35 36 37 38 39 40 41 42 43 44 45 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 4 5 14 15 18 19 20 21 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 0 1 12 13 14 15 16 17 20 21 42 43 44 45 46 47 48 49 50 51 52 53 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 4 5 6 7 14 15 18 19 20 21 22 23 24 25 48 49 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 14 15 16 17 18 19 20 21 22 23 24 25 48 49 50 51 52 53 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 18 19 22 23 24 25 28 29 30 31 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 18 19 22 23 24 25 26 27 28 29 30 31 +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 4 5 6 7 10 11 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 8 9 10 11 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 4 5 6 7 10 11 12 13 14 15 16 17 +DEAL:0:2d:: 4 5 6 7 10 11 12 13 14 15 16 17 +DEAL:0:2d::Cell: 2 +DEAL:0:2d:: 10 11 20 21 24 25 +DEAL:0:2d:: 8 9 10 11 18 19 20 21 22 23 24 25 +DEAL:0:2d::Cell: 3 +DEAL:0:2d:: 10 11 16 17 20 21 24 25 26 27 28 29 +DEAL:0:2d:: 10 11 16 17 20 21 24 25 26 27 28 29 +DEAL:0:2d::Cell: 4 +DEAL:0:2d:: 12 13 14 15 16 17 30 31 32 33 34 35 +DEAL:0:2d:: 12 13 14 15 16 17 30 31 32 33 34 35 +DEAL:0:2d::Cell: 5 +DEAL:0:2d:: 30 31 32 33 34 35 36 37 38 39 40 41 +DEAL:0:2d:: 30 31 32 33 34 35 36 37 38 39 40 41 +DEAL:0:2d::Cell: 6 +DEAL:0:2d:: 16 17 26 27 28 29 34 35 42 43 44 45 +DEAL:0:2d:: 16 17 26 27 28 29 34 35 42 43 44 45 +DEAL:0:2d::Cell: 7 +DEAL:0:2d:: 34 35 40 41 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 34 35 40 41 42 43 44 45 46 47 48 49 diff --git a/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec3 b/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec3 new file mode 100644 index 000000000000..f8507beb6ea3 --- /dev/null +++ b/tests/matrix_free/dof_info_02.with_mpi=true.with_p4est=true.mpirun=1.output.vec3 @@ -0,0 +1,19 @@ + +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 4 5 14 15 18 19 20 21 36 37 38 39 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 0 1 12 13 14 15 16 17 20 21 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 14 15 18 19 20 21 22 23 24 25 28 29 30 31 48 49 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 8 9 10 11 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 48 49 50 51 52 53 +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 4 5 6 7 8 9 10 11 14 15 18 19 20 21 22 23 24 25 28 29 30 31 36 37 38 39 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 +DEAL:0:2d::Testing FESystem<2>[FE_Q<2>(1)^2] +DEAL:0:2d::Cell: 0 +DEAL:0:2d:: 4 5 6 7 10 11 12 13 14 15 16 17 20 21 24 25 26 27 28 29 +DEAL:0:2d:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 +DEAL:0:2d::Cell: 1 +DEAL:0:2d:: 12 13 14 15 16 17 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 +DEAL:0:2d:: 12 13 14 15 16 17 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 From f7f359106346926819a4102f25b2223ef8b21ba2 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Mon, 4 Feb 2019 10:55:39 -0600 Subject: [PATCH 060/507] example/step-4: Return the correct return value This commit reverts a stray change that should have probably never made it into 0e12f6f87a0b84fadd8df629f55da42a8494ce8f --- examples/step-4/step-4.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/step-4/step-4.cc b/examples/step-4/step-4.cc index a63c86d40e5a..a4b0aa53907b 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; } From bb5fb7de671a7700ecef591d597acb696c5b31d4 Mon Sep 17 00:00:00 2001 From: Rene Gassmoeller Date: Mon, 4 Feb 2019 13:12:12 -0800 Subject: [PATCH 061/507] Fix serialization of XDMFEntry class --- include/deal.II/base/data_out_base.h | 5 +- tests/serialization/xdmf_entry.cc | 74 +++++++++++++++++++++++++++ tests/serialization/xdmf_entry.output | 36 +++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 tests/serialization/xdmf_entry.cc create mode 100644 tests/serialization/xdmf_entry.output 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/tests/serialization/xdmf_entry.cc b/tests/serialization/xdmf_entry.cc new file mode 100644 index 000000000000..2a3c3b5948e6 --- /dev/null +++ b/tests/serialization/xdmf_entry.cc @@ -0,0 +1,74 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// check serialization for XDMFEntry + +#include + +#include "serialization.h" + +void +test() +{ + const std::string mesh_filename = "mesh.h5"; + const std::string solution_filename = "solution.h5"; + + const double time = 0.5; + const unsigned int nodes = 128; + const unsigned int cells = 16; + const unsigned int dim = 2; + const unsigned int spacedim = 3; + + XDMFEntry entry1( + mesh_filename, solution_filename, time, nodes, cells, dim, spacedim); + XDMFEntry entry2; + + // save data to archive + std::ostringstream oss; + { + boost::archive::text_oarchive oa(oss, boost::archive::no_header); + oa << entry1; + // archive and stream closed when destructors are called + } + deallog << oss.str() << std::endl; + + // verify correctness of the serialization + { + std::istringstream iss(oss.str()); + boost::archive::text_iarchive ia(iss, boost::archive::no_header); + ia >> entry2; + } + + deallog << "XDMFEntry before serialization: " << std::endl + << std::endl + << entry1.get_xdmf_content(0) << std::endl; + + deallog << "XDMFEntry after de-serialization: " << std::endl + << std::endl + << entry2.get_xdmf_content(0) << std::endl; +} + + +int +main() +{ + initlog(); + deallog << std::setprecision(3); + + test(); + + deallog << "OK" << std::endl; +} diff --git a/tests/serialization/xdmf_entry.output b/tests/serialization/xdmf_entry.output new file mode 100644 index 000000000000..fdeaefeca94a --- /dev/null +++ b/tests/serialization/xdmf_entry.output @@ -0,0 +1,36 @@ + +DEAL::0 0 1 11 solution.h5 7 mesh.h5 5.00000000000000000e-01 128 16 2 3 0 0 0 0 + +DEAL::XDMFEntry before serialization: +DEAL:: +DEAL:: + + +DEAL::XDMFEntry after de-serialization: +DEAL:: +DEAL:: + + +DEAL::OK From 461fb7721cfdd7a2989bbacd71a7076d727e5eeb Mon Sep 17 00:00:00 2001 From: David Wells Date: Sun, 3 Feb 2019 22:35:36 -0500 Subject: [PATCH 062/507] Cleanup the Vector::thread_loop_partitioner logic. It was previously possible to, in one function call, either set up the partitioner multiple times or for inappropriately small vectors. This commit cleans up the way we handle the partitioner in multiple places so that, when possible, vectors share partitioners and do not set up partitioners if they are too small. --- include/deal.II/lac/vector.h | 20 +++- include/deal.II/lac/vector.templates.h | 123 +++++++++++++------------ 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/include/deal.II/lac/vector.h b/include/deal.II/lac/vector.h index 2dadf1da5e10..b413f686b129 100644 --- a/include/deal.II/lac/vector.h +++ b/include/deal.II/lac/vector.h @@ -986,6 +986,22 @@ class Vector : public Subscriptor */ AlignedVector values; + /** + * Convenience function used at the end of initialization or + * reinitialization. Resets (if necessary) the loop partitioner to the + * correct state, based on its current state and the length of the vector. + */ + void + maybe_reset_thread_partitioner(); + + /** + * Actual implementation of the reinit functions. + */ + void + do_reinit(const size_type new_size, + const bool omit_zeroing_entries, + const bool reset_partitioner); + /** * For parallel loops with TBB, this member variable stores the affinity * information of loops. @@ -1275,7 +1291,8 @@ template inline void Vector::swap(Vector &v) { - std::swap(values, v.values); + values.swap(v.values); + std::swap(thread_loop_partitioner, v.thread_loop_partitioner); } @@ -1300,6 +1317,7 @@ Vector::load(Archive &ar, const unsigned int) // the load stuff again from the archive ar &static_cast(*this); ar &values; + maybe_reset_thread_partitioner(); } #endif diff --git a/include/deal.II/lac/vector.templates.h b/include/deal.II/lac/vector.templates.h index 87c126c8b8b4..bc98f73050e5 100644 --- a/include/deal.II/lac/vector.templates.h +++ b/include/deal.II/lac/vector.templates.h @@ -83,6 +83,11 @@ namespace internal copy_petsc_vector(const PETScWrappers::VectorBase &v, ::dealii::Vector & out) { + if (v.size() == 0) + { + out.reinit(0); + return; + } // Create a sequential PETSc vector and then copy over the entries into // the deal.II vector. Vec sequential_vector; @@ -125,10 +130,7 @@ namespace internal template Vector::Vector(const PETScWrappers::VectorBase &v) { - if (v.size() != 0) - { - internal::copy_petsc_vector(v, *this); - } + internal::copy_petsc_vector(v, *this); } #endif @@ -164,6 +166,8 @@ Vector::Vector(const TrilinosWrappers::MPI::Vector &v) AssertThrow(ierr == 0, ExcTrilinosError(ierr)); std::copy(start_ptr[0], start_ptr[0] + size(), begin()); + + maybe_reset_thread_partitioner(); } } @@ -177,7 +181,6 @@ Vector::operator=(const Vector &v) if (PointerComparison::equal(this, &v)) return *this; - thread_loop_partitioner = v.thread_loop_partitioner; if (size() != v.size()) reinit(v, true); @@ -201,7 +204,6 @@ template inline Vector & Vector::operator=(const Vector &v) { - thread_loop_partitioner = v.thread_loop_partitioner; if (size() != v.size()) reinit(v, true); @@ -221,41 +223,7 @@ template inline void Vector::reinit(const size_type n, const bool omit_zeroing_entries) { - const std::size_t old_size = size(); - - // avoid allocating if the new size is not larger than the old size - if (n <= size()) - { - thread_loop_partitioner = - std::make_shared(); - if (n == 0) - { - values.clear(); - } - else if (n != size()) - values.resize_fast(n); - - if (!omit_zeroing_entries) - values.fill(); - return; - } - - // otherwise size() < n and we must allocate - AlignedVector new_values; - new_values.resize_fast(n); - if (!omit_zeroing_entries) - new_values.fill(); - new_values.swap(values); - - if (old_size != size()) - { - // only reset the partitioner if we actually expect a significant vector - // size - if (size() >= - 4 * internal::VectorImplementation::minimum_parallel_grain_size) - thread_loop_partitioner = - std::make_shared(); - } + do_reinit(n, omit_zeroing_entries, true); } @@ -264,26 +232,9 @@ template inline void Vector::grow_or_shrink(const size_type n) { - const std::size_t old_size = size(); - if (n == 0) - { - values.clear(); - thread_loop_partitioner = - std::make_shared(); - return; - } - values.resize(n); - if (old_size != n) - { - // only reset the partitioner if we actually expect a significant vector - // size - if (size() >= - 4 * internal::VectorImplementation::minimum_parallel_grain_size) - thread_loop_partitioner = - std::make_shared(); - } + maybe_reset_thread_partitioner(); } @@ -294,9 +245,8 @@ void Vector::reinit(const Vector &v, const bool omit_zeroing_entries) { + do_reinit(v.size(), omit_zeroing_entries, false); thread_loop_partitioner = v.thread_loop_partitioner; - - reinit(v.size(), omit_zeroing_entries); } @@ -1046,6 +996,57 @@ Vector::memory_consumption() const } + +template +void +Vector::maybe_reset_thread_partitioner() +{ + if (size() >= 4 * internal::VectorImplementation::minimum_parallel_grain_size) + { + if (thread_loop_partitioner == nullptr) + thread_loop_partitioner = + std::make_shared(); + } + else + thread_loop_partitioner.reset(); +} + + + +template +void +Vector::do_reinit(const size_type new_size, + const bool omit_zeroing_entries, + const bool reset_partitioner) +{ + if (new_size <= size()) + { + if (new_size == 0) + { + values.clear(); + } + else + { + values.resize_fast(new_size); + if (!omit_zeroing_entries) + values.fill(); + } + } + else + { + // otherwise size() < new_size and we must allocate + AlignedVector new_values; + new_values.resize_fast(new_size); + if (!omit_zeroing_entries) + new_values.fill(); + new_values.swap(values); + } + + if (reset_partitioner) + maybe_reset_thread_partitioner(); +} + + DEAL_II_NAMESPACE_CLOSE #endif From a0ad3a186d4507726fd2b36650999b623d4cd97c Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Mon, 4 Feb 2019 07:51:52 -0700 Subject: [PATCH 063/507] Update documentation of some VectorTools functions. --- include/deal.II/numerics/vector_tools.h | 147 +++++++++++++++++++++--- 1 file changed, 134 insertions(+), 13 deletions(-) diff --git a/include/deal.II/numerics/vector_tools.h b/include/deal.II/numerics/vector_tools.h index 20b2d9b74d6b..ec060968c17b 100644 --- a/include/deal.II/numerics/vector_tools.h +++ b/include/deal.II/numerics/vector_tools.h @@ -2163,17 +2163,50 @@ namespace VectorTools * vector is deleted. This function is for the case of a scalar finite * element. * - * It is worth noting that delta functions do not exist in reality, and - * consequently, using this function does not model any real situation. This - * is, because no real object is able to focus an infinite force density - * at an infinitesimally small part of the domain. Rather, all real - * devices will spread out the force over a finite area. Only if this - * area is so small that it cannot be resolved by any mesh does it make - * sense to model the situation in a way that uses a delta function with - * the same overall force. On the other hand, a situation that is probably - * more fruitfully simulated with a delta function is the electric potential - * of a point source; in this case, the solution is known to have a - * logarithmic singularity (in 2d) or a $\frac{1}{r}$ singularity (in 3d), + * This function is typically used in one of these two contexts: + * - Let's say you want to solve the same kind of problems many times + * over, with different values for right hand sides or coefficients, + * and then evaluate the solution at the same point every time. You + * could do this by calling VectorTools::point_value() after each + * solve, or you could realize that to evaluate the solution $u_h$ + * at a point $p$, you could rearrange operations like this: + * @f{align*}{ + * u_h(p) &= \sum_j U_j \varphi_j(p) = \sum_j U_j F_j + * \\ &= U \cdot F + * @f} + * with the vector as defined above. In other words, point evaluation + * can be achieved with just a single vector-vector product, and the + * vector $F$ can be computed once and for all and reused + * for each solve, without having to go through the mesh every time + * to find out which cell (and where in the cell) the point $p$ is + * located. + * - This function is also useful if you wanted to compute the Green's + * function for the problem you are solving. This is because the + * Green's function $G(x,p)$ is defined by + * @f{align*}{ + * L G(x,p) &= \delta(x-p)$ + * @f} + * where $L$ is the differential operator of your problem. The discrete + * version then requires computing the right hand side vector + * $F_i = \int_\Omega \varphi_i(x) \delta(x-p)$, which is exactly + * the vector computed by the current function. + * + * While maybe not relevant for documenting what this + * function does, it may be interesting to note that delta functions + * do not exist in reality, and consequently, using this function + * does not model any real situation. This is, because no real + * object is able to focus an infinite force density at an + * infinitesimally small part of the domain (rather, all real + * devices will spread out the force over a finite area); nor is it + * possible to measure values at individual points (but all + * measurements will somehow be averaged over small areas). Only if + * this area is so small that it cannot be resolved by any mesh does + * it make sense to model the situation in a way that uses a delta + * function with the same overall force or sensitivity. On the other + * hand, a situation that is probably more fruitfully simulated with + * a delta function is the electric potential of a point source; in + * this case, the solution is known to have a logarithmic + * singularity (in 2d) or a $\frac{1}{r}$ singularity (in 3d), * neither of which is bounded. * * Mathematically, the use of delta functions typically leads to exact @@ -2610,13 +2643,24 @@ namespace VectorTools * point, and return the (vector) value of this function through the last * argument. * - * This function uses a Q1-mapping for the cell the point is evaluated + * This function uses a $Q_1$-mapping for the cell the point is evaluated * in. If you need to evaluate using a different mapping (for example when * using curved boundaries), use the point_difference() function that takes * a mapping. * + * This function is not particularly cheap. This is because it first + * needs to find which cell a given point is in, then find the point + * on the reference cell that matches the given evaluation point, + * and then evaluate the shape functions there. You probably do not + * want to use this function to evaluate the solution at many + * points. For this kind of application, the FEFieldFunction class + * offers at least some optimizations. On the other hand, if you + * want to evaluate many solutions at the same point, you may + * want to look at the VectorTools::create_point_source_vector() + * function. + * * @note If the cell in which the point is found is not locally owned, an - * exception of type VectorTools::ExcPointNotAvailableHere is thrown. + * exception of type VectorTools::ExcPointNotAvailableHere is thrown. * * @note This function needs to find the cell within which a point lies, * and this can only be done up to a certain numerical tolerance of course. @@ -2670,6 +2714,17 @@ namespace VectorTools * using curved boundaries), use the point_difference() function that takes * a mapping. * + * This function is not particularly cheap. This is because it first + * needs to find which cell a given point is in, then find the point + * on the reference cell that matches the given evaluation point, + * and then evaluate the shape functions there. You probably do not + * want to use this function to evaluate the solution at many + * points. For this kind of application, the FEFieldFunction class + * offers at least some optimizations. On the other hand, if you + * want to evaluate many solutions at the same point, you may + * want to look at the VectorTools::create_point_source_vector() + * function. + * * This function is used in the "Possibilities for extensions" part of the * results section of * @ref step_3 "step-3". @@ -2726,6 +2781,17 @@ namespace VectorTools * Compared with the other function of the same name, this function uses an * arbitrary mapping to evaluate the point value. * + * This function is not particularly cheap. This is because it first + * needs to find which cell a given point is in, then find the point + * on the reference cell that matches the given evaluation point, + * and then evaluate the shape functions there. You probably do not + * want to use this function to evaluate the solution at many + * points. For this kind of application, the FEFieldFunction class + * offers at least some optimizations. On the other hand, if you + * want to evaluate many solutions at the same point, you may + * want to look at the VectorTools::create_point_source_vector() + * function. + * * @note If the cell in which the point is found is not locally owned, an * exception of type VectorTools::ExcPointNotAvailableHere is thrown. * @@ -2781,6 +2847,17 @@ namespace VectorTools * Compared with the other function of the same name, this function uses an * arbitrary mapping to evaluate the difference. * + * This function is not particularly cheap. This is because it first + * needs to find which cell a given point is in, then find the point + * on the reference cell that matches the given evaluation point, + * and then evaluate the shape functions there. You probably do not + * want to use this function to evaluate the solution at many + * points. For this kind of application, the FEFieldFunction class + * offers at least some optimizations. On the other hand, if you + * want to evaluate many solutions at the same point, you may + * want to look at the VectorTools::create_point_source_vector() + * function. + * * @note If the cell in which the point is found is not locally owned, an * exception of type VectorTools::ExcPointNotAvailableHere is thrown. * @@ -2834,6 +2911,17 @@ namespace VectorTools * This is a wrapper function using a Q1-mapping for cell boundaries to call * the other point_gradient() function. * + * This function is not particularly cheap. This is because it first + * needs to find which cell a given point is in, then find the point + * on the reference cell that matches the given evaluation point, + * and then evaluate the shape functions there. You probably do not + * want to use this function to evaluate the solution at many + * points. For this kind of application, the FEFieldFunction class + * offers at least some optimizations. On the other hand, if you + * want to evaluate many solutions at the same point, you may + * want to look at the VectorTools::create_point_source_vector() + * function. + * * @note If the cell in which the point is found is not locally owned, an * exception of type VectorTools::ExcPointNotAvailableHere is thrown. * @@ -2887,6 +2975,17 @@ namespace VectorTools * Compared with the other function of the same name, this is a wrapper * function using a Q1-mapping for cells. * + * This function is not particularly cheap. This is because it first + * needs to find which cell a given point is in, then find the point + * on the reference cell that matches the given evaluation point, + * and then evaluate the shape functions there. You probably do not + * want to use this function to evaluate the solution at many + * points. For this kind of application, the FEFieldFunction class + * offers at least some optimizations. On the other hand, if you + * want to evaluate many solutions at the same point, you may + * want to look at the VectorTools::create_point_source_vector() + * function. + * * @note If the cell in which the point is found is not locally owned, an * exception of type VectorTools::ExcPointNotAvailableHere is thrown. * @@ -2936,6 +3035,17 @@ namespace VectorTools * Compared with the other function of the same name, this function uses an * arbitrary mapping for evaluation. * + * This function is not particularly cheap. This is because it first + * needs to find which cell a given point is in, then find the point + * on the reference cell that matches the given evaluation point, + * and then evaluate the shape functions there. You probably do not + * want to use this function to evaluate the solution at many + * points. For this kind of application, the FEFieldFunction class + * offers at least some optimizations. On the other hand, if you + * want to evaluate many solutions at the same point, you may + * want to look at the VectorTools::create_point_source_vector() + * function. + * * @note If the cell in which the point is found is not locally owned, an * exception of type VectorTools::ExcPointNotAvailableHere is thrown. * @@ -2991,6 +3101,17 @@ namespace VectorTools * Compared with the other function of the same name, this function uses an * arbitrary mapping for evaluation. * + * This function is not particularly cheap. This is because it first + * needs to find which cell a given point is in, then find the point + * on the reference cell that matches the given evaluation point, + * and then evaluate the shape functions there. You probably do not + * want to use this function to evaluate the solution at many + * points. For this kind of application, the FEFieldFunction class + * offers at least some optimizations. On the other hand, if you + * want to evaluate many solutions at the same point, you may + * want to look at the VectorTools::create_point_source_vector() + * function. + * * @note If the cell in which the point is found is not locally owned, an * exception of type VectorTools::ExcPointNotAvailableHere is thrown. * From f809d49183e94d267d5ec0a71ffd6c4ff328adfb Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Tue, 5 Feb 2019 16:02:13 -0700 Subject: [PATCH 064/507] [CI]: add Jenkins.mark Add a separate Jenkins pipeline that runs in a few seconds to set the commit status to pending. This is needed as Jenkins only starts setting a commit status when the normal jobs start running and not when they are in the queue. This can lead to a) accidental merges before we test things and b) repeated /rebuild triggers. --- Jenkinsfile | 3 +++ contrib/ci/Jenkinsfile.mark | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 contrib/ci/Jenkinsfile.mark diff --git a/Jenkinsfile b/Jenkinsfile index 09370d793b2a..9e3e48848fc8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -42,6 +42,9 @@ pipeline { 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 ''' diff --git a/contrib/ci/Jenkinsfile.mark b/contrib/ci/Jenkinsfile.mark new file mode 100644 index 000000000000..c10638a5133d --- /dev/null +++ b/contrib/ci/Jenkinsfile.mark @@ -0,0 +1,51 @@ +#!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 none + + 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' + } + } + } + } + + } +} From a1e4ce9bbe4a92b71b09add8df2efd75626c44ed Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Tue, 5 Feb 2019 16:08:43 -0700 Subject: [PATCH 065/507] set agent --- contrib/ci/Jenkinsfile.mark | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/contrib/ci/Jenkinsfile.mark b/contrib/ci/Jenkinsfile.mark index c10638a5133d..37aa15478cd7 100644 --- a/contrib/ci/Jenkinsfile.mark +++ b/contrib/ci/Jenkinsfile.mark @@ -20,7 +20,13 @@ Settings to apply inside Jenkins: pipeline { - agent none + agent + { + docker + { + image 'dealii/indent' + } + } stages { From 881e97e1a440ca834a4c0d7cfa86dba4c4a65a42 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Tue, 5 Feb 2019 19:06:12 +0100 Subject: [PATCH 066/507] Fix initialization of LA::d::Vector in multigrid. --- .../deal.II/multigrid/mg_transfer.templates.h | 59 ++- .../parallel_multigrid_adaptive_08.cc | 423 ++++++++++++++++++ ...4est=true.with_lapack=true.mpirun=3.output | 47 ++ 3 files changed, 498 insertions(+), 31 deletions(-) create mode 100644 tests/matrix_free/parallel_multigrid_adaptive_08.cc create mode 100644 tests/matrix_free/parallel_multigrid_adaptive_08.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=3.output diff --git a/include/deal.II/multigrid/mg_transfer.templates.h b/include/deal.II/multigrid/mg_transfer.templates.h index 439f2dda3085..c207fe593ed2 100644 --- a/include/deal.II/multigrid/mg_transfer.templates.h +++ b/include/deal.II/multigrid/mg_transfer.templates.h @@ -104,34 +104,6 @@ namespace internal } } - /** - * Adjust vectors on all levels to correct size. Here, we just count the - * numbers of degrees of freedom on each level and @p reinit each level - * vector to this length. - */ - template - void - reinit_vector(const dealii::DoFHandler &mg_dof, - const std::vector &, - MGLevelObject> &v) - { - const parallel::Triangulation *tria = - (dynamic_cast *>( - &mg_dof.get_triangulation())); - - for (unsigned int level = v.min_level(); level <= v.max_level(); ++level) - { - if (v[level].size() != mg_dof.locally_owned_mg_dofs(level).size() || - v[level].local_size() != - mg_dof.locally_owned_mg_dofs(level).n_elements()) - v[level].reinit(mg_dof.locally_owned_mg_dofs(level), - tria != nullptr ? tria->get_communicator() : - MPI_COMM_SELF); - else - v[level] = 0.; - } - } - #ifdef DEAL_II_WITH_TRILINOS /** @@ -453,12 +425,37 @@ MGLevelGlobalTransfer>::copy_to_mg( solution_transfer ? solution_copy_indices_level_mine : copy_indices_level_mine; + (void)mg_dof_handler; + AssertIndexRange(dst.max_level(), mg_dof_handler.get_triangulation().n_global_levels()); AssertIndexRange(dst.min_level(), dst.max_level() + 1); - internal::MGTransfer::reinit_vector(mg_dof_handler, - component_to_block_map, - dst); + + for (unsigned int level = dst.min_level(); level <= dst.max_level(); ++level) + if (dst[level].size() != mg_dof_handler.n_dofs(level) || + dst[level].local_size() != + mg_dof_handler.locally_owned_mg_dofs(level).n_elements()) + { + // In case a ghosted level vector has been initialized, we can simply + // use that as a template for the vector partitioning. If not, we + // resort to the locally owned range of the dof handler. + if (level <= ghosted_level_vector.max_level() && + ghosted_level_vector[level].size() == mg_dof_handler.n_dofs(level)) + dst[level].reinit(ghosted_level_vector[level], false); + else + { + const parallel::Triangulation *tria = + (dynamic_cast *>( + &mg_dof_handler.get_triangulation())); + dst[level].reinit(mg_dof_handler.locally_owned_mg_dofs(level), + tria != nullptr ? tria->get_communicator() : + MPI_COMM_SELF); + } + } + else if ((perform_plain_copy == false && + perform_renumbered_plain_copy == false) || + level != dst.max_level()) + dst[level] = 0; if (perform_plain_copy) { diff --git a/tests/matrix_free/parallel_multigrid_adaptive_08.cc b/tests/matrix_free/parallel_multigrid_adaptive_08.cc new file mode 100644 index 000000000000..4fb6c2b0c433 --- /dev/null +++ b/tests/matrix_free/parallel_multigrid_adaptive_08.cc @@ -0,0 +1,423 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 - 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. +// +// --------------------------------------------------------------------- + + + +// similar to parallel_multigrid_adaptive_02 but without using a separate +// transfer class that builds the appropriate vectors. Furthermore, we want to +// avoid setting some vectors to zero in the cell loop. Rather, +// MatrixFreeOperators::LaplaceOperator::adjust_ghost_range_if_necessary() +// will do that - or rather a variant of that, given that we want to modify +// the cell loop of the LaplaceOperator class and provide our own. This forces +// us to reimplement a few things, but all ideas are the same as in the +// matrix-free operators. + +#include + +#include + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "../tests.h" + +std::ofstream logfile("output"); + +using namespace dealii::MatrixFreeOperators; + + +template +class MyLaplaceOperator : public MatrixFreeOperators::LaplaceOperator< + dim, + fe_degree, + fe_degree + 1, + 1, + LinearAlgebra::distributed::Vector> +{ +public: + void + initialize(std::shared_ptr> data, + const MGConstrainedDoFs & mg_constrained_dofs, + const unsigned int level) + { + MatrixFreeOperators::Base>:: + initialize(data, + mg_constrained_dofs, + level, + std::vector({0})); + + std::vector interface_indices; + mg_constrained_dofs.get_refinement_edge_indices(level).fill_index_vector( + interface_indices); + vmult_edge_constrained_indices.clear(); + vmult_edge_constrained_indices.reserve(interface_indices.size()); + vmult_edge_constrained_values.resize(interface_indices.size()); + const IndexSet &locally_owned = + this->data->get_dof_handler(0).locally_owned_mg_dofs(level); + for (unsigned int i = 0; i < interface_indices.size(); ++i) + if (locally_owned.is_element(interface_indices[i])) + vmult_edge_constrained_indices.push_back( + locally_owned.index_within_set(interface_indices[i])); + } + + void + initialize(std::shared_ptr> data, + const std::vector & mask = {}) + { + MatrixFreeOperators::Base>:: + initialize(data, mask); + } + + + void + vmult(LinearAlgebra::distributed::Vector & dst, + const LinearAlgebra::distributed::Vector &src) const + { + adjust_ghost_range_if_necessary(src); + adjust_ghost_range_if_necessary(dst); + + for (unsigned int i = 0; i < vmult_edge_constrained_indices.size(); ++i) + { + vmult_edge_constrained_values[i] = + src.local_element(vmult_edge_constrained_indices[i]); + const_cast &>(src) + .local_element(vmult_edge_constrained_indices[i]) = 0.; + } + + // zero dst within the loop + this->data->cell_loop( + &MyLaplaceOperator::local_apply, this, dst, src, true); + + for (auto i : this->data->get_constrained_dofs(0)) + dst.local_element(i) = src.local_element(i); + for (unsigned int i = 0; i < vmult_edge_constrained_indices.size(); ++i) + { + dst.local_element(vmult_edge_constrained_indices[i]) = + vmult_edge_constrained_values[i]; + const_cast &>(src) + .local_element(vmult_edge_constrained_indices[i]) = + vmult_edge_constrained_values[i]; + } + } + +private: + void + local_apply(const MatrixFree & data, + LinearAlgebra::distributed::Vector & dst, + const LinearAlgebra::distributed::Vector &src, + const std::pair &cell_range) const + { + FEEvaluation phi(data); + + for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) + { + phi.reinit(cell); + phi.gather_evaluate(src, false, true); + for (unsigned int q = 0; q < phi.n_q_points; ++q) + phi.submit_gradient(phi.get_gradient(q), q); + phi.integrate_scatter(false, true, dst); + } + } + + void + adjust_ghost_range_if_necessary( + const LinearAlgebra::distributed::Vector &vec) const + { + if (vec.get_partitioner().get() == + this->data->get_dof_info(0).vector_partitioner.get()) + return; + + Assert(vec.get_partitioner()->local_size() == + this->data->get_dof_info(0).vector_partitioner->local_size(), + ExcMessage("The vector passed to the vmult() function does not have " + "the correct size for compatibility with MatrixFree.")); + LinearAlgebra::distributed::Vector copy_vec(vec); + const_cast &>(vec).reinit( + this->data->get_dof_info(0).vector_partitioner); + const_cast &>(vec) + .copy_locally_owned_data_from(copy_vec); + } + + std::vector vmult_edge_constrained_indices; + + mutable std::vector vmult_edge_constrained_values; +}; + + + +template +class MGCoarseIterative + : public MGCoarseGridBase> +{ +public: + MGCoarseIterative() + {} + + void + initialize(const MatrixType &matrix) + { + coarse_matrix = &matrix; + } + + virtual void + operator()(const unsigned int level, + LinearAlgebra::distributed::Vector & dst, + const LinearAlgebra::distributed::Vector &src) const + { + ReductionControl solver_control(1e4, 1e-50, 1e-10); + SolverCG> solver_coarse( + solver_control); + solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity()); + } + + const MatrixType *coarse_matrix; +}; + + + +template +void +do_test(const DoFHandler &dof) +{ + deallog << "Testing " << dof.get_fe().get_name(); + deallog << std::endl; + deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl; + + IndexSet locally_relevant_dofs; + DoFTools::extract_locally_relevant_dofs(dof, locally_relevant_dofs); + + // Dirichlet BC + Functions::ZeroFunction zero_function; + std::map *> dirichlet_boundary; + dirichlet_boundary[0] = &zero_function; + + // fine-level constraints + AffineConstraints constraints; + constraints.reinit(locally_relevant_dofs); + DoFTools::make_hanging_node_constraints(dof, constraints); + VectorTools::interpolate_boundary_values(dof, + dirichlet_boundary, + constraints); + constraints.close(); + + // level constraints: + MGConstrainedDoFs mg_constrained_dofs; + mg_constrained_dofs.initialize(dof, dirichlet_boundary); + + MappingQ mapping(fe_degree + 1); + + MyLaplaceOperator fine_matrix; + std::shared_ptr> fine_level_data( + new MatrixFree()); + + typename MatrixFree::AdditionalData fine_level_additional_data; + fine_level_additional_data.tasks_parallel_scheme = + MatrixFree::AdditionalData::none; + fine_level_additional_data.tasks_block_size = 3; + fine_level_data->reinit(mapping, + dof, + constraints, + QGauss<1>(n_q_points_1d), + fine_level_additional_data); + + fine_matrix.initialize(fine_level_data); + fine_matrix.compute_diagonal(); + + + LinearAlgebra::distributed::Vector in, sol; + fine_matrix.initialize_dof_vector(in); + fine_matrix.initialize_dof_vector(sol); + + // set constant rhs vector + { + // this is to make it consistent with parallel_multigrid_adaptive.cc + AffineConstraints hanging_node_constraints; + hanging_node_constraints.reinit(locally_relevant_dofs); + DoFTools::make_hanging_node_constraints(dof, hanging_node_constraints); + hanging_node_constraints.close(); + + for (unsigned int i = 0; i < in.local_size(); ++i) + if (!hanging_node_constraints.is_constrained( + in.get_partitioner()->local_to_global(i))) + in.local_element(i) = 1.; + } + + // set up multigrid in analogy to step-37 + using LevelMatrixType = MyLaplaceOperator; + + MGLevelObject mg_matrices; + MGLevelObject> mg_level_data; + mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1); + mg_level_data.resize(0, dof.get_triangulation().n_global_levels() - 1); + for (unsigned int level = 0; + level < dof.get_triangulation().n_global_levels(); + ++level) + { + typename MatrixFree::AdditionalData mg_additional_data; + mg_additional_data.tasks_parallel_scheme = + MatrixFree::AdditionalData::none; + mg_additional_data.tasks_block_size = 3; + mg_additional_data.level_mg_handler = level; + + AffineConstraints level_constraints; + IndexSet relevant_dofs; + DoFTools::extract_locally_relevant_level_dofs(dof, level, relevant_dofs); + level_constraints.reinit(relevant_dofs); + level_constraints.add_lines( + mg_constrained_dofs.get_boundary_indices(level)); + level_constraints.close(); + + mg_level_data[level].reinit(mapping, + dof, + level_constraints, + QGauss<1>(n_q_points_1d), + mg_additional_data); + mg_matrices[level].initialize(std::make_shared>( + mg_level_data[level]), + mg_constrained_dofs, + level); + mg_matrices[level].compute_diagonal(); + } + MGLevelObject> mg_interface_matrices; + mg_interface_matrices.resize(0, + dof.get_triangulation().n_global_levels() - 1); + for (unsigned int level = 0; + level < dof.get_triangulation().n_global_levels(); + ++level) + mg_interface_matrices[level].initialize(mg_matrices[level]); + + MGTransferMatrixFree mg_transfer(mg_constrained_dofs); + mg_transfer.build(dof); + + MGCoarseIterative mg_coarse; + mg_coarse.initialize(mg_matrices[0]); + + typedef PreconditionChebyshev> + SMOOTHER; + MGSmootherPrecondition> + mg_smoother; + + MGLevelObject smoother_data; + smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1); + for (unsigned int level = 0; + level < dof.get_triangulation().n_global_levels(); + ++level) + { + smoother_data[level].smoothing_range = 15.; + smoother_data[level].degree = 5; + smoother_data[level].eig_cg_n_iterations = 15; + smoother_data[level].preconditioner = + mg_matrices[level].get_matrix_diagonal_inverse(); + } + mg_smoother.initialize(mg_matrices, smoother_data); + + mg::Matrix> mg_matrix(mg_matrices); + mg::Matrix> mg_interface( + mg_interface_matrices); + + Multigrid> mg( + dof, mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother); + mg.set_edge_matrices(mg_interface, mg_interface); + PreconditionMG, + MGTransferMatrixFree> + preconditioner(dof, mg, mg_transfer); + + { + // avoid output from inner (coarse-level) solver + deallog.depth_file(3); + + ReductionControl control(30, 1e-20, 1e-7); + SolverCG> solver(control); + solver.solve(fine_matrix, sol, in, preconditioner); + } + + fine_matrix.clear(); + for (unsigned int level = 0; + level < dof.get_triangulation().n_global_levels(); + ++level) + mg_matrices[level].clear(); +} + + + +template +void +test() +{ + parallel::distributed::Triangulation tria( + MPI_COMM_WORLD, + Triangulation::limit_level_difference_at_vertices, + parallel::distributed::Triangulation::construct_multigrid_hierarchy); + GridGenerator::hyper_cube(tria); + tria.refine_global(6 - dim); + const unsigned int n_runs = fe_degree == 1 ? 6 - dim : 5 - dim; + for (unsigned int i = 0; i < n_runs; ++i) + { + for (typename Triangulation::active_cell_iterator cell = + tria.begin_active(); + cell != tria.end(); + ++cell) + if (cell->is_locally_owned() && + ((cell->center().norm() < 0.5 && + (cell->level() < 5 || cell->center().norm() > 0.45)) || + (dim == 2 && cell->center().norm() > 1.2))) + cell->set_refine_flag(); + tria.execute_coarsening_and_refinement(); + FE_Q fe(fe_degree); + DoFHandler dof(tria); + dof.distribute_dofs(fe); + dof.distribute_mg_dofs(fe); + + do_test(dof); + } +} + + + +int +main(int argc, char **argv) +{ + Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1); + mpi_initlog(true); + + test<2, 2>(); +} diff --git a/tests/matrix_free/parallel_multigrid_adaptive_08.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=3.output b/tests/matrix_free/parallel_multigrid_adaptive_08.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=3.output new file mode 100644 index 000000000000..f00e1a40b439 --- /dev/null +++ b/tests/matrix_free/parallel_multigrid_adaptive_08.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=3.output @@ -0,0 +1,47 @@ + +DEAL::Testing FE_Q<2>(2) +DEAL::Number of degrees of freedom: 1935 +DEAL:cg::Starting value 43.0929 +DEAL:cg:cg::Starting value 2.63785 +DEAL:cg:cg::Convergence step 1 value 0.00000 +DEAL:cg:cg::Starting value 0.000574845 +DEAL:cg:cg::Convergence step 1 value 0.00000 +DEAL:cg:cg::Starting value 4.62010e-05 +DEAL:cg:cg::Convergence step 1 value 6.77626e-21 +DEAL:cg:cg::Starting value 6.27180e-07 +DEAL:cg:cg::Convergence step 1 value 1.05879e-22 +DEAL:cg:cg::Starting value 3.19916e-08 +DEAL:cg:cg::Convergence step 1 value 0.00000 +DEAL:cg::Convergence step 5 value 2.10775e-06 +DEAL::Testing FE_Q<2>(2) +DEAL::Number of degrees of freedom: 3403 +DEAL:cg::Starting value 55.4346 +DEAL:cg:cg::Starting value 3.96150 +DEAL:cg:cg::Convergence step 1 value 0.00000 +DEAL:cg:cg::Starting value 0.00121318 +DEAL:cg:cg::Convergence step 1 value 0.00000 +DEAL:cg:cg::Starting value 9.44668e-05 +DEAL:cg:cg::Convergence step 1 value 1.35525e-20 +DEAL:cg:cg::Starting value 1.80128e-06 +DEAL:cg:cg::Convergence step 1 value 2.11758e-22 +DEAL:cg:cg::Starting value 1.21766e-07 +DEAL:cg:cg::Convergence step 1 value 2.64698e-23 +DEAL:cg:cg::Starting value 5.04178e-09 +DEAL:cg:cg::Convergence step 1 value 0.00000 +DEAL:cg::Convergence step 6 value 4.24128e-07 +DEAL::Testing FE_Q<2>(2) +DEAL::Number of degrees of freedom: 8417 +DEAL:cg::Starting value 87.1149 +DEAL:cg:cg::Starting value 9.09582 +DEAL:cg:cg::Convergence step 1 value 0.00000 +DEAL:cg:cg::Starting value 0.00294550 +DEAL:cg:cg::Convergence step 1 value 0.00000 +DEAL:cg:cg::Starting value 0.000242151 +DEAL:cg:cg::Convergence step 1 value 0.00000 +DEAL:cg:cg::Starting value 3.21426e-06 +DEAL:cg:cg::Convergence step 1 value 0.00000 +DEAL:cg:cg::Starting value 1.60211e-07 +DEAL:cg:cg::Convergence step 1 value 0.00000 +DEAL:cg:cg::Starting value 3.38024e-09 +DEAL:cg:cg::Convergence step 1 value 4.13590e-25 +DEAL:cg::Convergence step 6 value 2.56705e-07 From 797969ed01c7f685b8495e77f34ea7bf33ce9abb Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Tue, 5 Feb 2019 19:08:36 +0100 Subject: [PATCH 067/507] Add changelog. --- doc/news/changes/minor/20190205MartinKronbichler | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 doc/news/changes/minor/20190205MartinKronbichler 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) From adf0ac2259e3e1943af51e4eeec13b3303989500 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Wed, 6 Feb 2019 14:18:56 +0100 Subject: [PATCH 068/507] use binary search in BlockIndices::global_to_local() --- doc/news/changes/minor/20190206DenisDavydov | 4 ++ include/deal.II/lac/block_indices.h | 8 +-- tests/lac/block_indices_02.cc | 60 +++++++++++++++++++++ tests/lac/block_indices_02.output | 11 ++++ 4 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 doc/news/changes/minor/20190206DenisDavydov create mode 100644 tests/lac/block_indices_02.cc create mode 100644 tests/lac/block_indices_02.output 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/include/deal.II/lac/block_indices.h b/include/deal.II/lac/block_indices.h index 6ada38375a72..ef81f81c6e54 100644 --- a/include/deal.II/lac/block_indices.h +++ b/include/deal.II/lac/block_indices.h @@ -333,11 +333,11 @@ BlockIndices::global_to_local(const size_type i) const Assert(i < total_size(), ExcIndexRangeType(i, 0, total_size())); Assert(n_blocks > 0, ExcLowerRangeType(i, size_type(1))); - unsigned int block = n_blocks - 1; - while (i < start_indices[block]) - --block; + // start_indices[0] == 0 so we might as well start from the next one + const auto it = + --std::upper_bound(++start_indices.begin(), start_indices.end(), i); - return {block, i - start_indices[block]}; + return {std::distance(start_indices.begin(), it), i - *it}; } diff --git a/tests/lac/block_indices_02.cc b/tests/lac/block_indices_02.cc new file mode 100644 index 000000000000..0d2cc2c4bd2f --- /dev/null +++ b/tests/lac/block_indices_02.cc @@ -0,0 +1,60 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Test BlockIndices::global_to_local() for very large number of blocks + +#include + +#include "../tests.h" + + + +void +test() +{ + constexpr unsigned int n_blocks = 10000; + constexpr types::global_dof_index block_size = 3; + constexpr types::global_dof_index size = n_blocks * block_size; + BlockIndices idx(n_blocks, block_size); + + const std::vector is = {{0, + 1, + block_size * 500 + 2, + block_size * 600, + block_size * 701 - 1, + size - 1}}; + + deallog << "n_blocks: " << n_blocks << std::endl + << "block_size: " << block_size << std::endl + << "size: " << idx.size() << std::endl; + for (auto i : is) + { + const auto p = idx.global_to_local(i); + AssertDimension(p.first, i / block_size); + AssertDimension(p.second, i % block_size); + deallog << i << " -> (" << p.first << "," << p.second << ")" << std::endl; + } + + deallog << std::endl; +} + + +int +main() +{ + initlog(); + test(); +} diff --git a/tests/lac/block_indices_02.output b/tests/lac/block_indices_02.output new file mode 100644 index 000000000000..6265aaf46676 --- /dev/null +++ b/tests/lac/block_indices_02.output @@ -0,0 +1,11 @@ + +DEAL::n_blocks: 10000 +DEAL::block_size: 3 +DEAL::size: 10000 +DEAL::0 -> (0,0) +DEAL::1 -> (0,1) +DEAL::1502 -> (500,2) +DEAL::1800 -> (600,0) +DEAL::2102 -> (700,2) +DEAL::29999 -> (9999,2) +DEAL:: From b6cd01769019e600993cbe061aef92df62c370fc Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Wed, 6 Feb 2019 17:00:24 -0500 Subject: [PATCH 069/507] Do not use I in header files due to conflict with The C version of defines the macro I. So when a third-party library such as lapacke include is included before the header the variable I is expanded which trips the compiler. --- include/deal.II/base/patterns.h | 16 ++++++++-------- include/deal.II/physics/transformations.h | 10 ++++++---- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/include/deal.II/base/patterns.h b/include/deal.II/base/patterns.h index d4ea6babc0b2..3a8617fc91e0 100644 --- a/include/deal.II/base/patterns.h +++ b/include/deal.II/base/patterns.h @@ -2296,15 +2296,15 @@ namespace Patterns } private: - template + template static std::array::value> to_string_internal_1(const T & t, const Patterns::Tuple &pattern, - std_cxx14::index_sequence) + std_cxx14::index_sequence) { std::array::value> a = { - {Convert::type>::to_string( - std::get(t), pattern.get_pattern(I).clone())...}}; + {Convert::type>::to_string( + std::get(t), pattern.get_pattern(U).clone())...}}; return a; } @@ -2317,15 +2317,15 @@ namespace Patterns std_cxx14::make_index_sequence::value>{}); } - template + template static T to_value_internal_1(const std::vector &s, const Patterns::Tuple & pattern, - std_cxx14::index_sequence) + std_cxx14::index_sequence) { return std::make_tuple( - Convert::type>::to_value( - s[I], pattern.get_pattern(I).clone())...); + Convert::type>::to_value( + s[U], pattern.get_pattern(U).clone())...); } static T diff --git a/include/deal.II/physics/transformations.h b/include/deal.II/physics/transformations.h index 322aa29747fa..12e8fcc8a328 100644 --- a/include/deal.II/physics/transformations.h +++ b/include/deal.II/physics/transformations.h @@ -852,8 +852,9 @@ namespace internal Tensor<2, dim, Number> tmp_1; for (unsigned int i = 0; i < dim; ++i) for (unsigned int J = 0; J < dim; ++J) - for (unsigned int I = 0; I < dim; ++I) - tmp_1[i][J] += F[i][I] * T[I][J]; + // Loop over I but complex.h defines a macro I, so use I_ instead + for (unsigned int I_ = 0; I_ < dim; ++I_) + tmp_1[i][J] += F[i][I_] * T[I_][J]; dealii::SymmetricTensor<2, dim, Number> out; for (unsigned int i = 0; i < dim; ++i) @@ -918,12 +919,13 @@ namespace internal // Push forward (inner) index 1 Tensor<4, dim, Number> tmp; - for (unsigned int I = 0; I < dim; ++I) + // Loop over I but complex.h defines a macro I, so use I_ instead + for (unsigned int I_ = 0; I_ < dim; ++I_) for (unsigned int j = 0; j < dim; ++j) for (unsigned int K = 0; K < dim; ++K) for (unsigned int L = 0; L < dim; ++L) for (unsigned int J = 0; J < dim; ++J) - tmp[I][j][K][L] += F[j][J] * H[I][J][K][L]; + tmp[I_][j][K][L] += F[j][J] * H[I_][J][K][L]; // Push forward (outer) indices 0 and 3 tmp = contract<1, 0>(F, contract<3, 1>(tmp, F)); From 479cd3d51f46b9eac0170f03e78917ed959b8f92 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 7 Feb 2019 00:22:57 +0100 Subject: [PATCH 070/507] Use size_type for rows in ChunkSparsityPattern --- include/deal.II/lac/chunk_sparsity_pattern.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/include/deal.II/lac/chunk_sparsity_pattern.h b/include/deal.II/lac/chunk_sparsity_pattern.h index 4a458f598213..a43a3f9558d6 100644 --- a/include/deal.II/lac/chunk_sparsity_pattern.h +++ b/include/deal.II/lac/chunk_sparsity_pattern.h @@ -64,10 +64,15 @@ namespace ChunkSparsityPatternIterators class Accessor { public: + /** + * Declare the type for container size. + */ + using size_type = types::global_dof_index; + /** * Constructor. */ - Accessor(const ChunkSparsityPattern *matrix, const unsigned int row); + Accessor(const ChunkSparsityPattern *matrix, const size_type row); /** * Constructor. Construct the end accessor for the given sparsity pattern. @@ -165,11 +170,16 @@ namespace ChunkSparsityPatternIterators class Iterator { public: + /** + * Declare the type for container size. + */ + using size_type = types::global_dof_index; + /** * Constructor. Create an iterator into the sparsity pattern @p sp for the * given row and the index within it. */ - Iterator(const ChunkSparsityPattern *sp, const unsigned int row); + Iterator(const ChunkSparsityPattern *sp, const size_type row); /** * Prefix increment. @@ -865,7 +875,7 @@ class ChunkSparsityPattern : public Subscriptor namespace ChunkSparsityPatternIterators { inline Accessor::Accessor(const ChunkSparsityPattern *sparsity_pattern, - const unsigned int row) + const size_type row) : sparsity_pattern(sparsity_pattern) , reduced_accessor(row == sparsity_pattern->n_rows() ? *sparsity_pattern->sparsity_pattern.end() : @@ -1039,7 +1049,7 @@ namespace ChunkSparsityPatternIterators inline Iterator::Iterator(const ChunkSparsityPattern *sparsity_pattern, - const unsigned int row) + const size_type row) : accessor(sparsity_pattern, row) {} From b163e04e589737eba7702e93f648073022b3afc1 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 7 Feb 2019 10:43:15 +0100 Subject: [PATCH 071/507] Replace all unsigned int by size_type in ChunkSparsityPattern --- include/deal.II/lac/chunk_sparsity_pattern.h | 90 ++++++++++---------- source/lac/chunk_sparsity_pattern.cc | 18 ++-- 2 files changed, 53 insertions(+), 55 deletions(-) diff --git a/include/deal.II/lac/chunk_sparsity_pattern.h b/include/deal.II/lac/chunk_sparsity_pattern.h index a43a3f9558d6..cc0d6969c674 100644 --- a/include/deal.II/lac/chunk_sparsity_pattern.h +++ b/include/deal.II/lac/chunk_sparsity_pattern.h @@ -83,7 +83,7 @@ namespace ChunkSparsityPatternIterators * Row number of the element represented by this object. This function can * only be called for entries for which is_valid_entry() is true. */ - unsigned int + size_type row() const; /** @@ -96,7 +96,7 @@ namespace ChunkSparsityPatternIterators * Column number of the element represented by this object. This function * can only be called for entries for which is_valid_entry() is true. */ - unsigned int + size_type column() const; /** @@ -143,12 +143,12 @@ namespace ChunkSparsityPatternIterators /** * Current chunk row number. */ - unsigned int chunk_row; + size_type chunk_row; /** * Current chunk col number. */ - unsigned int chunk_col; + size_type chunk_col; /** * Move the accessor to the next nonzero entry in the matrix. @@ -443,13 +443,12 @@ class ChunkSparsityPattern : public Subscriptor * these iterators) must be a container itself that provides functions * begin and end designating a range of iterators that * describe the contents of one line. Dereferencing these inner iterators - * must either yield a pair of an unsigned integer as column index and a + * must either yield a pair of a scalar as column index and a * value of arbitrary type (such a type would be used if we wanted to - * describe a sparse matrix with one such object), or simply an unsigned - * integer (of we only wanted to describe a sparsity pattern). The function - * is able to determine itself whether an unsigned integer or a pair is what - * we get after dereferencing the inner iterators, through some template - * magic. + * describe a sparse matrix with one such object), or simply a scalar (if we + * only wanted to describe a sparsity pattern). The function is able to + * determine itself whether a scalar or a pair is what we get after + * dereferencing the inner iterators, through some template magic. * * While the order of the outer iterators denotes the different rows of the * matrix, the order of the inner iterator denoting the columns does not @@ -471,7 +470,7 @@ class ChunkSparsityPattern : public Subscriptor * Note that this example works since the iterators dereferenced yield * containers with functions begin and end (namely * std::vectors), and the inner iterators dereferenced yield - * unsigned integers as column indices. Note that we could have replaced + * scalars as column indices. Note that we could have replaced * each of the two std::vector occurrences by std::list, * and the inner one by std::set as well. * @@ -493,12 +492,12 @@ class ChunkSparsityPattern : public Subscriptor * @endcode * * This example works because dereferencing iterators of the inner type - * yields a pair of unsigned integers and a value, the first of which we + * yields a pair of scalars and a value, the first of which we * take as column index. As previously, the outer std::vector could - * be replaced by std::list, and the inner std::map could be replaced by std::vector >, or a list or set of such pairs, as they all return - * iterators that point to such pairs. + * be replaced by std::list, and the inner + * std::map could be replaced by + * std::vector >, or a list or set of + * such pairs, as they all return iterators that point to such pairs. */ template void @@ -547,11 +546,11 @@ class ChunkSparsityPattern : public Subscriptor */ template void - create_from(const unsigned int m, - const unsigned int n, - const Sparsity & sparsity_pattern_for_chunks, - const unsigned int chunk_size, - const bool optimize_diagonal = true); + create_from(const size_type m, + const size_type n, + const Sparsity &sparsity_pattern_for_chunks, + const size_type chunk_size, + const bool optimize_diagonal = true); /** * Return whether the object is empty. It is empty if no memory is @@ -683,7 +682,7 @@ class ChunkSparsityPattern : public Subscriptor * that case. */ iterator - begin(const unsigned int r) const; + begin(const size_type r) const; /** * Final iterator of row r. It points to the first element past the @@ -694,7 +693,7 @@ class ChunkSparsityPattern : public Subscriptor * matrix. */ iterator - end(const unsigned int r) const; + end(const size_type r) const; /** * Write the data of this object en bloc to a file. This is done in a binary @@ -764,22 +763,22 @@ class ChunkSparsityPattern : public Subscriptor * Exception */ DeclException1(ExcInvalidNumber, - int, + size_type, << "The provided number is invalid here: " << arg1); /** * Exception */ DeclException2(ExcInvalidIndex, - int, - int, + size_type, + size_type, << "The given index " << arg1 << " should be less than " << arg2 << "."); /** * Exception */ DeclException2(ExcNotEnoughSpace, - int, - int, + size_type, + size_type, << "Upon entering a new entry to row " << arg1 << ": there was no free entry any more. " << std::endl << "(Maximum number of entries for this row: " << arg2 @@ -808,8 +807,8 @@ class ChunkSparsityPattern : public Subscriptor * Exception */ DeclException2(ExcIteratorRange, - int, - int, + size_type, + size_type, << "The iterators denote a range of " << arg1 << " elements, but the given number of rows was " << arg2); /** @@ -820,15 +819,15 @@ class ChunkSparsityPattern : public Subscriptor * Exception */ DeclException1(ExcInvalidNumberOfPartitions, - int, + size_type, << "The number of partitions you gave is " << arg1 << ", but must be greater than zero."); /** * Exception */ DeclException2(ExcInvalidArraySize, - int, - int, + size_type, + size_type, << "The array has size " << arg1 << " but should have size " << arg2); //@} @@ -912,7 +911,7 @@ namespace ChunkSparsityPatternIterators - inline unsigned int + inline Accessor::size_type Accessor::row() const { Assert(is_valid_entry() == true, ExcInvalidIterator()); @@ -923,7 +922,7 @@ namespace ChunkSparsityPatternIterators - inline unsigned int + inline Accessor::size_type Accessor::column() const { Assert(is_valid_entry() == true, ExcInvalidIterator()); @@ -970,13 +969,12 @@ namespace ChunkSparsityPatternIterators reduced_accessor.container->n_nonzero_elements()) return true; - const unsigned int global_row = sparsity_pattern->get_chunk_size() * - reduced_accessor.row() + - chunk_row, - other_global_row = - sparsity_pattern->get_chunk_size() * - other.reduced_accessor.row() + - other.chunk_row; + const auto global_row = sparsity_pattern->get_chunk_size() * + reduced_accessor.row() + + chunk_row, + other_global_row = sparsity_pattern->get_chunk_size() * + other.reduced_accessor.row() + + other.chunk_row; if (global_row < other_global_row) return true; else if (global_row > other_global_row) @@ -993,7 +991,7 @@ namespace ChunkSparsityPatternIterators inline void Accessor::advance() { - const unsigned int chunk_size = sparsity_pattern->get_chunk_size(); + const auto chunk_size = sparsity_pattern->get_chunk_size(); Assert(chunk_row < chunk_size && chunk_col < chunk_size, ExcIteratorPastEnd()); Assert(reduced_accessor.row() * chunk_size + chunk_row < @@ -1014,7 +1012,7 @@ namespace ChunkSparsityPatternIterators reduced_accessor.column() * chunk_size + chunk_col == sparsity_pattern->n_cols()) { - const unsigned int reduced_row = reduced_accessor.row(); + const auto reduced_row = reduced_accessor.row(); // end of row if (reduced_accessor.linear_index + 1 == reduced_accessor.container->rowstart[reduced_row + 1]) @@ -1128,7 +1126,7 @@ ChunkSparsityPattern::end() const inline ChunkSparsityPattern::iterator -ChunkSparsityPattern::begin(const unsigned int r) const +ChunkSparsityPattern::begin(const size_type r) const { Assert(r < n_rows(), ExcIndexRange(r, 0, n_rows())); return {this, r}; @@ -1137,7 +1135,7 @@ ChunkSparsityPattern::begin(const unsigned int r) const inline ChunkSparsityPattern::iterator -ChunkSparsityPattern::end(const unsigned int r) const +ChunkSparsityPattern::end(const size_type r) const { Assert(r < n_rows(), ExcIndexRange(r, 0, n_rows())); return {this, r + 1}; diff --git a/source/lac/chunk_sparsity_pattern.cc b/source/lac/chunk_sparsity_pattern.cc index 60b4167a5399..db9cc4bbe47b 100644 --- a/source/lac/chunk_sparsity_pattern.cc +++ b/source/lac/chunk_sparsity_pattern.cc @@ -292,10 +292,10 @@ namespace internal template void -ChunkSparsityPattern::create_from(const unsigned int m, - const unsigned int n, +ChunkSparsityPattern::create_from(const size_type m, + const size_type n, const Sparsity &sparsity_pattern_for_chunks, - const unsigned int chunk_size_in, + const size_type chunk_size_in, const bool) { Assert(m > (sparsity_pattern_for_chunks.n_rows() - 1) * chunk_size_in && @@ -598,17 +598,17 @@ ChunkSparsityPattern::copy_from( const DynamicSparsityPattern &, const size_type); template void -ChunkSparsityPattern::create_from(const unsigned int, - const unsigned int, +ChunkSparsityPattern::create_from(const size_type, + const size_type, const SparsityPattern &, - const unsigned int, + const size_type, const bool); template void ChunkSparsityPattern::create_from( - const unsigned int, - const unsigned int, + const size_type, + const size_type, const DynamicSparsityPattern &, - const unsigned int, + const size_type, const bool); template void ChunkSparsityPattern::copy_from(const FullMatrix &, From 371a71a783fc84f2c4b07852db71ee9ab589af0e Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 7 Feb 2019 14:00:08 +0100 Subject: [PATCH 072/507] Replace 'scalar' by 'integer' --- include/deal.II/lac/chunk_sparsity_pattern.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/deal.II/lac/chunk_sparsity_pattern.h b/include/deal.II/lac/chunk_sparsity_pattern.h index cc0d6969c674..e958ecd89a54 100644 --- a/include/deal.II/lac/chunk_sparsity_pattern.h +++ b/include/deal.II/lac/chunk_sparsity_pattern.h @@ -443,11 +443,11 @@ class ChunkSparsityPattern : public Subscriptor * these iterators) must be a container itself that provides functions * begin and end designating a range of iterators that * describe the contents of one line. Dereferencing these inner iterators - * must either yield a pair of a scalar as column index and a + * must either yield a pair of an integer as column index and a * value of arbitrary type (such a type would be used if we wanted to - * describe a sparse matrix with one such object), or simply a scalar (if we + * describe a sparse matrix with one such object), or simply an integer (if we * only wanted to describe a sparsity pattern). The function is able to - * determine itself whether a scalar or a pair is what we get after + * determine itself whether an integer or a pair is what we get after * dereferencing the inner iterators, through some template magic. * * While the order of the outer iterators denotes the different rows of the @@ -470,7 +470,7 @@ class ChunkSparsityPattern : public Subscriptor * Note that this example works since the iterators dereferenced yield * containers with functions begin and end (namely * std::vectors), and the inner iterators dereferenced yield - * scalars as column indices. Note that we could have replaced + * integers as column indices. Note that we could have replaced * each of the two std::vector occurrences by std::list, * and the inner one by std::set as well. * @@ -492,7 +492,7 @@ class ChunkSparsityPattern : public Subscriptor * @endcode * * This example works because dereferencing iterators of the inner type - * yields a pair of scalars and a value, the first of which we + * yields a pair of integers and a value, the first of which we * take as column index. As previously, the outer std::vector could * be replaced by std::list, and the inner * std::map could be replaced by From d4473deb06d77babfd0573ae6c4ce8cb723912c3 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Tue, 5 Feb 2019 10:20:26 -0600 Subject: [PATCH 073/507] CMake: Do not automatically rebuild a project when switching build type For a long time the "debug" and "release" targets of our convenience macro DEAL_II_INVOKE_AUTOPILOT automatically rebuild the project when switching to the debug or release flavor. Closes #7693 --- cmake/macros/macro_deal_ii_invoke_autopilot.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmake/macros/macro_deal_ii_invoke_autopilot.cmake b/cmake/macros/macro_deal_ii_invoke_autopilot.cmake index 94fcbc8a4982..a494f0a9e8f4 100644 --- a/cmake/macros/macro_deal_ii_invoke_autopilot.cmake +++ b/cmake/macros/macro_deal_ii_invoke_autopilot.cmake @@ -141,13 +141,11 @@ MACRO(DEAL_II_INVOKE_AUTOPILOT) # 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" ) From 06181108246e8c09c298a91d0730bb8061b7991f Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Tue, 5 Feb 2019 10:26:28 -0600 Subject: [PATCH 074/507] add a changes entry --- doc/news/changes/incompatibilities/20190205Maier | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 doc/news/changes/incompatibilities/20190205Maier 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) From 613673a1c0a1470ff7ad2e486b4cf8242636ae5e Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 7 Feb 2019 18:04:32 +0100 Subject: [PATCH 075/507] Unrestrict ScaLAPACKMatrix::copy_to/from --- include/deal.II/lac/scalapack.h | 3 --- source/lac/scalapack.cc | 40 ++++++++++++--------------------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/include/deal.II/lac/scalapack.h b/include/deal.II/lac/scalapack.h index ebc212f622fd..e44ef1ffe48c 100644 --- a/include/deal.II/lac/scalapack.h +++ b/include/deal.II/lac/scalapack.h @@ -203,8 +203,6 @@ class ScaLAPACKMatrix : protected TransposeTable * The user has to ensure that all processes call this with identical @p rank. * The @p rank refers to a process of the MPI communicator used to create the process grid * of the distributed matrix. - * - * @note This function requires MPI-3.0 support */ void copy_from(const LAPACKFullMatrix &matrix, @@ -215,7 +213,6 @@ class ScaLAPACKMatrix : protected TransposeTable * * @note This function should only be used for relatively small matrix * dimensions. It is primarily intended for debugging purposes. - * This function requires MPI-3.0 support */ void copy_to(FullMatrix &matrix) const; diff --git a/source/lac/scalapack.cc b/source/lac/scalapack.cc index 8651557833d8..89d98c930c22 100644 --- a/source/lac/scalapack.cc +++ b/source/lac/scalapack.cc @@ -361,19 +361,18 @@ void ScaLAPACKMatrix::copy_from(const LAPACKFullMatrix &B, const unsigned int rank) { -# if DEAL_II_MPI_VERSION_GTE(3, 0) if (n_rows * n_columns == 0) return; const unsigned int this_mpi_process( Utilities::MPI::this_mpi_process(this->grid->mpi_communicator)); -# ifdef DEBUG +# ifdef DEBUG Assert(Utilities::MPI::max(rank, this->grid->mpi_communicator) == rank, ExcMessage("All processes have to call routine with identical rank")); Assert(Utilities::MPI::min(rank, this->grid->mpi_communicator) == rank, ExcMessage("All processes have to call routine with identical rank")); -# endif +# endif // root process has to be active in the grid of A if (this_mpi_process == rank) @@ -391,12 +390,12 @@ ScaLAPACKMatrix::copy_from(const LAPACKFullMatrix &B, const int n = 1; const std::vector ranks(n, rank); MPI_Group group_B; - MPI_Group_incl(group_A, n, ranks.data(), &group_B); + MPI_Group_incl(group_A, n, DEAL_II_MPI_CONST_CAST(ranks.data()), &group_B); MPI_Comm communicator_B; - MPI_Comm_create_group(this->grid->mpi_communicator, - group_B, - 0, - &communicator_B); + Utilities::MPI::create_group(this->grid->mpi_communicator, + group_B, + 0, + &communicator_B); int n_proc_rows_B = 1, n_proc_cols_B = 1; int this_process_row_B = -1, this_process_column_B = -1; int blacs_context_B = -1; @@ -485,11 +484,6 @@ ScaLAPACKMatrix::copy_from(const LAPACKFullMatrix &B, MPI_Comm_free(&communicator_B); state = LAPACKSupport::matrix; -# else - (void)B; - (void)rank; - AssertThrow(false, ExcNotImplemented()); -# endif } @@ -534,19 +528,18 @@ void ScaLAPACKMatrix::copy_to(LAPACKFullMatrix &B, const unsigned int rank) const { -# if DEAL_II_MPI_VERSION_GTE(3, 0) if (n_rows * n_columns == 0) return; const unsigned int this_mpi_process( Utilities::MPI::this_mpi_process(this->grid->mpi_communicator)); -# ifdef DEBUG +# ifdef DEBUG Assert(Utilities::MPI::max(rank, this->grid->mpi_communicator) == rank, ExcMessage("All processes have to call routine with identical rank")); Assert(Utilities::MPI::min(rank, this->grid->mpi_communicator) == rank, ExcMessage("All processes have to call routine with identical rank")); -# endif +# endif if (this_mpi_process == rank) { @@ -565,12 +558,12 @@ ScaLAPACKMatrix::copy_to(LAPACKFullMatrix &B, const int n = 1; const std::vector ranks(n, rank); MPI_Group group_B; - MPI_Group_incl(group_A, n, ranks.data(), &group_B); + MPI_Group_incl(group_A, n, DEAL_II_MPI_CONST_CAST(ranks.data()), &group_B); MPI_Comm communicator_B; - MPI_Comm_create_group(this->grid->mpi_communicator, - group_B, - 0, - &communicator_B); + Utilities::MPI::create_group(this->grid->mpi_communicator, + group_B, + 0, + &communicator_B); int n_proc_rows_B = 1, n_proc_cols_B = 1; int this_process_row_B = -1, this_process_column_B = -1; int blacs_context_B = -1; @@ -657,11 +650,6 @@ ScaLAPACKMatrix::copy_to(LAPACKFullMatrix &B, MPI_Group_free(&group_B); if (MPI_COMM_NULL != communicator_B) MPI_Comm_free(&communicator_B); -# else - (void)B; - (void)rank; - AssertThrow(false, ExcNotImplemented()); -# endif } From 9d6dd6845c3bc9eabd4d27ac4e4caa76f3d78436 Mon Sep 17 00:00:00 2001 From: Marc Fehling Date: Tue, 18 Dec 2018 15:23:15 +0100 Subject: [PATCH 076/507] Automatic transfer of active fe indices during refinement and serialization. --- doc/news/changes/major/20190127Fehling | 10 + doc/news/changes/minor/20180723MarcFehling | 6 - .../distributed/active_fe_indices_transfer.h | 211 --------- .../deal.II/distributed/solution_transfer.h | 82 +--- include/deal.II/hp/dof_handler.h | 147 +++++- source/distributed/CMakeLists.txt | 2 - .../distributed/active_fe_indices_transfer.cc | 215 --------- .../active_fe_indices_transfer.inst.in | 30 -- source/hp/dof_handler.cc | 425 ++++++++++++++---- tests/mpi/hp_active_fe_indices_transfer_01.cc | 94 ++-- tests/mpi/hp_active_fe_indices_transfer_02.cc | 127 ++++++ ...ransfer_02.with_p4est=true.mpirun=2.output | 175 ++++++++ ...ransfer_02.with_p4est=true.mpirun=8.output | 223 +++++++++ tests/mpi/hp_cell_weights_01.cc | 5 - tests/mpi/hp_cell_weights_02.cc | 5 - tests/mpi/p4est_save_06.cc | 10 +- tests/mpi/solution_transfer_04.cc | 5 - 17 files changed, 1073 insertions(+), 699 deletions(-) create mode 100644 doc/news/changes/major/20190127Fehling delete mode 100644 doc/news/changes/minor/20180723MarcFehling delete mode 100644 include/deal.II/distributed/active_fe_indices_transfer.h delete mode 100644 source/distributed/active_fe_indices_transfer.cc delete mode 100644 source/distributed/active_fe_indices_transfer.inst.in create mode 100644 tests/mpi/hp_active_fe_indices_transfer_02.cc create mode 100644 tests/mpi/hp_active_fe_indices_transfer_02.with_p4est=true.mpirun=2.output create mode 100644 tests/mpi/hp_active_fe_indices_transfer_02.with_p4est=true.mpirun=8.output 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/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/include/deal.II/distributed/active_fe_indices_transfer.h b/include/deal.II/distributed/active_fe_indices_transfer.h deleted file mode 100644 index c1c8702fe4e7..000000000000 --- a/include/deal.II/distributed/active_fe_indices_transfer.h +++ /dev/null @@ -1,211 +0,0 @@ -// --------------------------------------------------------------------- -// -// 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. -// -// --------------------------------------------------------------------- - -#ifndef dealii_distributed_active_fe_indices_transfer_h -#define dealii_distributed_active_fe_indices_transfer_h - -#include - -#include - -#include - - -DEAL_II_NAMESPACE_OPEN - -namespace parallel -{ - namespace distributed - { - /** - * This class transfers each cell's `active_fe_index` of a hp::FECollection - * attached to a hp::DoFHandler while refining and/or coarsening a - * distributed grid and handles the necessary communication. - * - * This class therefore does for the `active_fe_index` information of each - * cell what parallel::distributed::SolutionTransfer does for the values - * of degrees of freedom defined on a parallel::distributed::Triangulation. - * - * If refinement is involved in the data transfer process, the children of - * a refined cell inherit the `active_fe_index` from their parent. If - * cells get coarsened into one, the latter will get the least dominating - * `active_fe_index` amongst its children, as determined by the function - * hp::FECollection::find_least_face_dominating_fe_in_collection(). - * - * @note If you use more than one object to attach data to a - * parallel::distributed::Triangulation at the same time (e.g. a - * parallel::distributed::SolutionTransfer object), the calls to - * parallel::distributed::ActiveFEIndicesTransfer::prepare_for_transfer(), - * parallel::distributed::SolutionTransfer::prepare_for_coarsening_and_refinement() - * and parallel::distributed::SolutionTransfer::prepare_serialization(), - * as well as parallel::distributed::ActiveFEIndicesTransfer::unpack() and - * parallel::distributed::SolutionTransfer::interpolate(), or - * parallel::distributed::ActiveFEIndicesTransfer::deserialize() and - * parallel::distributed::SolutionTransfer::deserialize() for serialization, - * need to be in the same order, respectively. - * - *

Transferring each cell's active_fe_index

- * - * The following code snippet demonstrates how to transfer all active FE - * indices across refinement/coarsening of the triangulation that is - * registered to the hp::DoFHandler member object of this class. - * - * @code - * parallel::distributed::ActiveFEIndicesTransfer - * feidx_trans(hp_dof_handler); - * // flag some cells for refinement and coarsening, e.g. - * GridRefinement::refine_and_coarsen_fixed_fraction(tria, - * error_indicators, - * 0.3, - * 0.05); - * - * // prepare the triangulation, - * tria.prepare_coarsening_and_refinement(); - * - * // prepare the SolutionTransfer object for coarsening and refinement - * // and give the solution vector that we intend to interpolate later, - * feidx_trans.prepare_for_transfer(); - * - * // actually execute the refinement, - * tria.execute_coarsening_and_refinement(); - * - * // unpack all active fe indices, - * feidx_trans.unpack(); - * - * // redistribute dofs for further use, - * // using the active FE indices just restored - * hp_dof_handler.distribute_dofs(fe_collection); - * @endcode - * - * - *

Use for serialization

- * - * This class can be used to serialize and later deserialize a distributed - * mesh with attached data to separate files. If you use more than one - * hp::DoFHandler and therefore more than one - * parallel::distributed::ActiveFEIndicesTransfer object, they need to be - * serialized and deserialized in the same order. - * - * For serialization, the following code snippet saves not only the - * triangulation itself, but also the active FE indices of a hp::DoFHandler - * that works on this triangulation: - * @code - * parallel::distributed::ActiveFEIndicesTransfer - * feidx_trans(hp_dof_handler); - * feidx_trans.prepare_for_transfer(); - * - * triangulation.save(filename); - * @endcode - * - * Later, during deserialization, both the triangulation and all active FE - * indices of the hp::DoFHandler can be restored as follows: - * @code - * //[create coarse mesh...] - * triangulation.load(filename); - * - * parallel::distributed::ActiveFEIndicesTransfer - * feidx_trans(hp_dof_handler); - * feidx_trans.deserialize(); - * - * // distribute dofs for further use, - * // using the active FE indices just restored - * hp_dof_handler.distribute_dofs(fe_collection); - * @endcode - * - * @note See documentation of parallel::distributed::SolutionTransfer for - * matching code snippets in both cases. - * - * @ingroup distributed - * @author Marc Fehling, 2018 - */ - template - class ActiveFEIndicesTransfer - { - public: - /** - * Constructor. - * - * @param[in] dof The hp::DoFHandler on which all - * operations will happen. At the time when this constructor - * is called, the hp::DoFHandler still points to the triangulation - * before the refinement in question happens. - */ - ActiveFEIndicesTransfer(const hp::DoFHandler &dof_handler); - - /** - * Prepare the current object for coarsening and refinement or - * serialization. - */ - void - prepare_for_transfer(); - - /** - * Unpack the information previously stored in this object before - * the mesh was refined or coarsened onto the current set of cells. - */ - void - unpack(); - - /** - * Execute the deserialization of the stored information. - * This needs to be done after calling Triangulation::load(). - */ - void - deserialize(); - - private: - /** - * Pointer to the hp::DoFHandler to work with. - */ - SmartPointer, - ActiveFEIndicesTransfer> - dof_handler; - - /** - * The handle that the parallel::distributed::Triangulation has - * assigned to this object with which we can access our memory - * offset and our pack function. - */ - unsigned int handle; - - /** - * A callback function used to pack the data on the current mesh into - * objects that can later be retrieved after refinement, coarsening and - * repartitioning. - */ - std::vector - pack_callback( - const typename Triangulation::cell_iterator &cell, - const typename Triangulation::CellStatus status); - - /** - * A callback function used to unpack the data on the current mesh that - * has been packed up previously on the mesh before refinement, - * coarsening and repartitioning. - */ - void - unpack_callback( - const typename Triangulation::cell_iterator &cell, - const typename Triangulation::CellStatus status, - const boost::iterator_range::const_iterator> - &data_range); - }; - } // namespace distributed -} // namespace parallel - - -DEAL_II_NAMESPACE_CLOSE - -#endif diff --git a/include/deal.II/distributed/solution_transfer.h b/include/deal.II/distributed/solution_transfer.h index a0d47d7544cc..558ebeed2966 100644 --- a/include/deal.II/distributed/solution_transfer.h +++ b/include/deal.II/distributed/solution_transfer.h @@ -153,32 +153,12 @@ namespace parallel * * If an object of the hp::DoFHandler class is registered with an * instantiation of this parallel::distributed::SolutionTransfer - * class, the following requirements have to be met: - *
    - *
  • - * The hp::DoFHandler needs to be explicitly mentioned - * in the parallel::distributed::SolutionTransfer type, i.e.: - * @code - * parallel::distributed::SolutionsTransfer> sol_trans(hp_dof_handler); - * @endcode - *
  • - *
  • - * The transfer of the active_fe_index of each cell - * has to be scheduled as well in the parallel::distributed case, - * since ownerships of cells change during mesh repartitioning. - * This can be achieved with the - * parallel::distributed::ActiveFEIndicesTransfer class. The order in - * which both objects append data during the packing process does not - * matter. However, the unpacking process after refinement or - * deserialization requires the `active_fe_index` to be distributed - * before interpolating the data of the - * parallel::distributed::SolutionTransfer object, so that the correct - * FiniteElement object is associated with each cell. See the - * documentation on parallel::distributed::ActiveFEIndicesTransfer - * for further instructions. - *
  • - *
+ * class, it is necessary to explicitly specify this in the template + * argument list of this class, i.e.: + * @code + * parallel::distributed::SolutionsTransfer> sol_trans(hp_dof_handler); + * @endcode * * Since data on hp::DoFHandler objects is associated with many different * FiniteElement objects, each cell's data has to be processed with its @@ -190,44 +170,22 @@ namespace parallel * function hp::FECollection::find_least_face_dominating_fe_in_collection(), * and unpacked on the same cell with the same index. * - * Code snippets to demonstrate the usage of the - * parallel::distributed::SolutionTransfer class with hp::DoFHandler - * objects are provided in the following. Here VectorType - * is your favorite vector type, e.g. PETScWrappers::MPI::Vector, - * TrilinosWrappers::MPI::Vector, or corresponding block vectors. - * - * After refinement, the order in which to unpack the transferred data - * is important: - * @code - * //[prepare triangulation for refinement ...] - * - * parallel::distributed::ActiveFEIndicesTransfer - * feidx_trans(hp_dof_handler); - * parallel::distributed:: - * SolutionTransfer> - * sol_trans(hp_dof_handler); - * - * feidx_trans.prepare_for_transfer(); - * sol_trans.prepare_for_coarsening_and_refinement(solution); - * triangulation.execute_coarsening_and_refinement(); - * - * feidx_trans.unpack(); - * hp_dof_handler.distribute_dofs(fe_collection); - * - * VectorType interpolated_solution; - * //[create VectorType in the right size here ...] - * soltrans.interpolate(interpolated_solution); - * @endcode + * Transferring a solution across refinement works exactly like in the + * non-hp case. However, when considering serialization, we also have to + * store the active_fe_indices in an additional step. A code snippet + * demonstrating serialization with the + * parallel::distributed::SolutionTransfer class with hp::DoFHandler objects + * is provided in the following. Here VectorType is your favorite vector + * type, e.g. PETScWrappers::MPI::Vector, TrilinosWrappers::MPI::Vector, or + * corresponding block vectors. * * If vector has the locally relevant DoFs, serialization works as follows: * @code - * parallel::distributed::ActiveFEIndicesTransfer - * feidx_trans(hp_dof_handler); * parallel::distributed:: * SolutionTransfer> * sol_trans(hp_dof_handler); * - * feidx_trans.prepare_for_transfer(); + * hp_dof_handler.prepare_for_serialization_of_active_fe_indices(); * sol_trans.prepare_serialization(vector); * * triangulation.save(filename); @@ -239,14 +197,14 @@ namespace parallel * //[create coarse mesh...] * triangulation.load(filename); * - * hp::DoFHandler hp_dof_handler(triangulation); * hp::FECollection fe_collection; * //[prepare identical fe_collection...] - * hp_dof_handler.distribute_dofs(fe_collection); * - * parallel::distributed::ActiveFEIndicesTransfer - * feidx_trans(hp_dof_handler); - * feidx_trans.deserialize(); + * hp::DoFHandler hp_dof_handler(triangulation); + * // We need to introduce our dof_handler to the fe_collection + * // before setting all active_fe_indices. + * hp_dof_handler.distribute_dofs(fe_collection); + * hp_dof_handler.deserialize_active_fe_indices(); * hp_dof_handler.distribute_dofs(fe_collection); * * parallel::distributed:: diff --git a/include/deal.II/hp/dof_handler.h b/include/deal.II/hp/dof_handler.h index 95c33c30ed5f..29a3746ec89a 100644 --- a/include/deal.II/hp/dof_handler.h +++ b/include/deal.II/hp/dof_handler.h @@ -26,6 +26,8 @@ #include #include +#include + #include #include #include @@ -36,6 +38,7 @@ #include #include +#include #include #include @@ -159,12 +162,23 @@ namespace hp * @ref GlossArtificialCell "the glossary entry on artificial cells" * for more information. * - * Using a parallel::distributed::Triangulation with an hp::DoFHandler - * requires additional attention during coarsening and refinement, since - * no information on active FE indices will be automatically transferred. - * This has to be done manually using the - * parallel::distributed::ActiveFEIndicesTransfer class. Consult its - * documentation for more information. + * During refinement and coarsening, information about the @p active_fe_index + * of each cell will be automatically transferred. + * + * However, using a parallel::distributed::Triangulation with an + * hp::DoFHandler requires additional attention during serialization, since no + * information on active FE indices will be automatically transferred. This + * has to be done manually using the + * prepare_for_serialization_of_active_fe_indices() and + * deserialize_active_fe_indices() functions. The former has to be called + * before parallel::distributed::Triangulation::save() is invoked, and the + * latter needs to be run after parallel::distributed::Triangulation::load(). + * If further data will be attached to the triangulation via the + * parallel::distributed::CellDataTransfer, + * parallel::distributed::SolutionTransfer, or Particles::ParticleHandler + * classes, all corresponding preparation and deserialization function calls + * need to happen in the same order. Consult the documentation of + * parallel::distributed::SolutionTransfer for more information. * * * @ingroup dofs @@ -884,6 +898,43 @@ namespace hp virtual std::size_t memory_consumption() const; + /** + * Whenever serialization with a parallel::distributed::Triangulation as the + * underlying triangulation is considered, we also need to consider storing + * the active_fe_indices on all active cells as well. + * + * This function registers that these indices are to be stored whenever the + * parallel::distributed::Triangulation::save() function is called on the + * underlying triangulation. + * + * @note Currently only implemented for triangulations of type + * parallel::distributed::Triangulation. An assertion will be triggered if + * a different type is registered. + * + * @see The documentation of parallel::distributed::SolutionTransfer has further + * information on serialization. + */ + void + prepare_for_serialization_of_active_fe_indices(); + + /** + * Whenever serialization with a parallel::distributed::Triangulation as the + * underlying triangulation is considered, we also need to consider storing + * the active_fe_indices on all active cells as well. + * + * This function deserializes and distributes the previously stored + * active_fe_indices on all active cells. + * + * @note Currently only implemented for triangulations of type + * parallel::distributed::Triangulation. An assertion will be triggered if + * a different type is registered. + * + * @see The documentation of parallel::distributed::SolutionTransfer has further + * information on serialization. + */ + void + deserialize_active_fe_indices(); + /** * Write the data of this object to a stream for the purpose of * serialization. @@ -1039,17 +1090,70 @@ namespace hp post_refinement_action(); /** - * Functions that will be triggered through signals whenever the - * triangulation is modified, with the restriction that it is not - * a parallel::distributed::Triangulation. + * A function that will be triggered through a triangulation + * signal just before the associated Triangulation is modified. + * + * The function that stores the active_fe_indices of all cells that will + * be refined or coarsened before the refinement happens, so that + * they can be set again after refinement. + */ + void + pre_active_fe_index_transfer(); + + /** + * A function that will be triggered through a triangulation + * signal just before the associated parallel::shared::Triangulation is + * modified. + * + * The function that stores the active_fe_indices of all cells that will + * be refined or coarsened before the refinement happens, so that + * they can be set again after refinement. + */ + void + pre_shared_active_fe_index_transfer(); + + /** + * A function that will be triggered through a triangulation + * signal just before the associated parallel::distributed::Triangulation is + * modified. + * + * The function that stores all active_fe_indices on locally owned cells for + * distribution over all participating processors. + */ + void + pre_distributed_active_fe_index_transfer(); + + /** + * A function that will be triggered through a triangulation + * signal just after the associated Triangulation is modified. + * + * The function that restores the active_fe_indices of all cells that + * were refined or coarsened. + */ + void + post_active_fe_index_transfer(); + + /** + * A function that will be triggered through a triangulation + * signal just after the associated parallel::shared::Triangulation is + * modified. * - * Here they are used to administrate the active_fe_indices during the - * spatial refinement. + * The function that restores the active_fe_indices of all cells that + * were refined or coarsened. */ void - pre_refinement_fe_index_update(); + post_shared_active_fe_index_transfer(); + + /** + * A function that will be triggered through a triangulation + * signal just after the associated parallel::distributed::Triangulation is + * modified. + * + * The function that restores all active_fe_indices on locally owned cells + * that have been communicated. + */ void - post_refinement_fe_index_update(); + post_distributed_active_fe_index_transfer(); /** * Space to store the DoF numbers for the different levels. Analogous to @@ -1120,6 +1224,23 @@ namespace hp */ std::map coarsened_cells_fe_index; + /** + * Container to temporarily store the active_fe_index of every locally + * owned cell for transfer across parallel::distributed::Triangulation + * objects. + */ + std::vector active_fe_indices; + + /** + * Helper object to transfer all active_fe_indices on + * parallel::distributed::Triangulation objects during refinement/coarsening + * and serialization. + */ + std::unique_ptr< + parallel::distributed:: + CellDataTransfer>> + cell_data_transfer; + /** * A list of connections with which this object connects to the * triangulation to get information about when the triangulation changes. diff --git a/source/distributed/CMakeLists.txt b/source/distributed/CMakeLists.txt index ac47675cbe3a..fec5610af2b0 100644 --- a/source/distributed/CMakeLists.txt +++ b/source/distributed/CMakeLists.txt @@ -18,7 +18,6 @@ INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) SET(_unity_include_src grid_refinement.cc cell_weights.cc - active_fe_indices_transfer.cc cell_data_transfer.cc solution_transfer.cc tria.cc @@ -42,7 +41,6 @@ SETUP_SOURCE_LIST("${_unity_include_src}" SET(_inst grid_refinement.inst.in cell_weights.inst.in - active_fe_indices_transfer.inst.in cell_data_transfer.inst.in solution_transfer.inst.in tria.inst.in diff --git a/source/distributed/active_fe_indices_transfer.cc b/source/distributed/active_fe_indices_transfer.cc deleted file mode 100644 index 60ea718f17ca..000000000000 --- a/source/distributed/active_fe_indices_transfer.cc +++ /dev/null @@ -1,215 +0,0 @@ -// --------------------------------------------------------------------- -// -// 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. -// -// --------------------------------------------------------------------- - - -#include - -#ifdef DEAL_II_WITH_P4EST - -# include -# include - -# include - -# include - -DEAL_II_NAMESPACE_OPEN - -namespace parallel -{ - namespace distributed - { - template - ActiveFEIndicesTransfer::ActiveFEIndicesTransfer( - const hp::DoFHandler &dof_handler) - : dof_handler(&dof_handler, typeid(*this).name()) - , handle(numbers::invalid_unsigned_int) - { - Assert( - (dynamic_cast< - const parallel::distributed::Triangulation *>( - &(this->dof_handler)->get_triangulation()) != nullptr), - ExcMessage( - "parallel::distributed::ActiveFEIndicesTransfer requires a parallel::distributed::Triangulation object.")); - } - - - - template - void - ActiveFEIndicesTransfer::prepare_for_transfer() - { - parallel::distributed::Triangulation *tria = - (dynamic_cast *>( - const_cast *>( - &dof_handler->get_triangulation()))); - Assert(tria != nullptr, ExcInternalError()); - - handle = tria->register_data_attach( - std::bind(&ActiveFEIndicesTransfer::pack_callback, - this, - std::placeholders::_1, - std::placeholders::_2), - /*returns_variable_size_data=*/false); - } - - - - template - void - ActiveFEIndicesTransfer::unpack() - { - // TODO: casting away constness is bad - parallel::distributed::Triangulation *tria = - (dynamic_cast *>( - const_cast *>( - &dof_handler->get_triangulation()))); - Assert(tria != nullptr, ExcInternalError()); - - tria->notify_ready_to_unpack( - handle, - std::bind(&ActiveFEIndicesTransfer::unpack_callback, - this, - std::placeholders::_1, - std::placeholders::_2, - std::placeholders::_3)); - } - - - - template - void - ActiveFEIndicesTransfer::deserialize() - { - // For deserialization, we need to register this object - // to the triangulation first to get a valid handle for - // data access. - prepare_for_transfer(); - unpack(); - } - - - - template - std::vector - ActiveFEIndicesTransfer::pack_callback( - const typename Triangulation::cell_iterator &cell_, - const typename Triangulation::CellStatus status) - { - const typename hp::DoFHandler::cell_iterator cell( - *cell_, dof_handler); - - unsigned int fe_index = numbers::invalid_unsigned_int; - - switch (status) - { - case parallel::distributed::Triangulation::CELL_PERSIST: - case parallel::distributed::Triangulation::CELL_REFINE: - fe_index = cell->active_fe_index(); - break; - - case parallel::distributed::Triangulation::CELL_COARSEN: - // In this case, the callback function will be called on the parent - // cell which shall store the packed information. We need to choose - // from its children which ID to store. - { - std::set fe_indices_children; - for (unsigned int child_index = 0; - child_index < GeometryInfo::max_children_per_cell; - ++child_index) - { - typename hp::DoFHandler::cell_iterator child = - cell->child(child_index); - - fe_indices_children.insert(child->active_fe_index()); - } - - fe_index = - dof_handler->get_fe_collection() - .find_least_dominating_fe_in_collection(fe_indices_children, - /*codim=*/0); - - Assert(fe_index != numbers::invalid_unsigned_int, - ExcMessage( - "No FiniteElement has been found in your FECollection " - "that dominates all children of a cell you are trying " - "to coarsen!")); - } - break; - - default: - Assert(false, ExcInternalError()); - break; - } - - return Utilities::pack(fe_index, /*allow_compression=*/false); - } - - - - template - void - ActiveFEIndicesTransfer::unpack_callback( - const typename Triangulation::cell_iterator &cell_, - const typename Triangulation::CellStatus status, - const boost::iterator_range::const_iterator> - &data_range) - { - typename hp::DoFHandler::cell_iterator cell(*cell_, - dof_handler); - - const unsigned int fe_index = - Utilities::unpack(data_range.begin(), - data_range.end(), - /*allow_compression=*/false); - - Assert(fe_index <= dof_handler->get_fe().size(), ExcInternalError()); - - switch (status) - { - case parallel::distributed::Triangulation::CELL_PERSIST: - case parallel::distributed::Triangulation::CELL_COARSEN: - cell->set_active_fe_index(fe_index); - break; - - case parallel::distributed::Triangulation::CELL_REFINE: - // In this case, the callback function will be called on the parent - // cell which stores the packed information. We need to distribute - // it on its children. - for (unsigned int child_index = 0; - child_index < GeometryInfo::max_children_per_cell; - ++child_index) - cell->child(child_index)->set_active_fe_index(fe_index); - break; - - default: - Assert(false, ExcInternalError()); - break; - } - } - } // namespace distributed -} // namespace parallel - - -// explicit instantiations -# include "active_fe_indices_transfer.inst" - -DEAL_II_NAMESPACE_CLOSE - -#endif diff --git a/source/distributed/active_fe_indices_transfer.inst.in b/source/distributed/active_fe_indices_transfer.inst.in deleted file mode 100644 index 4e91a9b682a1..000000000000 --- a/source/distributed/active_fe_indices_transfer.inst.in +++ /dev/null @@ -1,30 +0,0 @@ -// --------------------------------------------------------------------- -// -// 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. -// -// --------------------------------------------------------------------- - - - -for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) - { - namespace parallel - \{ - namespace distributed - \{ -#if deal_II_dimension <= deal_II_space_dimension - template class ActiveFEIndicesTransfer; -#endif - \} - \} - } diff --git a/source/hp/dof_handler.cc b/source/hp/dof_handler.cc index c7b5011f89d1..01900459d885 100644 --- a/source/hp/dof_handler.cc +++ b/source/hp/dof_handler.cc @@ -238,6 +238,7 @@ namespace internal } + /** * Do that part of reserving space that pertains to cells, * since this is the same in all space dimensions. @@ -652,6 +653,7 @@ namespace internal } + /** * Reserve enough space in the levels[] objects to * store the numbers of the degrees of freedom needed for the @@ -825,6 +827,7 @@ namespace internal } + /** * Implement the function of same name in the mother class. */ @@ -905,6 +908,7 @@ namespace internal } + template static unsigned int max_couplings_between_dofs(const DoFHandler<3, spacedim> &dof_handler) @@ -938,6 +942,7 @@ namespace internal } + /** * Given a hp::DoFHandler object, make sure that the active_fe_indices * that a user has set for locally owned cells are communicated to all @@ -1037,6 +1042,7 @@ namespace internal } // namespace internal + namespace hp { template @@ -1057,6 +1063,7 @@ namespace hp {} + template DoFHandler::DoFHandler( const Triangulation &tria) @@ -1069,6 +1076,7 @@ namespace hp } + template DoFHandler::~DoFHandler() { @@ -1086,8 +1094,10 @@ namespace hp } + /*------------------------ Cell iterator functions ------------------------*/ + template typename DoFHandler::cell_iterator DoFHandler::begin(const unsigned int level) const @@ -1121,6 +1131,7 @@ namespace hp } + template typename DoFHandler::cell_iterator DoFHandler::end(const unsigned int level) const @@ -1131,6 +1142,7 @@ namespace hp } + template typename DoFHandler::active_cell_iterator DoFHandler::end_active(const unsigned int level) const @@ -1151,6 +1163,7 @@ namespace hp } + template IteratorRange::active_cell_iterator> DoFHandler::active_cell_iterators() const @@ -1329,10 +1342,9 @@ namespace hp // protected data of this object, but for simplicity we use the // cell-wise access. this way we also have to pass some debug-mode // tests which we would have to duplicate ourselves otherwise - active_cell_iterator cell = begin_active(), endc = end(); - for (unsigned int i = 0; cell != endc; ++cell, ++i) + for (const auto &cell : active_cell_iterators()) if (cell->is_locally_owned()) - cell->set_active_fe_index(active_fe_indices[i]); + cell->set_active_fe_index(active_fe_indices[cell->active_cell_index()]); } @@ -1347,11 +1359,13 @@ namespace hp // we could try to extract the values directly, since they are // stored as protected data of this object, but for simplicity we // use the cell-wise access. - active_cell_iterator cell = begin_active(), endc = end(); - for (unsigned int i = 0; cell != endc; ++cell, ++i) - active_fe_indices[i] = cell->active_fe_index(); + for (const auto &cell : active_cell_iterators()) + if (cell->is_locally_owned()) + active_fe_indices[cell->active_cell_index()] = cell->active_fe_index(); } + + template void DoFHandler::initialize( @@ -1375,6 +1389,7 @@ namespace hp } + template void DoFHandler::distribute_dofs( @@ -1490,29 +1505,12 @@ namespace hp } + template void DoFHandler::setup_policy_and_listeners() { - // decide whether we need a sequential or a parallel shared/distributed - // policy - if (dynamic_cast *>( - &*this->tria) != nullptr) - policy = - std_cxx14::make_unique>>( - *this); - else if (dynamic_cast< - const parallel::distributed::Triangulation *>( - &*this->tria) != nullptr) - policy = std_cxx14::make_unique< - internal::DoFHandlerImplementation::Policy::ParallelDistributed< - DoFHandler>>(*this); - else - policy = - std_cxx14::make_unique>>(*this); - + // connect functions to signals of the underlying triangulation tria_listeners.push_back(this->tria->signals.pre_refinement.connect( std::bind(&DoFHandler::pre_refinement_action, std::ref(*this)))); @@ -1522,22 +1520,77 @@ namespace hp tria_listeners.push_back(this->tria->signals.create.connect(std::bind( &DoFHandler::post_refinement_action, std::ref(*this)))); - // Only connect the update of active fe indices if we are not using a - // p::d::Triangulation. In this case, the class ActiveFEIndicesTransfer - // has to be consulted. - if (dynamic_cast - *>(&*this->tria) == nullptr) + // decide whether we need a sequential or a parallel shared/distributed + // policy and attach corresponding callback functions dealing with the + // transfer of active_fe_indices + if (const auto *distributed_tria = dynamic_cast< + const parallel::distributed::Triangulation *>( + &this->get_triangulation())) { + policy = std_cxx14::make_unique< + internal::DoFHandlerImplementation::Policy::ParallelDistributed< + DoFHandler>>(*this); + +#ifdef DEAL_II_WITH_P4EST + cell_data_transfer = std_cxx14::make_unique< + parallel::distributed:: + CellDataTransfer>>( + *distributed_tria, + /*transfer_variable_size_data=*/false, + ¶llel::distributed::CellDataTransfer< + dim, + spacedim, + std::vector>::CoarseningStrategies::check_equality); +#endif + + tria_listeners.push_back( + distributed_tria->signals.pre_distributed_refinement.connect( + std::bind( + &DoFHandler::pre_distributed_active_fe_index_transfer, + std::ref(*this)))); + tria_listeners.push_back( + distributed_tria->signals.post_distributed_refinement.connect( + std::bind( + &DoFHandler::post_distributed_active_fe_index_transfer, + std::ref(*this)))); + } + else if (dynamic_cast + *>(&this->get_triangulation()) != nullptr) + { + policy = + std_cxx14::make_unique>>( + *this); + + tria_listeners.push_back( + this->tria->signals.pre_refinement.connect(std::bind( + &DoFHandler::pre_shared_active_fe_index_transfer, + std::ref(*this)))); + tria_listeners.push_back( + this->tria->signals.post_refinement.connect(std::bind( + &DoFHandler::post_shared_active_fe_index_transfer, + std::ref(*this)))); + } + else + { + policy = + std_cxx14::make_unique>>( + *this); + tria_listeners.push_back(this->tria->signals.pre_refinement.connect( - std::bind(&DoFHandler::pre_refinement_fe_index_update, + std::bind(&DoFHandler::pre_active_fe_index_transfer, std::ref(*this)))); tria_listeners.push_back(this->tria->signals.post_refinement.connect( - std::bind(&DoFHandler::post_refinement_fe_index_update, + std::bind(&DoFHandler::post_active_fe_index_transfer, std::ref(*this)))); } } + template void DoFHandler::clear() @@ -1695,6 +1748,7 @@ namespace hp } + template void DoFHandler::pre_refinement_action() @@ -1703,6 +1757,7 @@ namespace hp } + template void DoFHandler::post_refinement_action() @@ -1727,9 +1782,10 @@ namespace hp } + template void - DoFHandler::pre_refinement_fe_index_update() + DoFHandler::pre_active_fe_index_transfer() { // Finite elements need to be assigned to each cell by calling // distribute_dofs() first to make this functionality available. @@ -1738,6 +1794,74 @@ namespace hp Assert(refined_cells_fe_index.empty(), ExcInternalError()); Assert(coarsened_cells_fe_index.empty(), ExcInternalError()); + // Store active_fe_index information for all cells that will be + // affected by refinement/coarsening. + for (const auto &cell : active_cell_iterators()) + if (cell->is_locally_owned()) + { + if (cell->refine_flag_set()) + { + // Store the active_fe_index of each cell that will be refined + // to and distribute it later on its children. + refined_cells_fe_index.insert( + {cell, cell->active_fe_index()}); + } + else if (cell->coarsen_flag_set()) + { + // From all cells that will be coarsened, determine their + // parent and calculate its proper active_fe_index, so that it + // can be set after refinement. But first, check if that + // particular cell has a parent at all. + Assert(cell->level() > 0, ExcInternalError()); + const auto &parent = cell->parent(); + // Check if the active_fe_index for the current cell has been + // determined already. + if (coarsened_cells_fe_index.find(parent) == + coarsened_cells_fe_index.end()) + { + std::set fe_indices_children; + for (unsigned int child_index = 0; + child_index < parent->n_children(); + ++child_index) + { + Assert(parent->child(child_index)->active(), + ExcInternalError()); + + fe_indices_children.insert( + parent->child(child_index)->active_fe_index()); + } + + const unsigned int fe_index = + fe_collection.find_least_dominating_fe_in_collection( + fe_indices_children, /*codim=*/0); + + Assert( + fe_index != numbers::invalid_unsigned_int, + ExcMessage( + "No FiniteElement has been found in your FECollection " + "that dominates all children of a cell you are trying " + "to coarsen!")); + + coarsened_cells_fe_index.insert({parent, fe_index}); + } + } + } + } + } + + + + template + void + DoFHandler::pre_shared_active_fe_index_transfer() + { +#ifndef DEAL_II_WITH_MPI + Assert(false, ExcInternalError()); +#else + // Finite elements need to be assigned to each cell by calling + // distribute_dofs() first to make this functionality available. + if (fe_collection.size() > 0) + { // If the underlying shared::Tria allows artificial cells, // then save the current set of subdomain ids, and set // subdomain ids to the "true" owner of each cell. We later @@ -1745,9 +1869,10 @@ namespace hp const parallel::shared::Triangulation *shared_tria = (dynamic_cast *>( &(*tria))); + Assert(shared_tria != nullptr, ExcInternalError()); std::vector saved_subdomain_ids; - if (shared_tria != nullptr && shared_tria->with_artificial_cells()) + if (shared_tria->with_artificial_cells()) { saved_subdomain_ids.resize(shared_tria->n_active_cells()); @@ -1767,54 +1892,11 @@ namespace hp communicate_active_fe_indices(*this); } - // Store active_fe_index information for all cells that will be - // affected by refinement/coarsening. - for (const auto &cell : active_cell_iterators()) - { - if (cell->refine_flag_set()) - { - // Store the active_fe_index of each cell that will be refined - // to and distribute it later on its children. - refined_cells_fe_index.insert({cell, cell->active_fe_index()}); - } - else if (cell->coarsen_flag_set()) - { - // From all cells that will be coarsened, determine their parent - // and calculate its proper active_fe_index, so that it can be - // set after refinement. - // But first, check if that particular cell has a parent at all. - Assert(cell->level() > 0, ExcInternalError()); - const auto &parent = cell->parent(); - // Check if the active_fe_index for the current cell has been - // determined already. - if (coarsened_cells_fe_index.find(parent) == - coarsened_cells_fe_index.end()) - { - std::set fe_indices_children; - for (unsigned int child_index = 0; - child_index < parent->n_children(); - ++child_index) - fe_indices_children.insert( - parent->child(child_index)->active_fe_index()); - - const unsigned int fe_index = - fe_collection.find_least_dominating_fe_in_collection( - fe_indices_children, /*codim=*/0); - - Assert( - fe_index != numbers::invalid_unsigned_int, - ExcMessage( - "No FiniteElement has been found in your FECollection " - "that dominates all children of a cell you are trying " - "to coarsen!")); - - coarsened_cells_fe_index.insert({parent, fe_index}); - } - } - } + // Now do what we would do in the sequential case. + pre_active_fe_index_transfer(); // Finally, restore current subdomain_ids. - if (shared_tria != nullptr && shared_tria->with_artificial_cells()) + if (shared_tria->with_artificial_cells()) for (const auto &cell : active_cell_iterators()) { if (cell->is_artificial()) @@ -1824,17 +1906,69 @@ namespace hp saved_subdomain_ids[cell->active_cell_index()]); } } +#endif } + template void - DoFHandler::post_refinement_fe_index_update() + DoFHandler::pre_distributed_active_fe_index_transfer() { +#ifndef DEAL_II_WITH_P4EST + Assert(false, ExcInternalError()); +#else // Finite elements need to be assigned to each cell by calling // distribute_dofs() first to make this functionality available. if (fe_collection.size() > 0) { + // First, do what we would do in the sequential case. + pre_active_fe_index_transfer(); + + // If we work on a p::d::Triangulation, we have to transfer all + // active_fe_indices since ownership of cells may change. We will + // use our p::d::CellDataTransfer member to achieve this. Further, + // we prepare the values in such a way that they will correspond to + // the active_fe_indices on the new mesh. + + // Gather all current active_fe_indices. + get_active_fe_indices(active_fe_indices); + + // Overwrite values of cells that will be coarsened with the + // active_fe_index determined beforehand for their parent. + for (const auto &pair : coarsened_cells_fe_index) + for (unsigned int child_index = 0; + child_index < pair.first->n_children(); + ++child_index) + active_fe_indices[pair.first->child(child_index) + ->active_cell_index()] = pair.second; + + // Attach to transfer object. + cell_data_transfer->prepare_for_coarsening_and_refinement( + active_fe_indices); + + // Free some memory. + refined_cells_fe_index.clear(); + coarsened_cells_fe_index.clear(); + } +#endif + } + + + + template + void + DoFHandler::post_active_fe_index_transfer() + { + // Finite elements need to be assigned to each cell by calling + // distribute_dofs() first to make this functionality available. + if (fe_collection.size() > 0) + { + // For Triangulation and p::s::Triangulation, the old cell iterators + // are still valid. There is no need to transfer data in this case, + // and we can re-use our previously gathered information from the + // container. + // Distribute active_fe_indices from all refined cells on their // respective children. for (const auto &pair : refined_cells_fe_index) @@ -1868,19 +2002,140 @@ namespace hp } } + // Clear stored active_fe_indices. + refined_cells_fe_index.clear(); + coarsened_cells_fe_index.clear(); + } + } + + + + template + void + DoFHandler::post_shared_active_fe_index_transfer() + { +#ifndef DEAL_II_WITH_MPI + Assert(false, ExcInternalError()); +#else + // Finite elements need to be assigned to each cell by calling + // distribute_dofs() first to make this functionality available. + if (fe_collection.size() > 0) + { + // Do what we normally do in the sequential case. + post_active_fe_index_transfer(); + // We have to distribute the information about active_fe_indices // on all processors, if a parallel::shared::Triangulation // has been used. dealii::internal::hp::DoFHandlerImplementation::Implementation:: communicate_active_fe_indices(*this); + } +#endif + } - // Clear stored active_fe_indices. - refined_cells_fe_index.clear(); - coarsened_cells_fe_index.clear(); + + + template + void + DoFHandler::post_distributed_active_fe_index_transfer() + { +#ifndef DEAL_II_WITH_P4EST + Assert(false, ExcInternalError()); +#else + // Finite elements need to be assigned to each cell by calling + // distribute_dofs() first to make this functionality available. + if (fe_collection.size() > 0) + { + // Unpack active_fe_indices. + active_fe_indices.resize(tria->n_active_cells(), + numbers::invalid_unsigned_int); + cell_data_transfer->unpack(active_fe_indices); + + // Update all locally owned active_fe_indices. + set_active_fe_indices(active_fe_indices); + + // Free some memory. + active_fe_indices.clear(); + active_fe_indices.shrink_to_fit(); } +#endif + } + + + + template + void + DoFHandler::prepare_for_serialization_of_active_fe_indices() + { +#ifndef DEAL_II_WITH_P4EST + Assert(false, + ExcMessage( + "You are attempting to use a functionality that is only available " + "if deal.II was configured to use p4est, but cmake did not find a " + "valid p4est library.")); +#else + Assert( + (dynamic_cast + *>(&this->get_triangulation()) != nullptr), + ExcMessage( + "This functionality requires a parallel::distributed::Triangulation object.")); + + // Finite elements need to be assigned to each cell by calling + // distribute_dofs() first to make this functionality available. + if (fe_collection.size() > 0) + { + // If we work on a p::d::Triangulation, we have to transfer all + // active fe indices since ownership of cells may change. + + // Gather all current active_fe_indices + get_active_fe_indices(active_fe_indices); + + // Attach to transfer object + cell_data_transfer->prepare_for_serialization(active_fe_indices); + } +#endif + } + + + + template + void + DoFHandler::deserialize_active_fe_indices() + { +#ifndef DEAL_II_WITH_P4EST + Assert(false, + ExcMessage( + "You are attempting to use a functionality that is only available " + "if deal.II was configured to use p4est, but cmake did not find a " + "valid p4est library.")); +#else + Assert( + (dynamic_cast + *>(&this->get_triangulation()) != nullptr), + ExcMessage( + "This functionality requires a parallel::distributed::Triangulation object.")); + + // Finite elements need to be assigned to each cell by calling + // distribute_dofs() first to make this functionality available. + if (fe_collection.size() > 0) + { + // Unpack active_fe_indices. + active_fe_indices.resize(tria->n_active_cells(), + numbers::invalid_unsigned_int); + cell_data_transfer->deserialize(active_fe_indices); + + // Update all locally owned active_fe_indices. + set_active_fe_indices(active_fe_indices); + + // Free some memory. + active_fe_indices.clear(); + active_fe_indices.shrink_to_fit(); + } +#endif } + template template types::global_dof_index @@ -1894,6 +2149,7 @@ namespace hp } + template template void @@ -1907,6 +2163,7 @@ namespace hp } + template void DoFHandler::clear_space() diff --git a/tests/mpi/hp_active_fe_indices_transfer_01.cc b/tests/mpi/hp_active_fe_indices_transfer_01.cc index 4e0266a1b9a6..2d5cb00ab231 100644 --- a/tests/mpi/hp_active_fe_indices_transfer_01.cc +++ b/tests/mpi/hp_active_fe_indices_transfer_01.cc @@ -15,10 +15,9 @@ -// ActiveFEIndicesTransfer Test +// active fe indices transfer on refinement -#include #include #include @@ -51,65 +50,54 @@ test() for (unsigned int i = 0; i < max_degree; ++i) fe_collection.push_back(FE_Q(max_degree - i)); - typename hp::DoFHandler::active_cell_iterator cell; - unsigned int i = 0; - - for (cell = dh.begin_active(); cell != dh.end(); ++cell) - { - if (cell->is_locally_owned()) - { - // set active fe index - if (!(cell->is_artificial())) - { - if (i >= fe_collection.size()) - i = 0; - cell->set_active_fe_index(i++); - } - - // set refinement/coarsening flags - if (cell->id().to_string() == "0_1:0") - cell->set_refine_flag(); - else if (cell->parent()->id().to_string() == - ((dim == 2) ? "3_0:" : "7_0:")) - cell->set_coarsen_flag(); - - deallog << "myid=" << myid << " cellid=" << cell->id() - << " fe_index=" << cell->active_fe_index() - << " feq_degree=" << max_degree - cell->active_fe_index(); - if (cell->coarsen_flag_set()) - deallog << " coarsening"; - else if (cell->refine_flag_set()) - deallog << " refining"; - deallog << std::endl; - } - } - + // this distribute_dofs() call is necessary + // we need to introduce dof_handler to its fe_collection first dh.distribute_dofs(fe_collection); - // ----- transfer ----- - parallel::distributed::ActiveFEIndicesTransfer feidx_transfer(dh); + unsigned int i = 0; + for (auto &cell : dh.active_cell_iterators()) + if (cell->is_locally_owned()) + { + // set active fe index + if (!(cell->is_artificial())) + { + if (i >= fe_collection.size()) + i = 0; + cell->set_active_fe_index(i++); + } + + // set refinement/coarsening flags + if (cell->id().to_string() == "0_1:0") + cell->set_refine_flag(); + else if (cell->parent()->id().to_string() == + ((dim == 2) ? "3_0:" : "7_0:")) + cell->set_coarsen_flag(); + + deallog << "myid=" << myid << " cellid=" << cell->id() + << " fe_index=" << cell->active_fe_index() + << " feq_degree=" << max_degree - cell->active_fe_index(); + if (cell->coarsen_flag_set()) + deallog << " coarsening"; + else if (cell->refine_flag_set()) + deallog << " refining"; + deallog << std::endl; + } - feidx_transfer.prepare_for_transfer(); + // ----- transfer ----- tria.execute_coarsening_and_refinement(); deallog << "cells after: " << tria.n_global_active_cells() << std::endl; - feidx_transfer.unpack(); - - // for further calculations, distribute dofs after unpacking, i.e. - // dh.distribute_dofs(fe_collection); - // ------ verify ------ // check if all children adopted the correct id - for (cell = dh.begin_active(); cell != dh.end(); ++cell) - { - if (cell->is_locally_owned()) - { - deallog << "myid=" << myid << " cellid=" << cell->id() - << " fe_index=" << cell->active_fe_index() - << " feq_degree=" << max_degree - cell->active_fe_index() - << std::endl; - } - } + for (auto &cell : dh.active_cell_iterators()) + if (cell->is_locally_owned()) + deallog << "myid=" << myid << " cellid=" << cell->id() + << " fe_index=" << cell->active_fe_index() + << " feq_degree=" << max_degree - cell->active_fe_index() + << std::endl; + + // for further calculations, distribute dofs, i.e. + // dh.distribute_dofs(fe_collection); // make sure no processor is hanging MPI_Barrier(MPI_COMM_WORLD); diff --git a/tests/mpi/hp_active_fe_indices_transfer_02.cc b/tests/mpi/hp_active_fe_indices_transfer_02.cc new file mode 100644 index 000000000000..65393457401e --- /dev/null +++ b/tests/mpi/hp_active_fe_indices_transfer_02.cc @@ -0,0 +1,127 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + + +// active fe indices transfer on serialization + + +#include + +#include + +#include + +#include + +#include "../tests.h" + + +template +void +test() +{ + const unsigned int max_degree = 1 + Utilities::pow(2, dim); + + // prepare FECollection with arbitrary number of entries + hp::FECollection fe_collection; + for (unsigned int i = 0; i < max_degree; ++i) + fe_collection.push_back(FE_Q(max_degree - i)); + + { + deallog << "writing" << std::endl; + + // ------ setup ------ + parallel::distributed::Triangulation tria(MPI_COMM_WORLD); + GridGenerator::subdivided_hyper_cube(tria, 2); + tria.refine_global(1); + + // this distribute_dofs() call is necessary + // we need to introduce dof_handler to its fe_collection first + hp::DoFHandler dh(tria); + dh.distribute_dofs(fe_collection); + + unsigned int i = 0; + for (auto &cell : dh.active_cell_iterators()) + if (cell->is_locally_owned()) + { + // set active fe index + if (!(cell->is_artificial())) + { + if (i >= fe_collection.size()) + i = 0; + cell->set_active_fe_index(i++); + } + + deallog << "cellid=" << cell->id() + << " fe_index=" << cell->active_fe_index() << std::endl; + } + + // ----- transfer ----- + dh.prepare_for_serialization_of_active_fe_indices(); + tria.save("file"); + + // make sure no processor is hanging + MPI_Barrier(MPI_COMM_WORLD); + } + + { + deallog << "reading" << std::endl; + + // ------ setup ------ + parallel::distributed::Triangulation tria(MPI_COMM_WORLD); + GridGenerator::subdivided_hyper_cube(tria, 2); + // triangulation has to be initialized with correct coarse cells + + // this distribute_dofs() call is necessary + // we need to introduce dof_handler to its fe_collection first + hp::DoFHandler dh(tria); + dh.distribute_dofs(fe_collection); + + // ----- transfer ----- + tria.load("file"); + dh.deserialize_active_fe_indices(); + + // ------ verify ------ + // check if all children adopted the correct id + for (auto &cell : dh.active_cell_iterators()) + if (cell->is_locally_owned()) + deallog << "cellid=" << cell->id() + << " fe_index=" << cell->active_fe_index() << std::endl; + + // distribute dofs again for further calculations, i.e. + // dh.distribute_dofs(fe_collection); + + // make sure no processor is hanging + MPI_Barrier(MPI_COMM_WORLD); + } + + deallog << "OK" << std::endl; +} + + +int +main(int argc, char *argv[]) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + MPILogInitAll log; + + deallog.push("2d"); + test<2>(); + deallog.pop(); + deallog.push("3d"); + test<3>(); + deallog.pop(); +} diff --git a/tests/mpi/hp_active_fe_indices_transfer_02.with_p4est=true.mpirun=2.output b/tests/mpi/hp_active_fe_indices_transfer_02.with_p4est=true.mpirun=2.output new file mode 100644 index 000000000000..a9f6eeb1ba56 --- /dev/null +++ b/tests/mpi/hp_active_fe_indices_transfer_02.with_p4est=true.mpirun=2.output @@ -0,0 +1,175 @@ + +DEAL:0:2d::writing +DEAL:0:2d::cellid=0_1:0 fe_index=0 +DEAL:0:2d::cellid=0_1:1 fe_index=1 +DEAL:0:2d::cellid=0_1:2 fe_index=2 +DEAL:0:2d::cellid=0_1:3 fe_index=3 +DEAL:0:2d::cellid=1_1:0 fe_index=4 +DEAL:0:2d::cellid=1_1:1 fe_index=0 +DEAL:0:2d::cellid=1_1:2 fe_index=1 +DEAL:0:2d::cellid=1_1:3 fe_index=2 +DEAL:0:2d::reading +DEAL:0:2d::cellid=0_1:0 fe_index=0 +DEAL:0:2d::cellid=0_1:1 fe_index=1 +DEAL:0:2d::cellid=0_1:2 fe_index=2 +DEAL:0:2d::cellid=0_1:3 fe_index=3 +DEAL:0:2d::cellid=1_1:0 fe_index=4 +DEAL:0:2d::cellid=1_1:1 fe_index=0 +DEAL:0:2d::cellid=1_1:2 fe_index=1 +DEAL:0:2d::cellid=1_1:3 fe_index=2 +DEAL:0:2d::OK +DEAL:0:3d::writing +DEAL:0:3d::cellid=0_1:0 fe_index=0 +DEAL:0:3d::cellid=0_1:1 fe_index=1 +DEAL:0:3d::cellid=0_1:2 fe_index=2 +DEAL:0:3d::cellid=0_1:3 fe_index=3 +DEAL:0:3d::cellid=0_1:4 fe_index=4 +DEAL:0:3d::cellid=0_1:5 fe_index=5 +DEAL:0:3d::cellid=0_1:6 fe_index=6 +DEAL:0:3d::cellid=0_1:7 fe_index=7 +DEAL:0:3d::cellid=1_1:0 fe_index=8 +DEAL:0:3d::cellid=1_1:1 fe_index=0 +DEAL:0:3d::cellid=1_1:2 fe_index=1 +DEAL:0:3d::cellid=1_1:3 fe_index=2 +DEAL:0:3d::cellid=1_1:4 fe_index=3 +DEAL:0:3d::cellid=1_1:5 fe_index=4 +DEAL:0:3d::cellid=1_1:6 fe_index=5 +DEAL:0:3d::cellid=1_1:7 fe_index=6 +DEAL:0:3d::cellid=2_1:0 fe_index=7 +DEAL:0:3d::cellid=2_1:1 fe_index=8 +DEAL:0:3d::cellid=2_1:2 fe_index=0 +DEAL:0:3d::cellid=2_1:3 fe_index=1 +DEAL:0:3d::cellid=2_1:4 fe_index=2 +DEAL:0:3d::cellid=2_1:5 fe_index=3 +DEAL:0:3d::cellid=2_1:6 fe_index=4 +DEAL:0:3d::cellid=2_1:7 fe_index=5 +DEAL:0:3d::cellid=3_1:0 fe_index=6 +DEAL:0:3d::cellid=3_1:1 fe_index=7 +DEAL:0:3d::cellid=3_1:2 fe_index=8 +DEAL:0:3d::cellid=3_1:3 fe_index=0 +DEAL:0:3d::cellid=3_1:4 fe_index=1 +DEAL:0:3d::cellid=3_1:5 fe_index=2 +DEAL:0:3d::cellid=3_1:6 fe_index=3 +DEAL:0:3d::cellid=3_1:7 fe_index=4 +DEAL:0:3d::reading +DEAL:0:3d::cellid=0_1:0 fe_index=0 +DEAL:0:3d::cellid=0_1:1 fe_index=1 +DEAL:0:3d::cellid=0_1:2 fe_index=2 +DEAL:0:3d::cellid=0_1:3 fe_index=3 +DEAL:0:3d::cellid=0_1:4 fe_index=4 +DEAL:0:3d::cellid=0_1:5 fe_index=5 +DEAL:0:3d::cellid=0_1:6 fe_index=6 +DEAL:0:3d::cellid=0_1:7 fe_index=7 +DEAL:0:3d::cellid=1_1:0 fe_index=8 +DEAL:0:3d::cellid=1_1:1 fe_index=0 +DEAL:0:3d::cellid=1_1:2 fe_index=1 +DEAL:0:3d::cellid=1_1:3 fe_index=2 +DEAL:0:3d::cellid=1_1:4 fe_index=3 +DEAL:0:3d::cellid=1_1:5 fe_index=4 +DEAL:0:3d::cellid=1_1:6 fe_index=5 +DEAL:0:3d::cellid=1_1:7 fe_index=6 +DEAL:0:3d::cellid=2_1:0 fe_index=7 +DEAL:0:3d::cellid=2_1:1 fe_index=8 +DEAL:0:3d::cellid=2_1:2 fe_index=0 +DEAL:0:3d::cellid=2_1:3 fe_index=1 +DEAL:0:3d::cellid=2_1:4 fe_index=2 +DEAL:0:3d::cellid=2_1:5 fe_index=3 +DEAL:0:3d::cellid=2_1:6 fe_index=4 +DEAL:0:3d::cellid=2_1:7 fe_index=5 +DEAL:0:3d::cellid=3_1:0 fe_index=6 +DEAL:0:3d::cellid=3_1:1 fe_index=7 +DEAL:0:3d::cellid=3_1:2 fe_index=8 +DEAL:0:3d::cellid=3_1:3 fe_index=0 +DEAL:0:3d::cellid=3_1:4 fe_index=1 +DEAL:0:3d::cellid=3_1:5 fe_index=2 +DEAL:0:3d::cellid=3_1:6 fe_index=3 +DEAL:0:3d::cellid=3_1:7 fe_index=4 +DEAL:0:3d::OK + +DEAL:1:2d::writing +DEAL:1:2d::cellid=2_1:0 fe_index=0 +DEAL:1:2d::cellid=2_1:1 fe_index=1 +DEAL:1:2d::cellid=2_1:2 fe_index=2 +DEAL:1:2d::cellid=2_1:3 fe_index=3 +DEAL:1:2d::cellid=3_1:0 fe_index=4 +DEAL:1:2d::cellid=3_1:1 fe_index=0 +DEAL:1:2d::cellid=3_1:2 fe_index=1 +DEAL:1:2d::cellid=3_1:3 fe_index=2 +DEAL:1:2d::reading +DEAL:1:2d::cellid=2_1:0 fe_index=0 +DEAL:1:2d::cellid=2_1:1 fe_index=1 +DEAL:1:2d::cellid=2_1:2 fe_index=2 +DEAL:1:2d::cellid=2_1:3 fe_index=3 +DEAL:1:2d::cellid=3_1:0 fe_index=4 +DEAL:1:2d::cellid=3_1:1 fe_index=0 +DEAL:1:2d::cellid=3_1:2 fe_index=1 +DEAL:1:2d::cellid=3_1:3 fe_index=2 +DEAL:1:2d::OK +DEAL:1:3d::writing +DEAL:1:3d::cellid=4_1:0 fe_index=0 +DEAL:1:3d::cellid=4_1:1 fe_index=1 +DEAL:1:3d::cellid=4_1:2 fe_index=2 +DEAL:1:3d::cellid=4_1:3 fe_index=3 +DEAL:1:3d::cellid=4_1:4 fe_index=4 +DEAL:1:3d::cellid=4_1:5 fe_index=5 +DEAL:1:3d::cellid=4_1:6 fe_index=6 +DEAL:1:3d::cellid=4_1:7 fe_index=7 +DEAL:1:3d::cellid=5_1:0 fe_index=8 +DEAL:1:3d::cellid=5_1:1 fe_index=0 +DEAL:1:3d::cellid=5_1:2 fe_index=1 +DEAL:1:3d::cellid=5_1:3 fe_index=2 +DEAL:1:3d::cellid=5_1:4 fe_index=3 +DEAL:1:3d::cellid=5_1:5 fe_index=4 +DEAL:1:3d::cellid=5_1:6 fe_index=5 +DEAL:1:3d::cellid=5_1:7 fe_index=6 +DEAL:1:3d::cellid=6_1:0 fe_index=7 +DEAL:1:3d::cellid=6_1:1 fe_index=8 +DEAL:1:3d::cellid=6_1:2 fe_index=0 +DEAL:1:3d::cellid=6_1:3 fe_index=1 +DEAL:1:3d::cellid=6_1:4 fe_index=2 +DEAL:1:3d::cellid=6_1:5 fe_index=3 +DEAL:1:3d::cellid=6_1:6 fe_index=4 +DEAL:1:3d::cellid=6_1:7 fe_index=5 +DEAL:1:3d::cellid=7_1:0 fe_index=6 +DEAL:1:3d::cellid=7_1:1 fe_index=7 +DEAL:1:3d::cellid=7_1:2 fe_index=8 +DEAL:1:3d::cellid=7_1:3 fe_index=0 +DEAL:1:3d::cellid=7_1:4 fe_index=1 +DEAL:1:3d::cellid=7_1:5 fe_index=2 +DEAL:1:3d::cellid=7_1:6 fe_index=3 +DEAL:1:3d::cellid=7_1:7 fe_index=4 +DEAL:1:3d::reading +DEAL:1:3d::cellid=4_1:0 fe_index=0 +DEAL:1:3d::cellid=4_1:1 fe_index=1 +DEAL:1:3d::cellid=4_1:2 fe_index=2 +DEAL:1:3d::cellid=4_1:3 fe_index=3 +DEAL:1:3d::cellid=4_1:4 fe_index=4 +DEAL:1:3d::cellid=4_1:5 fe_index=5 +DEAL:1:3d::cellid=4_1:6 fe_index=6 +DEAL:1:3d::cellid=4_1:7 fe_index=7 +DEAL:1:3d::cellid=5_1:0 fe_index=8 +DEAL:1:3d::cellid=5_1:1 fe_index=0 +DEAL:1:3d::cellid=5_1:2 fe_index=1 +DEAL:1:3d::cellid=5_1:3 fe_index=2 +DEAL:1:3d::cellid=5_1:4 fe_index=3 +DEAL:1:3d::cellid=5_1:5 fe_index=4 +DEAL:1:3d::cellid=5_1:6 fe_index=5 +DEAL:1:3d::cellid=5_1:7 fe_index=6 +DEAL:1:3d::cellid=6_1:0 fe_index=7 +DEAL:1:3d::cellid=6_1:1 fe_index=8 +DEAL:1:3d::cellid=6_1:2 fe_index=0 +DEAL:1:3d::cellid=6_1:3 fe_index=1 +DEAL:1:3d::cellid=6_1:4 fe_index=2 +DEAL:1:3d::cellid=6_1:5 fe_index=3 +DEAL:1:3d::cellid=6_1:6 fe_index=4 +DEAL:1:3d::cellid=6_1:7 fe_index=5 +DEAL:1:3d::cellid=7_1:0 fe_index=6 +DEAL:1:3d::cellid=7_1:1 fe_index=7 +DEAL:1:3d::cellid=7_1:2 fe_index=8 +DEAL:1:3d::cellid=7_1:3 fe_index=0 +DEAL:1:3d::cellid=7_1:4 fe_index=1 +DEAL:1:3d::cellid=7_1:5 fe_index=2 +DEAL:1:3d::cellid=7_1:6 fe_index=3 +DEAL:1:3d::cellid=7_1:7 fe_index=4 +DEAL:1:3d::OK + diff --git a/tests/mpi/hp_active_fe_indices_transfer_02.with_p4est=true.mpirun=8.output b/tests/mpi/hp_active_fe_indices_transfer_02.with_p4est=true.mpirun=8.output new file mode 100644 index 000000000000..883234fd1c5e --- /dev/null +++ b/tests/mpi/hp_active_fe_indices_transfer_02.with_p4est=true.mpirun=8.output @@ -0,0 +1,223 @@ + +DEAL:0:2d::writing +DEAL:0:2d::cellid=0_1:0 fe_index=0 +DEAL:0:2d::cellid=0_1:1 fe_index=1 +DEAL:0:2d::cellid=0_1:2 fe_index=2 +DEAL:0:2d::cellid=0_1:3 fe_index=3 +DEAL:0:2d::reading +DEAL:0:2d::cellid=0_1:0 fe_index=0 +DEAL:0:2d::cellid=0_1:1 fe_index=1 +DEAL:0:2d::OK +DEAL:0:3d::writing +DEAL:0:3d::cellid=0_1:0 fe_index=0 +DEAL:0:3d::cellid=0_1:1 fe_index=1 +DEAL:0:3d::cellid=0_1:2 fe_index=2 +DEAL:0:3d::cellid=0_1:3 fe_index=3 +DEAL:0:3d::cellid=0_1:4 fe_index=4 +DEAL:0:3d::cellid=0_1:5 fe_index=5 +DEAL:0:3d::cellid=0_1:6 fe_index=6 +DEAL:0:3d::cellid=0_1:7 fe_index=7 +DEAL:0:3d::reading +DEAL:0:3d::cellid=0_1:0 fe_index=0 +DEAL:0:3d::cellid=0_1:1 fe_index=1 +DEAL:0:3d::cellid=0_1:2 fe_index=2 +DEAL:0:3d::cellid=0_1:3 fe_index=3 +DEAL:0:3d::cellid=0_1:4 fe_index=4 +DEAL:0:3d::cellid=0_1:5 fe_index=5 +DEAL:0:3d::cellid=0_1:6 fe_index=6 +DEAL:0:3d::cellid=0_1:7 fe_index=7 +DEAL:0:3d::OK + +DEAL:1:2d::writing +DEAL:1:2d::reading +DEAL:1:2d::cellid=0_1:2 fe_index=2 +DEAL:1:2d::cellid=0_1:3 fe_index=3 +DEAL:1:2d::OK +DEAL:1:3d::writing +DEAL:1:3d::cellid=1_1:0 fe_index=0 +DEAL:1:3d::cellid=1_1:1 fe_index=1 +DEAL:1:3d::cellid=1_1:2 fe_index=2 +DEAL:1:3d::cellid=1_1:3 fe_index=3 +DEAL:1:3d::cellid=1_1:4 fe_index=4 +DEAL:1:3d::cellid=1_1:5 fe_index=5 +DEAL:1:3d::cellid=1_1:6 fe_index=6 +DEAL:1:3d::cellid=1_1:7 fe_index=7 +DEAL:1:3d::reading +DEAL:1:3d::cellid=1_1:0 fe_index=0 +DEAL:1:3d::cellid=1_1:1 fe_index=1 +DEAL:1:3d::cellid=1_1:2 fe_index=2 +DEAL:1:3d::cellid=1_1:3 fe_index=3 +DEAL:1:3d::cellid=1_1:4 fe_index=4 +DEAL:1:3d::cellid=1_1:5 fe_index=5 +DEAL:1:3d::cellid=1_1:6 fe_index=6 +DEAL:1:3d::cellid=1_1:7 fe_index=7 +DEAL:1:3d::OK + + +DEAL:2:2d::writing +DEAL:2:2d::cellid=1_1:0 fe_index=0 +DEAL:2:2d::cellid=1_1:1 fe_index=1 +DEAL:2:2d::cellid=1_1:2 fe_index=2 +DEAL:2:2d::cellid=1_1:3 fe_index=3 +DEAL:2:2d::reading +DEAL:2:2d::cellid=1_1:0 fe_index=0 +DEAL:2:2d::cellid=1_1:1 fe_index=1 +DEAL:2:2d::OK +DEAL:2:3d::writing +DEAL:2:3d::cellid=2_1:0 fe_index=0 +DEAL:2:3d::cellid=2_1:1 fe_index=1 +DEAL:2:3d::cellid=2_1:2 fe_index=2 +DEAL:2:3d::cellid=2_1:3 fe_index=3 +DEAL:2:3d::cellid=2_1:4 fe_index=4 +DEAL:2:3d::cellid=2_1:5 fe_index=5 +DEAL:2:3d::cellid=2_1:6 fe_index=6 +DEAL:2:3d::cellid=2_1:7 fe_index=7 +DEAL:2:3d::reading +DEAL:2:3d::cellid=2_1:0 fe_index=0 +DEAL:2:3d::cellid=2_1:1 fe_index=1 +DEAL:2:3d::cellid=2_1:2 fe_index=2 +DEAL:2:3d::cellid=2_1:3 fe_index=3 +DEAL:2:3d::cellid=2_1:4 fe_index=4 +DEAL:2:3d::cellid=2_1:5 fe_index=5 +DEAL:2:3d::cellid=2_1:6 fe_index=6 +DEAL:2:3d::cellid=2_1:7 fe_index=7 +DEAL:2:3d::OK + + +DEAL:3:2d::writing +DEAL:3:2d::reading +DEAL:3:2d::cellid=1_1:2 fe_index=2 +DEAL:3:2d::cellid=1_1:3 fe_index=3 +DEAL:3:2d::OK +DEAL:3:3d::writing +DEAL:3:3d::cellid=3_1:0 fe_index=0 +DEAL:3:3d::cellid=3_1:1 fe_index=1 +DEAL:3:3d::cellid=3_1:2 fe_index=2 +DEAL:3:3d::cellid=3_1:3 fe_index=3 +DEAL:3:3d::cellid=3_1:4 fe_index=4 +DEAL:3:3d::cellid=3_1:5 fe_index=5 +DEAL:3:3d::cellid=3_1:6 fe_index=6 +DEAL:3:3d::cellid=3_1:7 fe_index=7 +DEAL:3:3d::reading +DEAL:3:3d::cellid=3_1:0 fe_index=0 +DEAL:3:3d::cellid=3_1:1 fe_index=1 +DEAL:3:3d::cellid=3_1:2 fe_index=2 +DEAL:3:3d::cellid=3_1:3 fe_index=3 +DEAL:3:3d::cellid=3_1:4 fe_index=4 +DEAL:3:3d::cellid=3_1:5 fe_index=5 +DEAL:3:3d::cellid=3_1:6 fe_index=6 +DEAL:3:3d::cellid=3_1:7 fe_index=7 +DEAL:3:3d::OK + + +DEAL:4:2d::writing +DEAL:4:2d::cellid=2_1:0 fe_index=0 +DEAL:4:2d::cellid=2_1:1 fe_index=1 +DEAL:4:2d::cellid=2_1:2 fe_index=2 +DEAL:4:2d::cellid=2_1:3 fe_index=3 +DEAL:4:2d::reading +DEAL:4:2d::cellid=2_1:0 fe_index=0 +DEAL:4:2d::cellid=2_1:1 fe_index=1 +DEAL:4:2d::OK +DEAL:4:3d::writing +DEAL:4:3d::cellid=4_1:0 fe_index=0 +DEAL:4:3d::cellid=4_1:1 fe_index=1 +DEAL:4:3d::cellid=4_1:2 fe_index=2 +DEAL:4:3d::cellid=4_1:3 fe_index=3 +DEAL:4:3d::cellid=4_1:4 fe_index=4 +DEAL:4:3d::cellid=4_1:5 fe_index=5 +DEAL:4:3d::cellid=4_1:6 fe_index=6 +DEAL:4:3d::cellid=4_1:7 fe_index=7 +DEAL:4:3d::reading +DEAL:4:3d::cellid=4_1:0 fe_index=0 +DEAL:4:3d::cellid=4_1:1 fe_index=1 +DEAL:4:3d::cellid=4_1:2 fe_index=2 +DEAL:4:3d::cellid=4_1:3 fe_index=3 +DEAL:4:3d::cellid=4_1:4 fe_index=4 +DEAL:4:3d::cellid=4_1:5 fe_index=5 +DEAL:4:3d::cellid=4_1:6 fe_index=6 +DEAL:4:3d::cellid=4_1:7 fe_index=7 +DEAL:4:3d::OK + + +DEAL:5:2d::writing +DEAL:5:2d::reading +DEAL:5:2d::cellid=2_1:2 fe_index=2 +DEAL:5:2d::cellid=2_1:3 fe_index=3 +DEAL:5:2d::OK +DEAL:5:3d::writing +DEAL:5:3d::cellid=5_1:0 fe_index=0 +DEAL:5:3d::cellid=5_1:1 fe_index=1 +DEAL:5:3d::cellid=5_1:2 fe_index=2 +DEAL:5:3d::cellid=5_1:3 fe_index=3 +DEAL:5:3d::cellid=5_1:4 fe_index=4 +DEAL:5:3d::cellid=5_1:5 fe_index=5 +DEAL:5:3d::cellid=5_1:6 fe_index=6 +DEAL:5:3d::cellid=5_1:7 fe_index=7 +DEAL:5:3d::reading +DEAL:5:3d::cellid=5_1:0 fe_index=0 +DEAL:5:3d::cellid=5_1:1 fe_index=1 +DEAL:5:3d::cellid=5_1:2 fe_index=2 +DEAL:5:3d::cellid=5_1:3 fe_index=3 +DEAL:5:3d::cellid=5_1:4 fe_index=4 +DEAL:5:3d::cellid=5_1:5 fe_index=5 +DEAL:5:3d::cellid=5_1:6 fe_index=6 +DEAL:5:3d::cellid=5_1:7 fe_index=7 +DEAL:5:3d::OK + + +DEAL:6:2d::writing +DEAL:6:2d::cellid=3_1:0 fe_index=0 +DEAL:6:2d::cellid=3_1:1 fe_index=1 +DEAL:6:2d::cellid=3_1:2 fe_index=2 +DEAL:6:2d::cellid=3_1:3 fe_index=3 +DEAL:6:2d::reading +DEAL:6:2d::cellid=3_1:0 fe_index=0 +DEAL:6:2d::cellid=3_1:1 fe_index=1 +DEAL:6:2d::OK +DEAL:6:3d::writing +DEAL:6:3d::cellid=6_1:0 fe_index=0 +DEAL:6:3d::cellid=6_1:1 fe_index=1 +DEAL:6:3d::cellid=6_1:2 fe_index=2 +DEAL:6:3d::cellid=6_1:3 fe_index=3 +DEAL:6:3d::cellid=6_1:4 fe_index=4 +DEAL:6:3d::cellid=6_1:5 fe_index=5 +DEAL:6:3d::cellid=6_1:6 fe_index=6 +DEAL:6:3d::cellid=6_1:7 fe_index=7 +DEAL:6:3d::reading +DEAL:6:3d::cellid=6_1:0 fe_index=0 +DEAL:6:3d::cellid=6_1:1 fe_index=1 +DEAL:6:3d::cellid=6_1:2 fe_index=2 +DEAL:6:3d::cellid=6_1:3 fe_index=3 +DEAL:6:3d::cellid=6_1:4 fe_index=4 +DEAL:6:3d::cellid=6_1:5 fe_index=5 +DEAL:6:3d::cellid=6_1:6 fe_index=6 +DEAL:6:3d::cellid=6_1:7 fe_index=7 +DEAL:6:3d::OK + + +DEAL:7:2d::writing +DEAL:7:2d::reading +DEAL:7:2d::cellid=3_1:2 fe_index=2 +DEAL:7:2d::cellid=3_1:3 fe_index=3 +DEAL:7:2d::OK +DEAL:7:3d::writing +DEAL:7:3d::cellid=7_1:0 fe_index=0 +DEAL:7:3d::cellid=7_1:1 fe_index=1 +DEAL:7:3d::cellid=7_1:2 fe_index=2 +DEAL:7:3d::cellid=7_1:3 fe_index=3 +DEAL:7:3d::cellid=7_1:4 fe_index=4 +DEAL:7:3d::cellid=7_1:5 fe_index=5 +DEAL:7:3d::cellid=7_1:6 fe_index=6 +DEAL:7:3d::cellid=7_1:7 fe_index=7 +DEAL:7:3d::reading +DEAL:7:3d::cellid=7_1:0 fe_index=0 +DEAL:7:3d::cellid=7_1:1 fe_index=1 +DEAL:7:3d::cellid=7_1:2 fe_index=2 +DEAL:7:3d::cellid=7_1:3 fe_index=3 +DEAL:7:3d::cellid=7_1:4 fe_index=4 +DEAL:7:3d::cellid=7_1:5 fe_index=5 +DEAL:7:3d::cellid=7_1:6 fe_index=6 +DEAL:7:3d::cellid=7_1:7 fe_index=7 +DEAL:7:3d::OK + diff --git a/tests/mpi/hp_cell_weights_01.cc b/tests/mpi/hp_cell_weights_01.cc index 838e48cc85f5..6d15d5841b32 100644 --- a/tests/mpi/hp_cell_weights_01.cc +++ b/tests/mpi/hp_cell_weights_01.cc @@ -30,7 +30,6 @@ // This test works on a parallel::distributed::Triangulation. -#include #include #include @@ -66,9 +65,6 @@ test() dh.distribute_dofs(fe_collection); - parallel::distributed::ActiveFEIndicesTransfer feidx_transfer(dh); - feidx_transfer.prepare_for_transfer(); - parallel::CellWeights cell_weights(dh); cell_weights.register_ndofs_weighting(100000); @@ -85,7 +81,6 @@ test() tria.repartition(); - feidx_transfer.unpack(); dh.distribute_dofs(fe_collection); diff --git a/tests/mpi/hp_cell_weights_02.cc b/tests/mpi/hp_cell_weights_02.cc index 52b8a6608007..5d13dff77469 100644 --- a/tests/mpi/hp_cell_weights_02.cc +++ b/tests/mpi/hp_cell_weights_02.cc @@ -36,7 +36,6 @@ // to 'cut' its tree on a parent branch that does not exist in this case. -#include #include #include @@ -72,9 +71,6 @@ test() dh.distribute_dofs(fe_collection); - parallel::distributed::ActiveFEIndicesTransfer feidx_transfer(dh); - feidx_transfer.prepare_for_transfer(); - parallel::CellWeights cell_weights(dh); cell_weights.register_ndofs_weighting(100000); @@ -91,7 +87,6 @@ test() tria.repartition(); - feidx_transfer.unpack(); dh.distribute_dofs(fe_collection); diff --git a/tests/mpi/p4est_save_06.cc b/tests/mpi/p4est_save_06.cc index 446242a45410..5af46a86964b 100644 --- a/tests/mpi/p4est_save_06.cc +++ b/tests/mpi/p4est_save_06.cc @@ -21,7 +21,6 @@ #include #include -#include #include #include @@ -93,8 +92,6 @@ test() locally_relevant_dofs, com_small); - parallel::distributed::ActiveFEIndicesTransfer feidx_transfer( - dh); parallel::distributed:: SolutionTransfer> soltrans(dh); @@ -109,7 +106,7 @@ test() x.compress(VectorOperation::insert); rel_x = x; - feidx_transfer.prepare_for_transfer(); + dh.prepare_for_serialization_of_active_fe_indices(); soltrans.prepare_serialization(rel_x); tr.save("file"); @@ -138,10 +135,7 @@ test() fe_collection.push_back(FE_Q(max_degree - i)); dh.distribute_dofs(fe_collection); - - parallel::distributed::ActiveFEIndicesTransfer feidx_transfer(dh); - feidx_transfer.deserialize(); - + dh.deserialize_active_fe_indices(); dh.distribute_dofs(fe_collection); IndexSet locally_owned_dofs = dh.locally_owned_dofs(); diff --git a/tests/mpi/solution_transfer_04.cc b/tests/mpi/solution_transfer_04.cc index 6edb651b388d..6f81c5cf5f24 100644 --- a/tests/mpi/solution_transfer_04.cc +++ b/tests/mpi/solution_transfer_04.cc @@ -19,7 +19,6 @@ // This tests is based on mpi/feindices_transfer.cc -#include #include #include @@ -101,17 +100,13 @@ test() // ----- transfer ----- - parallel::distributed::ActiveFEIndicesTransfer feidx_transfer(dh); parallel::distributed:: SolutionTransfer> soltrans(dh); - feidx_transfer.prepare_for_transfer(); soltrans.prepare_for_coarsening_and_refinement(old_solution); tria.execute_coarsening_and_refinement(); - feidx_transfer.unpack(); - dh.distribute_dofs(fe_collection); locally_owned_dofs = dh.locally_owned_dofs(); DoFTools::extract_locally_relevant_dofs(dh, locally_relevant_dofs); From 3d6616dff1ed167c2e7669dc2d4da99d0d366465 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Tue, 5 Feb 2019 15:12:52 -0600 Subject: [PATCH 077/507] CMake: error message + guard target - Add a helpful message to make debug/release targets. - Only create the corresponding debug/release target if the build type is available. --- .../macro_deal_ii_invoke_autopilot.cmake | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/cmake/macros/macro_deal_ii_invoke_autopilot.cmake b/cmake/macros/macro_deal_ii_invoke_autopilot.cmake index a494f0a9e8f4..ca5a1c0832a9 100644 --- a/cmake/macros/macro_deal_ii_invoke_autopilot.cmake +++ b/cmake/macros/macro_deal_ii_invoke_autopilot.cmake @@ -138,19 +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} - COMMENT "Switch CMAKE_BUILD_TYPE to Debug" - ) + # - ADD_CUSTOM_TARGET(release - COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR} - 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 "Switch 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 "Switch 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' From f7cd45eeda29d4e503057f1bf96c78f894e53d67 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 30 Jan 2019 21:05:36 +0100 Subject: [PATCH 078/507] Move and fix std::enable_if to a template parameter, fix test --- ...GiovanniAlzettaDanielArndtWolfgangBangerth | 4 ++ include/deal.II/base/point.h | 15 ++++--- tests/base/point_04.cc | 45 ++++++++++++------- tests/base/point_04.output | 4 ++ 4 files changed, 45 insertions(+), 23 deletions(-) create mode 100644 doc/news/changes/minor/20190131GiovanniAlzettaDanielArndtWolfgangBangerth 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/include/deal.II/base/point.h b/include/deal.II/base/point.h index d486ae36c858..093c87eaa3d6 100644 --- a/include/deal.II/base/point.h +++ b/include/deal.II/base/point.h @@ -148,11 +148,11 @@ class Point : public Tensor<1, dim, Number> /** * Convert a boost::geometry::point to a dealii::Point. */ - template + template ::type = 0> Point(const boost::geometry::model:: - point &boost_pt, - typename std::enable_if<(dim == dummy_dim) && (dummy_dim != 0), - int>::type = 0); + point &boost_pt); /** * Return a unit vector in coordinate direction i, i.e., a vector @@ -371,11 +371,12 @@ inline Point::Point(const Number x, const Number y, const Number z) template -template +template < + std::size_t dummy_dim, + typename std::enable_if<(dim == dummy_dim) && (dummy_dim != 0), int>::type> inline Point::Point( const boost::geometry::model:: - point &boost_pt, - typename std::enable_if<(dim == dummy_dim) && (dummy_dim != 0), int>::type) + point &boost_pt) { Assert(dim <= 3, ExcNotImplemented()); this->values[0] = boost::geometry::get<0>(boost_pt); diff --git a/tests/base/point_04.cc b/tests/base/point_04.cc index 7dbb62241b5f..97613ae51f9e 100644 --- a/tests/base/point_04.cc +++ b/tests/base/point_04.cc @@ -26,37 +26,50 @@ namespace bg = boost::geometry; -template void -check() +check3d() { - bg::model::point bg_point; + bg::model::point point(-1.0, + 2.0, + 0.15); - constexpr unsigned int y_index = (spacedim < 2) ? 0 : 1; - constexpr unsigned int z_index = (spacedim < 3) ? 0 : 2; + Point<3> p(point); - bg_point.set<0>(42.0); - - if (dim >= 2) - bg_point.set(42.0 + dim); + for (unsigned int i = 0; i < 3; ++i) + deallog << p(i) << ' '; + deallog << std::endl; +} - if (dim >= 3) - bg_point.set(42.0 + dim + 1); +void +check2d() +{ + bg::model::point point(2.0, 3.0); - Point p(bg_point); + Point<2> p(point); - for (unsigned int i = 0; i < dim; ++i) + for (unsigned int i = 0; i < 2; ++i) deallog << p(i) << ' '; deallog << std::endl; } +void +check1d() +{ + bg::model::point point(12.0); + + Point<1> p(point); + + deallog << p(0) << ' '; + deallog << std::endl; +} + int main() { initlog(); deallog << std::setprecision(3); - check<1>(); - check<2>(); - check<3>(); + check1d(); + check2d(); + check3d(); } diff --git a/tests/base/point_04.output b/tests/base/point_04.output index e69de29bb2d1..199099313332 100644 --- a/tests/base/point_04.output +++ b/tests/base/point_04.output @@ -0,0 +1,4 @@ + +DEAL::12.0 +DEAL::2.00 3.00 +DEAL::-1.00 2.00 0.150 From 7ceedf3bfaed059d4d2e354f839fd9a75c7b0c19 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Fri, 8 Feb 2019 16:28:21 +0100 Subject: [PATCH 079/507] Adjust Chebyshev degree in loop to convention in literature. --- examples/step-37/step-37.cc | 4 +- examples/step-59/step-59.cc | 2 +- include/deal.II/lac/precondition.h | 10 +- tests/lac/precondition_chebyshev_01.cc | 2 +- tests/lac/precondition_chebyshev_02.cc | 2 +- tests/lac/precondition_chebyshev_03.cc | 2 +- tests/lac/precondition_chebyshev_04.cc | 2 +- tests/lac/precondition_chebyshev_05.cc | 2 +- ...h_mpi=true.with_p4est=true.mpirun=1.output | 20 +- ...h_mpi=true.with_p4est=true.mpirun=3.output | 20 +- ...h_mpi=true.with_p4est=true.mpirun=5.output | 20 +- ...h_mpi=true.with_p4est=true.mpirun=1.output | 20 +- ...h_mpi=true.with_p4est=true.mpirun=5.output | 20 +- ...h_mpi=true.with_p4est=true.mpirun=5.output | 20 +- ...inos=true.with_lapack=true.mpirun=3.output | 202 ++++++++++-------- ...inos=true.with_lapack=true.mpirun=7.output | 202 ++++++++++-------- ...inos=true.with_lapack=true.mpirun=3.output | 97 +++++---- ...inos=true.with_lapack=true.mpirun=7.output | 97 +++++---- ...inos=true.with_lapack=true.mpirun=3.output | 14 +- ...inos=true.with_lapack=true.mpirun=7.output | 14 +- ...4est=true.with_lapack=true.mpirun=3.output | 24 +-- ...4est=true.with_lapack=true.mpirun=7.output | 24 +-- ...4est=true.with_lapack=true.mpirun=4.output | 52 ++--- ...4est=true.with_lapack=true.mpirun=7.output | 52 ++--- ...4est=true.with_lapack=true.mpirun=4.output | 8 +- ...4est=true.with_lapack=true.mpirun=7.output | 16 +- ...ogeneous-1.mpirun=4.with_p4est=true.output | 88 ++++---- .../step-37.with_lapack=true.output | 12 +- ...h_mpi=true.with_p4est=true.mpirun=4.output | 6 +- tests/multigrid/step-16-04.cc | 2 +- tests/multigrid/step-16-05.cc | 2 +- tests/multigrid/step-16-06.cc | 2 +- tests/multigrid/step-16-50-serial.cc | 1 + tests/multigrid/step-16-50-serial.output | 20 +- 34 files changed, 567 insertions(+), 514 deletions(-) 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-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/include/deal.II/lac/precondition.h b/include/deal.II/lac/precondition.h index e61138208aa6..be50dd34a702 100644 --- a/include/deal.II/lac/precondition.h +++ b/include/deal.II/lac/precondition.h @@ -2250,13 +2250,16 @@ inline void PreconditionChebyshev:: do_chebyshev_loop(VectorType &dst, const VectorType &src) const { + if (data.degree < 2) + return; + // if delta is zero, we do not need to iterate because the updates will be // zero if (std::abs(delta) < 1e-40) return; double rhok = delta / theta, sigma = theta / delta; - for (unsigned int k = 0; k < data.degree; ++k) + for (unsigned int k = 0; k < data.degree - 1; ++k) { matrix_ptr->vmult(update2, dst); const double rhokp = 1. / (2. * sigma - rhok); @@ -2282,8 +2285,11 @@ inline void PreconditionChebyshev:: do_transpose_chebyshev_loop(VectorType &dst, const VectorType &src) const { + if (data.degree < 2) + return; + double rhok = delta / theta, sigma = theta / delta; - for (unsigned int k = 0; k < data.degree; ++k) + for (unsigned int k = 0; k < data.degree - 1; ++k) { matrix_ptr->Tvmult(update2, dst); const double rhokp = 1. / (2. * sigma - rhok); diff --git a/tests/lac/precondition_chebyshev_01.cc b/tests/lac/precondition_chebyshev_01.cc index 14caa3699b8f..494c61b4c5d4 100644 --- a/tests/lac/precondition_chebyshev_01.cc +++ b/tests/lac/precondition_chebyshev_01.cc @@ -56,7 +56,7 @@ check() PreconditionChebyshev>::AdditionalData data; data.smoothing_range = 2 * size; - data.degree = 3; + data.degree = 4; prec.initialize(m, data); deallog << "Exact inverse: "; diff --git a/tests/lac/precondition_chebyshev_02.cc b/tests/lac/precondition_chebyshev_02.cc index 13a179d44fbd..5b029fbcfc91 100644 --- a/tests/lac/precondition_chebyshev_02.cc +++ b/tests/lac/precondition_chebyshev_02.cc @@ -87,7 +87,7 @@ check() Vector, DiagonalMatrixManual>::AdditionalData data; data.smoothing_range = 2 * size; - data.degree = 3; + data.degree = 4; data.preconditioner.reset(new DiagonalMatrixManual()); data.preconditioner->set_vector_one(size); prec.initialize(m, data); diff --git a/tests/lac/precondition_chebyshev_03.cc b/tests/lac/precondition_chebyshev_03.cc index 4a964e85f4f7..c8999d959bca 100644 --- a/tests/lac/precondition_chebyshev_03.cc +++ b/tests/lac/precondition_chebyshev_03.cc @@ -59,7 +59,7 @@ main() SparseILU>::AdditionalData cheby_data; cheby_data.preconditioner.reset(new SparseILU()); cheby_data.preconditioner->initialize(A); - cheby_data.degree = 10; + cheby_data.degree = 11; cheby_data.smoothing_range = 40; cheby.initialize(A, cheby_data); diff --git a/tests/lac/precondition_chebyshev_04.cc b/tests/lac/precondition_chebyshev_04.cc index a4ba314794d0..484e93c22986 100644 --- a/tests/lac/precondition_chebyshev_04.cc +++ b/tests/lac/precondition_chebyshev_04.cc @@ -87,7 +87,7 @@ check() Vector, DiagonalMatrixManual>::AdditionalData data; data.smoothing_range = 2 * size; - data.degree = 3; + data.degree = 4; data.preconditioner.reset(new DiagonalMatrixManual()); data.preconditioner->set_vector_one(size); prec.initialize(m, data); diff --git a/tests/lac/precondition_chebyshev_05.cc b/tests/lac/precondition_chebyshev_05.cc index 8e6d2c1b1218..c65114d273f1 100644 --- a/tests/lac/precondition_chebyshev_05.cc +++ b/tests/lac/precondition_chebyshev_05.cc @@ -67,7 +67,7 @@ main(int argc, char **argv) cheby_data.preconditioner.reset( new TrilinosWrappers::PreconditionJacobi()); cheby_data.preconditioner->initialize(AA); - cheby_data.degree = 10; + cheby_data.degree = 11; cheby_data.smoothing_range = 40; cheby.initialize(AA, cheby_data); diff --git a/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=1.output b/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=1.output index 9465de82032c..4624baa08f23 100644 --- a/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=1.output +++ b/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=1.output @@ -2,40 +2,40 @@ DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 256 DEAL:2d:cg::Starting value 16.0000 -DEAL:2d:cg::Convergence step 6 value 3.31973e-12 +DEAL:2d:cg::Convergence step 7 value 1.80729e-11 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 1024 DEAL:2d:cg::Starting value 32.0000 -DEAL:2d:cg::Convergence step 6 value 1.50088e-09 +DEAL:2d:cg::Convergence step 8 value 8.73511e-11 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 4096 DEAL:2d:cg::Starting value 64.0000 -DEAL:2d:cg::Convergence step 7 value 7.89595e-10 +DEAL:2d:cg::Convergence step 8 value 4.57619e-10 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 576 DEAL:2d:cg::Starting value 24.0000 -DEAL:2d:cg::Convergence step 6 value 2.18769e-10 +DEAL:2d:cg::Convergence step 7 value 1.07430e-09 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 2304 DEAL:2d:cg::Starting value 48.0000 -DEAL:2d:cg::Convergence step 6 value 1.04858e-09 +DEAL:2d:cg::Convergence step 8 value 1.87005e-10 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 512 DEAL:3d:cg::Starting value 22.6274 -DEAL:3d:cg::Convergence step 4 value 1.39603e-17 +DEAL:3d:cg::Convergence step 4 value 7.99677e-17 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 4096 DEAL:3d:cg::Starting value 64.0000 -DEAL:3d:cg::Convergence step 6 value 2.68072e-11 +DEAL:3d:cg::Convergence step 6 value 2.27740e-11 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 32768 DEAL:3d:cg::Starting value 181.019 -DEAL:3d:cg::Convergence step 7 value 8.70647e-10 +DEAL:3d:cg::Convergence step 7 value 2.41331e-09 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 1728 DEAL:3d:cg::Starting value 41.5692 -DEAL:3d:cg::Convergence step 7 value 1.39310e-09 +DEAL:3d:cg::Convergence step 8 value 1.14978e-09 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 13824 DEAL:3d:cg::Starting value 117.576 -DEAL:3d:cg::Convergence step 8 value 1.40299e-09 +DEAL:3d:cg::Convergence step 9 value 1.16347e-09 diff --git a/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=3.output b/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=3.output index 07dcc3520536..7630f429b145 100644 --- a/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=3.output +++ b/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=3.output @@ -2,40 +2,40 @@ DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 256 DEAL:2d:cg::Starting value 16.0000 -DEAL:2d:cg::Convergence step 6 value 3.31973e-12 +DEAL:2d:cg::Convergence step 7 value 1.80729e-11 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 1024 DEAL:2d:cg::Starting value 32.0000 -DEAL:2d:cg::Convergence step 6 value 1.50088e-09 +DEAL:2d:cg::Convergence step 8 value 8.73511e-11 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 4096 DEAL:2d:cg::Starting value 64.0000 -DEAL:2d:cg::Convergence step 7 value 7.89595e-10 +DEAL:2d:cg::Convergence step 8 value 4.57619e-10 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 576 DEAL:2d:cg::Starting value 24.0000 -DEAL:2d:cg::Convergence step 6 value 2.18769e-10 +DEAL:2d:cg::Convergence step 7 value 1.07430e-09 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 2304 DEAL:2d:cg::Starting value 48.0000 -DEAL:2d:cg::Convergence step 6 value 1.04858e-09 +DEAL:2d:cg::Convergence step 8 value 1.87005e-10 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 512 DEAL:3d:cg::Starting value 22.6274 -DEAL:3d:cg::Convergence step 4 value 1.45014e-17 +DEAL:3d:cg::Convergence step 4 value 9.91449e-17 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 4096 DEAL:3d:cg::Starting value 64.0000 -DEAL:3d:cg::Convergence step 6 value 2.68072e-11 +DEAL:3d:cg::Convergence step 6 value 2.27740e-11 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 32768 DEAL:3d:cg::Starting value 181.019 -DEAL:3d:cg::Convergence step 7 value 8.70647e-10 +DEAL:3d:cg::Convergence step 7 value 2.41331e-09 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 1728 DEAL:3d:cg::Starting value 41.5692 -DEAL:3d:cg::Convergence step 7 value 1.39310e-09 +DEAL:3d:cg::Convergence step 8 value 1.14978e-09 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 13824 DEAL:3d:cg::Starting value 117.576 -DEAL:3d:cg::Convergence step 8 value 1.40299e-09 +DEAL:3d:cg::Convergence step 9 value 1.16347e-09 diff --git a/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=5.output b/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=5.output index 6d3556b543b8..e2e33e652a97 100644 --- a/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=5.output +++ b/tests/matrix_free/multigrid_dg_periodic.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=5.output @@ -2,40 +2,40 @@ DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 256 DEAL:2d:cg::Starting value 16.0000 -DEAL:2d:cg::Convergence step 6 value 3.31973e-12 +DEAL:2d:cg::Convergence step 7 value 1.80729e-11 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 1024 DEAL:2d:cg::Starting value 32.0000 -DEAL:2d:cg::Convergence step 6 value 1.50088e-09 +DEAL:2d:cg::Convergence step 8 value 8.73511e-11 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 4096 DEAL:2d:cg::Starting value 64.0000 -DEAL:2d:cg::Convergence step 7 value 7.89595e-10 +DEAL:2d:cg::Convergence step 8 value 4.57619e-10 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 576 DEAL:2d:cg::Starting value 24.0000 -DEAL:2d:cg::Convergence step 6 value 2.18769e-10 +DEAL:2d:cg::Convergence step 7 value 1.07430e-09 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 2304 DEAL:2d:cg::Starting value 48.0000 -DEAL:2d:cg::Convergence step 6 value 1.04858e-09 +DEAL:2d:cg::Convergence step 8 value 1.87005e-10 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 512 DEAL:3d:cg::Starting value 22.6274 -DEAL:3d:cg::Convergence step 4 value 1.18679e-17 +DEAL:3d:cg::Convergence step 4 value 7.23452e-17 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 4096 DEAL:3d:cg::Starting value 64.0000 -DEAL:3d:cg::Convergence step 6 value 2.68072e-11 +DEAL:3d:cg::Convergence step 6 value 2.27740e-11 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 32768 DEAL:3d:cg::Starting value 181.019 -DEAL:3d:cg::Convergence step 7 value 8.70647e-10 +DEAL:3d:cg::Convergence step 7 value 2.41331e-09 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 1728 DEAL:3d:cg::Starting value 41.5692 -DEAL:3d:cg::Convergence step 7 value 1.39310e-09 +DEAL:3d:cg::Convergence step 8 value 1.14978e-09 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 13824 DEAL:3d:cg::Starting value 117.576 -DEAL:3d:cg::Convergence step 8 value 1.40299e-09 +DEAL:3d:cg::Convergence step 9 value 1.16347e-09 diff --git a/tests/matrix_free/multigrid_dg_sip_01.with_mpi=true.with_p4est=true.mpirun=1.output b/tests/matrix_free/multigrid_dg_sip_01.with_mpi=true.with_p4est=true.mpirun=1.output index 29dbbfae2dc3..3755b9b07c24 100644 --- a/tests/matrix_free/multigrid_dg_sip_01.with_mpi=true.with_p4est=true.mpirun=1.output +++ b/tests/matrix_free/multigrid_dg_sip_01.with_mpi=true.with_p4est=true.mpirun=1.output @@ -2,40 +2,40 @@ DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 256 DEAL:2d:cg::Starting value 16.0000 -DEAL:2d:cg::Convergence step 4 value 1.45213e-06 +DEAL:2d:cg::Convergence step 5 value 3.60502e-07 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 1024 DEAL:2d:cg::Starting value 32.0000 -DEAL:2d:cg::Convergence step 5 value 8.09074e-08 +DEAL:2d:cg::Convergence step 5 value 2.14074e-06 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 4096 DEAL:2d:cg::Starting value 64.0000 -DEAL:2d:cg::Convergence step 5 value 9.08540e-07 +DEAL:2d:cg::Convergence step 5 value 5.99637e-06 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 576 DEAL:2d:cg::Starting value 24.0000 -DEAL:2d:cg::Convergence step 5 value 4.02774e-08 +DEAL:2d:cg::Convergence step 5 value 1.81901e-06 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 2304 DEAL:2d:cg::Starting value 48.0000 -DEAL:2d:cg::Convergence step 5 value 7.58404e-08 +DEAL:2d:cg::Convergence step 6 value 1.94976e-07 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 512 DEAL:3d:cg::Starting value 22.6274 -DEAL:3d:cg::Convergence step 5 value 2.70681e-07 +DEAL:3d:cg::Convergence step 6 value 7.43327e-08 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 4096 DEAL:3d:cg::Starting value 64.0000 -DEAL:3d:cg::Convergence step 5 value 3.69638e-06 +DEAL:3d:cg::Convergence step 6 value 2.28298e-06 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 32768 DEAL:3d:cg::Starting value 181.019 -DEAL:3d:cg::Convergence step 5 value 5.56024e-06 +DEAL:3d:cg::Convergence step 6 value 5.09300e-06 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 1728 DEAL:3d:cg::Starting value 41.5692 -DEAL:3d:cg::Convergence step 5 value 5.30416e-07 +DEAL:3d:cg::Convergence step 6 value 1.73456e-07 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 13824 DEAL:3d:cg::Starting value 117.576 -DEAL:3d:cg::Convergence step 6 value 8.58800e-07 +DEAL:3d:cg::Convergence step 7 value 5.35539e-07 diff --git a/tests/matrix_free/multigrid_dg_sip_01.with_mpi=true.with_p4est=true.mpirun=5.output b/tests/matrix_free/multigrid_dg_sip_01.with_mpi=true.with_p4est=true.mpirun=5.output index 29dbbfae2dc3..3755b9b07c24 100644 --- a/tests/matrix_free/multigrid_dg_sip_01.with_mpi=true.with_p4est=true.mpirun=5.output +++ b/tests/matrix_free/multigrid_dg_sip_01.with_mpi=true.with_p4est=true.mpirun=5.output @@ -2,40 +2,40 @@ DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 256 DEAL:2d:cg::Starting value 16.0000 -DEAL:2d:cg::Convergence step 4 value 1.45213e-06 +DEAL:2d:cg::Convergence step 5 value 3.60502e-07 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 1024 DEAL:2d:cg::Starting value 32.0000 -DEAL:2d:cg::Convergence step 5 value 8.09074e-08 +DEAL:2d:cg::Convergence step 5 value 2.14074e-06 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 4096 DEAL:2d:cg::Starting value 64.0000 -DEAL:2d:cg::Convergence step 5 value 9.08540e-07 +DEAL:2d:cg::Convergence step 5 value 5.99637e-06 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 576 DEAL:2d:cg::Starting value 24.0000 -DEAL:2d:cg::Convergence step 5 value 4.02774e-08 +DEAL:2d:cg::Convergence step 5 value 1.81901e-06 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 2304 DEAL:2d:cg::Starting value 48.0000 -DEAL:2d:cg::Convergence step 5 value 7.58404e-08 +DEAL:2d:cg::Convergence step 6 value 1.94976e-07 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 512 DEAL:3d:cg::Starting value 22.6274 -DEAL:3d:cg::Convergence step 5 value 2.70681e-07 +DEAL:3d:cg::Convergence step 6 value 7.43327e-08 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 4096 DEAL:3d:cg::Starting value 64.0000 -DEAL:3d:cg::Convergence step 5 value 3.69638e-06 +DEAL:3d:cg::Convergence step 6 value 2.28298e-06 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 32768 DEAL:3d:cg::Starting value 181.019 -DEAL:3d:cg::Convergence step 5 value 5.56024e-06 +DEAL:3d:cg::Convergence step 6 value 5.09300e-06 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 1728 DEAL:3d:cg::Starting value 41.5692 -DEAL:3d:cg::Convergence step 5 value 5.30416e-07 +DEAL:3d:cg::Convergence step 6 value 1.73456e-07 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 13824 DEAL:3d:cg::Starting value 117.576 -DEAL:3d:cg::Convergence step 6 value 8.58800e-07 +DEAL:3d:cg::Convergence step 7 value 5.35539e-07 diff --git a/tests/matrix_free/multigrid_dg_sip_02.with_mpi=true.with_p4est=true.mpirun=5.output b/tests/matrix_free/multigrid_dg_sip_02.with_mpi=true.with_p4est=true.mpirun=5.output index 29dbbfae2dc3..3755b9b07c24 100644 --- a/tests/matrix_free/multigrid_dg_sip_02.with_mpi=true.with_p4est=true.mpirun=5.output +++ b/tests/matrix_free/multigrid_dg_sip_02.with_mpi=true.with_p4est=true.mpirun=5.output @@ -2,40 +2,40 @@ DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 256 DEAL:2d:cg::Starting value 16.0000 -DEAL:2d:cg::Convergence step 4 value 1.45213e-06 +DEAL:2d:cg::Convergence step 5 value 3.60502e-07 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 1024 DEAL:2d:cg::Starting value 32.0000 -DEAL:2d:cg::Convergence step 5 value 8.09074e-08 +DEAL:2d:cg::Convergence step 5 value 2.14074e-06 DEAL:2d::Testing FE_DGQ<2>(1) DEAL:2d::Number of degrees of freedom: 4096 DEAL:2d:cg::Starting value 64.0000 -DEAL:2d:cg::Convergence step 5 value 9.08540e-07 +DEAL:2d:cg::Convergence step 5 value 5.99637e-06 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 576 DEAL:2d:cg::Starting value 24.0000 -DEAL:2d:cg::Convergence step 5 value 4.02774e-08 +DEAL:2d:cg::Convergence step 5 value 1.81901e-06 DEAL:2d::Testing FE_DGQ<2>(2) DEAL:2d::Number of degrees of freedom: 2304 DEAL:2d:cg::Starting value 48.0000 -DEAL:2d:cg::Convergence step 5 value 7.58404e-08 +DEAL:2d:cg::Convergence step 6 value 1.94976e-07 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 512 DEAL:3d:cg::Starting value 22.6274 -DEAL:3d:cg::Convergence step 5 value 2.70681e-07 +DEAL:3d:cg::Convergence step 6 value 7.43327e-08 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 4096 DEAL:3d:cg::Starting value 64.0000 -DEAL:3d:cg::Convergence step 5 value 3.69638e-06 +DEAL:3d:cg::Convergence step 6 value 2.28298e-06 DEAL:3d::Testing FE_DGQ<3>(1) DEAL:3d::Number of degrees of freedom: 32768 DEAL:3d:cg::Starting value 181.019 -DEAL:3d:cg::Convergence step 5 value 5.56024e-06 +DEAL:3d:cg::Convergence step 6 value 5.09300e-06 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 1728 DEAL:3d:cg::Starting value 41.5692 -DEAL:3d:cg::Convergence step 5 value 5.30416e-07 +DEAL:3d:cg::Convergence step 6 value 1.73456e-07 DEAL:3d::Testing FE_DGQ<3>(2) DEAL:3d::Number of degrees of freedom: 13824 DEAL:3d:cg::Starting value 117.576 -DEAL:3d:cg::Convergence step 6 value 8.58800e-07 +DEAL:3d:cg::Convergence step 7 value 5.35539e-07 diff --git a/tests/matrix_free/parallel_multigrid.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output b/tests/matrix_free/parallel_multigrid.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output index cd85abb36828..3c079a9e5332 100644 --- a/tests/matrix_free/parallel_multigrid.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output +++ b/tests/matrix_free/parallel_multigrid.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output @@ -2,130 +2,144 @@ DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 81 DEAL:2d:cg::Starting value 9.000 -DEAL:2d:cg:cg::Starting value 0.008804 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 1.035e-05 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 9.380e-08 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg::Convergence step 3 value 4.632e-07 +DEAL:2d:cg:cg::Starting value 0.02203 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 0.0001585 +DEAL:2d:cg:cg::Convergence step 1 value 2.711e-20 +DEAL:2d:cg:cg::Starting value 8.884e-07 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 3.123e-09 +DEAL:2d:cg:cg::Convergence step 1 value 8.272e-25 +DEAL:2d:cg::Convergence step 4 value 2.071e-08 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 289 DEAL:2d:cg::Starting value 17.00 -DEAL:2d:cg:cg::Starting value 0.02904 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 5.542e-06 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 3.318e-09 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg::Convergence step 3 value 4.000e-07 +DEAL:2d:cg:cg::Starting value 0.005310 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 5.163e-06 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 2.182e-08 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 9.610e-10 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg::Convergence step 4 value 2.778e-08 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 1089 DEAL:2d:cg::Starting value 33.00 -DEAL:2d:cg:cg::Starting value 0.1041 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 3.041e-06 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 1.133e-07 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 1.824e-10 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg::Convergence step 4 value 1.222e-08 +DEAL:2d:cg:cg::Starting value 0.008242 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 2.754e-06 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 9.820e-09 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 8.188e-12 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg::Convergence step 4 value 8.029e-08 DEAL:2d::Testing FE_Q<2>(2) DEAL:2d::Number of degrees of freedom: 289 DEAL:2d:cg::Starting value 17.00 -DEAL:2d:cg:cg::Starting value 0.4928 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 7.433e-05 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 4.269e-07 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 1.107e-09 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg::Convergence step 4 value 1.339e-08 +DEAL:2d:cg:cg::Starting value 3.849 +DEAL:2d:cg:cg::Convergence step 2 value 4.030e-15 +DEAL:2d:cg:cg::Starting value 0.0007035 +DEAL:2d:cg:cg::Convergence step 2 value 5.474e-20 +DEAL:2d:cg:cg::Starting value 4.286e-06 +DEAL:2d:cg:cg::Convergence step 2 value 4.924e-21 +DEAL:2d:cg:cg::Starting value 2.909e-08 +DEAL:2d:cg:cg::Convergence step 2 value 6.440e-24 +DEAL:2d:cg::Convergence step 4 value 3.931e-08 DEAL:2d::Testing FE_Q<2>(2) DEAL:2d::Number of degrees of freedom: 1089 DEAL:2d:cg::Starting value 33.00 -DEAL:2d:cg:cg::Starting value 1.857 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 6.915e-05 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 9.008e-07 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 2.272e-09 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg::Convergence step 4 value 1.555e-08 +DEAL:2d:cg:cg::Starting value 14.69 +DEAL:2d:cg:cg::Convergence step 2 value 1.477e-14 +DEAL:2d:cg:cg::Starting value 0.002915 +DEAL:2d:cg:cg::Convergence step 2 value 8.995e-19 +DEAL:2d:cg:cg::Starting value 3.439e-06 +DEAL:2d:cg:cg::Convergence step 2 value 3.178e-21 +DEAL:2d:cg:cg::Starting value 1.212e-08 +DEAL:2d:cg:cg::Convergence step 2 value 1.500e-23 +DEAL:2d:cg::Convergence step 4 value 8.121e-08 DEAL:2d::Testing FE_Q<2>(2) DEAL:2d::Number of degrees of freedom: 4225 DEAL:2d:cg::Starting value 65.00 -DEAL:2d:cg:cg::Starting value 7.324 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 0.0003835 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 5.631e-07 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 8.812e-09 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg::Convergence step 4 value 3.108e-08 +DEAL:2d:cg:cg::Starting value 58.09 +DEAL:2d:cg:cg::Convergence step 2 value 5.909e-15 +DEAL:2d:cg:cg::Starting value 0.01056 +DEAL:2d:cg:cg::Convergence step 2 value 5.646e-18 +DEAL:2d:cg:cg::Starting value 2.588e-05 +DEAL:2d:cg:cg::Convergence step 2 value 8.081e-21 +DEAL:2d:cg:cg::Starting value 6.672e-08 +DEAL:2d:cg:cg::Convergence step 2 value 4.727e-23 +DEAL:2d:cg::Convergence step 4 value 1.695e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 125 DEAL:3d:cg::Starting value 11.18 -DEAL:3d:cg:cg::Starting value 0.1411 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 7.053e-05 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 4.822e-09 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg::Convergence step 3 value 9.057e-09 +DEAL:3d:cg:cg::Starting value 0.5164 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 0.02357 +DEAL:3d:cg:cg::Convergence step 1 value 4.907e-18 +DEAL:3d:cg:cg::Starting value 5.322e-05 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 1.537e-07 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg::Convergence step 4 value 3.460e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 729 DEAL:3d:cg::Starting value 27.00 -DEAL:3d:cg:cg::Starting value 0.03502 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 0.0002864 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 1.471e-07 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg::Convergence step 3 value 1.321e-06 +DEAL:3d:cg:cg::Starting value 0.1824 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 0.004902 +DEAL:3d:cg:cg::Convergence step 1 value 6.133e-19 +DEAL:3d:cg:cg::Starting value 5.629e-06 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 3.386e-10 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg::Convergence step 4 value 1.074e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 4913 DEAL:3d:cg::Starting value 70.09 -DEAL:3d:cg:cg::Starting value 0.06187 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 7.069e-05 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 8.132e-07 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 1.153e-09 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg::Convergence step 4 value 6.546e-08 +DEAL:3d:cg:cg::Starting value 0.1633 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 0.0001064 +DEAL:3d:cg:cg::Convergence step 1 value 1.917e-20 +DEAL:3d:cg:cg::Starting value 1.367e-06 +DEAL:3d:cg:cg::Convergence step 1 value 2.995e-22 +DEAL:3d:cg:cg::Starting value 1.607e-08 +DEAL:3d:cg:cg::Convergence step 1 value 4.679e-24 +DEAL:3d:cg::Convergence step 4 value 5.067e-08 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 729 DEAL:3d:cg::Starting value 27.00 -DEAL:3d:cg:cg::Starting value 1.198 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 0.0001874 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 8.519e-08 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg::Convergence step 3 value 4.352e-08 +DEAL:3d:cg:cg::Starting value 1.696 +DEAL:3d:cg:cg::Convergence step 2 value 3.019e-16 +DEAL:3d:cg:cg::Starting value 0.1038 +DEAL:3d:cg:cg::Convergence step 2 value 1.281e-17 +DEAL:3d:cg:cg::Starting value 0.0001778 +DEAL:3d:cg:cg::Convergence step 2 value 2.774e-20 +DEAL:3d:cg:cg::Starting value 5.289e-06 +DEAL:3d:cg:cg::Convergence step 2 value 5.235e-22 +DEAL:3d:cg::Convergence step 4 value 2.355e-06 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 4913 DEAL:3d:cg::Starting value 70.09 -DEAL:3d:cg:cg::Starting value 6.688 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 0.0005904 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 2.187e-06 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg::Convergence step 3 value 2.196e-06 +DEAL:3d:cg:cg::Starting value 2.313 +DEAL:3d:cg:cg::Convergence step 2 value 3.056e-16 +DEAL:3d:cg:cg::Starting value 0.04486 +DEAL:3d:cg:cg::Convergence step 2 value 9.479e-18 +DEAL:3d:cg:cg::Starting value 0.0007197 +DEAL:3d:cg:cg::Convergence step 2 value 1.099e-19 +DEAL:3d:cg:cg::Starting value 2.909e-06 +DEAL:3d:cg:cg::Convergence step 2 value 1.507e-22 +DEAL:3d:cg::Convergence step 4 value 4.578e-06 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 35937 DEAL:3d:cg::Starting value 189.6 -DEAL:3d:cg:cg::Starting value 49.17 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 0.006462 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 8.640e-06 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg::Convergence step 3 value 9.302e-06 +DEAL:3d:cg:cg::Starting value 17.40 +DEAL:3d:cg:cg::Convergence step 2 value 1.067e-14 +DEAL:3d:cg:cg::Starting value 0.01679 +DEAL:3d:cg:cg::Convergence step 2 value 2.474e-18 +DEAL:3d:cg:cg::Starting value 0.001098 +DEAL:3d:cg:cg::Convergence step 2 value 8.085e-20 +DEAL:3d:cg:cg::Starting value 1.006e-06 +DEAL:3d:cg:cg::Convergence step 2 value 9.940e-23 +DEAL:3d:cg::Convergence step 4 value 1.784e-05 diff --git a/tests/matrix_free/parallel_multigrid.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output b/tests/matrix_free/parallel_multigrid.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output index cd85abb36828..03fd053a904c 100644 --- a/tests/matrix_free/parallel_multigrid.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output +++ b/tests/matrix_free/parallel_multigrid.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output @@ -2,130 +2,144 @@ DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 81 DEAL:2d:cg::Starting value 9.000 -DEAL:2d:cg:cg::Starting value 0.008804 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 1.035e-05 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 9.380e-08 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg::Convergence step 3 value 4.632e-07 +DEAL:2d:cg:cg::Starting value 0.02203 +DEAL:2d:cg:cg::Convergence step 1 value 3.469e-18 +DEAL:2d:cg:cg::Starting value 0.0001585 +DEAL:2d:cg:cg::Convergence step 1 value 2.711e-20 +DEAL:2d:cg:cg::Starting value 8.884e-07 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 3.123e-09 +DEAL:2d:cg:cg::Convergence step 1 value 4.136e-25 +DEAL:2d:cg::Convergence step 4 value 2.071e-08 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 289 DEAL:2d:cg::Starting value 17.00 -DEAL:2d:cg:cg::Starting value 0.02904 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 5.542e-06 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 3.318e-09 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg::Convergence step 3 value 4.000e-07 +DEAL:2d:cg:cg::Starting value 0.005310 +DEAL:2d:cg:cg::Convergence step 1 value 8.674e-19 +DEAL:2d:cg:cg::Starting value 5.163e-06 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 2.182e-08 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 9.610e-10 +DEAL:2d:cg:cg::Convergence step 1 value 2.068e-25 +DEAL:2d:cg::Convergence step 4 value 2.778e-08 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 1089 DEAL:2d:cg::Starting value 33.00 -DEAL:2d:cg:cg::Starting value 0.1041 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 3.041e-06 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 1.133e-07 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 1.824e-10 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg::Convergence step 4 value 1.222e-08 +DEAL:2d:cg:cg::Starting value 0.008242 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 2.754e-06 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 9.820e-09 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 8.188e-12 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg::Convergence step 4 value 8.029e-08 DEAL:2d::Testing FE_Q<2>(2) DEAL:2d::Number of degrees of freedom: 289 DEAL:2d:cg::Starting value 17.00 -DEAL:2d:cg:cg::Starting value 0.4928 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 7.433e-05 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 4.269e-07 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 1.107e-09 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg::Convergence step 4 value 1.339e-08 +DEAL:2d:cg:cg::Starting value 3.849 +DEAL:2d:cg:cg::Convergence step 2 value 2.944e-15 +DEAL:2d:cg:cg::Starting value 0.0007035 +DEAL:2d:cg:cg::Convergence step 2 value 9.681e-20 +DEAL:2d:cg:cg::Starting value 4.286e-06 +DEAL:2d:cg:cg::Convergence step 2 value 3.549e-21 +DEAL:2d:cg:cg::Starting value 2.909e-08 +DEAL:2d:cg:cg::Convergence step 2 value 1.182e-23 +DEAL:2d:cg::Convergence step 4 value 3.931e-08 DEAL:2d::Testing FE_Q<2>(2) DEAL:2d::Number of degrees of freedom: 1089 DEAL:2d:cg::Starting value 33.00 -DEAL:2d:cg:cg::Starting value 1.857 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 6.915e-05 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 9.008e-07 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 2.272e-09 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg::Convergence step 4 value 1.555e-08 +DEAL:2d:cg:cg::Starting value 14.69 +DEAL:2d:cg:cg::Convergence step 2 value 4.231e-15 +DEAL:2d:cg:cg::Starting value 0.002915 +DEAL:2d:cg:cg::Convergence step 2 value 5.424e-18 +DEAL:2d:cg:cg::Starting value 3.439e-06 +DEAL:2d:cg:cg::Convergence step 2 value 1.113e-21 +DEAL:2d:cg:cg::Starting value 1.212e-08 +DEAL:2d:cg:cg::Convergence step 2 value 7.249e-24 +DEAL:2d:cg::Convergence step 4 value 8.121e-08 DEAL:2d::Testing FE_Q<2>(2) DEAL:2d::Number of degrees of freedom: 4225 DEAL:2d:cg::Starting value 65.00 -DEAL:2d:cg:cg::Starting value 7.324 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 0.0003835 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 5.631e-07 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg:cg::Starting value 8.812e-09 -DEAL:2d:cg:cg::Convergence step 2 value 0 -DEAL:2d:cg::Convergence step 4 value 3.108e-08 +DEAL:2d:cg:cg::Starting value 58.09 +DEAL:2d:cg:cg::Convergence step 2 value 5.109e-14 +DEAL:2d:cg:cg::Starting value 0.01056 +DEAL:2d:cg:cg::Convergence step 2 value 7.258e-19 +DEAL:2d:cg:cg::Starting value 2.588e-05 +DEAL:2d:cg:cg::Convergence step 2 value 8.491e-21 +DEAL:2d:cg:cg::Starting value 6.672e-08 +DEAL:2d:cg:cg::Convergence step 2 value 1.252e-23 +DEAL:2d:cg::Convergence step 4 value 1.695e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 125 DEAL:3d:cg::Starting value 11.18 -DEAL:3d:cg:cg::Starting value 0.1411 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 7.053e-05 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 4.822e-09 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg::Convergence step 3 value 9.057e-09 +DEAL:3d:cg:cg::Starting value 0.5164 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 0.02357 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 5.322e-05 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 1.537e-07 +DEAL:3d:cg:cg::Convergence step 1 value 3.743e-23 +DEAL:3d:cg::Convergence step 4 value 3.460e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 729 DEAL:3d:cg::Starting value 27.00 -DEAL:3d:cg:cg::Starting value 0.03502 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 0.0002864 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 1.471e-07 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg::Convergence step 3 value 1.321e-06 +DEAL:3d:cg:cg::Starting value 0.1824 +DEAL:3d:cg:cg::Convergence step 1 value 3.925e-17 +DEAL:3d:cg:cg::Starting value 0.004902 +DEAL:3d:cg:cg::Convergence step 1 value 6.133e-19 +DEAL:3d:cg:cg::Starting value 5.629e-06 +DEAL:3d:cg:cg::Convergence step 1 value 1.198e-21 +DEAL:3d:cg:cg::Starting value 3.386e-10 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg::Convergence step 4 value 1.074e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 4913 DEAL:3d:cg::Starting value 70.09 -DEAL:3d:cg:cg::Starting value 0.06187 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 7.069e-05 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 8.132e-07 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 1.153e-09 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg::Convergence step 4 value 6.546e-08 +DEAL:3d:cg:cg::Starting value 0.1633 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 0.0001064 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 1.367e-06 +DEAL:3d:cg:cg::Convergence step 1 value 2.995e-22 +DEAL:3d:cg:cg::Starting value 1.607e-08 +DEAL:3d:cg:cg::Convergence step 1 value 4.679e-24 +DEAL:3d:cg::Convergence step 4 value 5.067e-08 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 729 DEAL:3d:cg::Starting value 27.00 -DEAL:3d:cg:cg::Starting value 1.198 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 0.0001874 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 8.519e-08 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg::Convergence step 3 value 4.352e-08 +DEAL:3d:cg:cg::Starting value 1.696 +DEAL:3d:cg:cg::Convergence step 2 value 2.866e-16 +DEAL:3d:cg:cg::Starting value 0.1038 +DEAL:3d:cg:cg::Convergence step 2 value 2.373e-17 +DEAL:3d:cg:cg::Starting value 0.0001778 +DEAL:3d:cg:cg::Convergence step 2 value 2.322e-20 +DEAL:3d:cg:cg::Starting value 5.289e-06 +DEAL:3d:cg:cg::Convergence step 2 value 3.474e-22 +DEAL:3d:cg::Convergence step 4 value 2.355e-06 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 4913 DEAL:3d:cg::Starting value 70.09 -DEAL:3d:cg:cg::Starting value 6.688 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 0.0005904 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 2.187e-06 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg::Convergence step 3 value 2.196e-06 +DEAL:3d:cg:cg::Starting value 2.313 +DEAL:3d:cg:cg::Convergence step 2 value 2.276e-15 +DEAL:3d:cg:cg::Starting value 0.04486 +DEAL:3d:cg:cg::Convergence step 2 value 8.352e-19 +DEAL:3d:cg:cg::Starting value 0.0007197 +DEAL:3d:cg:cg::Convergence step 2 value 7.308e-20 +DEAL:3d:cg:cg::Starting value 2.909e-06 +DEAL:3d:cg:cg::Convergence step 2 value 1.373e-22 +DEAL:3d:cg::Convergence step 4 value 4.578e-06 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 35937 DEAL:3d:cg::Starting value 189.6 -DEAL:3d:cg:cg::Starting value 49.17 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 0.006462 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg:cg::Starting value 8.640e-06 -DEAL:3d:cg:cg::Convergence step 2 value 0 -DEAL:3d:cg::Convergence step 3 value 9.302e-06 +DEAL:3d:cg:cg::Starting value 17.40 +DEAL:3d:cg:cg::Convergence step 2 value 1.045e-14 +DEAL:3d:cg:cg::Starting value 0.01679 +DEAL:3d:cg:cg::Convergence step 2 value 2.190e-18 +DEAL:3d:cg:cg::Starting value 0.001098 +DEAL:3d:cg:cg::Convergence step 2 value 1.752e-19 +DEAL:3d:cg:cg::Starting value 1.006e-06 +DEAL:3d:cg:cg::Convergence step 2 value 7.732e-22 +DEAL:3d:cg::Convergence step 4 value 1.784e-05 diff --git a/tests/matrix_free/parallel_multigrid_02.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output b/tests/matrix_free/parallel_multigrid_02.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output index 7b27e1ef5971..107753528473 100644 --- a/tests/matrix_free/parallel_multigrid_02.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output +++ b/tests/matrix_free/parallel_multigrid_02.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output @@ -2,68 +2,77 @@ DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 81 DEAL:2d:cg::Starting value 9.000 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg::Convergence step 3 value 3.515e-08 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg::Convergence step 3 value 6.753e-07 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 289 DEAL:2d:cg::Starting value 17.00 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg::Convergence step 3 value 2.831e-08 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg::Convergence step 4 value 2.625e-09 DEAL:2d::Testing FE_Q<2>(2) DEAL:2d::Number of degrees of freedom: 289 DEAL:2d:cg::Starting value 17.00 -DEAL:2d:cg:cg::Starting value 0.4815 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 9.432e-05 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 2.174e-07 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg::Convergence step 3 value 3.366e-07 +DEAL:2d:cg:cg::Starting value 3.765 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 0.0005314 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 3.806e-06 +DEAL:2d:cg:cg::Convergence step 1 value 4.235e-22 +DEAL:2d:cg:cg::Starting value 1.628e-08 +DEAL:2d:cg:cg::Convergence step 1 value 3.309e-24 +DEAL:2d:cg::Convergence step 4 value 1.712e-08 DEAL:2d::Testing FE_Q<2>(2) DEAL:2d::Number of degrees of freedom: 1089 DEAL:2d:cg::Starting value 33.00 -DEAL:2d:cg:cg::Starting value 1.818 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 0.0001408 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 3.548e-08 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg::Convergence step 3 value 8.040e-07 +DEAL:2d:cg:cg::Starting value 14.37 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 0.002280 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 6.550e-06 +DEAL:2d:cg:cg::Convergence step 1 value 8.470e-22 +DEAL:2d:cg:cg::Starting value 5.084e-08 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg::Convergence step 4 value 4.315e-08 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 125 DEAL:3d:cg::Starting value 11.18 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg::Convergence step 3 value 9.624e-10 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg::Convergence step 3 value 4.383e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 729 DEAL:3d:cg::Starting value 27.00 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg::Convergence step 3 value 1.308e-07 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg::Convergence step 3 value 1.025e-06 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 729 DEAL:3d:cg::Starting value 27.00 -DEAL:3d:cg:cg::Starting value 1.147 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 4.360e-05 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 1.203e-07 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg::Convergence step 3 value 2.611e-08 +DEAL:3d:cg:cg::Starting value 0.3913 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 0.0006066 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 3.469e-07 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 5.798e-10 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg::Convergence step 4 value 5.998e-09 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 4913 DEAL:3d:cg::Starting value 70.09 -DEAL:3d:cg:cg::Starting value 6.424 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 0.0006099 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 1.980e-06 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg::Convergence step 3 value 1.197e-06 +DEAL:3d:cg:cg::Starting value 2.274 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 0.0007566 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 3.302e-06 +DEAL:3d:cg:cg::Convergence step 1 value 4.235e-22 +DEAL:3d:cg:cg::Starting value 1.183e-08 +DEAL:3d:cg:cg::Convergence step 1 value 1.654e-24 +DEAL:3d:cg::Convergence step 4 value 5.811e-08 diff --git a/tests/matrix_free/parallel_multigrid_02.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output b/tests/matrix_free/parallel_multigrid_02.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output index 7b27e1ef5971..9b87149d9d44 100644 --- a/tests/matrix_free/parallel_multigrid_02.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output +++ b/tests/matrix_free/parallel_multigrid_02.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output @@ -2,68 +2,77 @@ DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 81 DEAL:2d:cg::Starting value 9.000 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg::Convergence step 3 value 3.515e-08 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg::Convergence step 3 value 6.753e-07 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 289 DEAL:2d:cg::Starting value 17.00 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg:cg::Convergence step 0 value 0 -DEAL:2d:cg::Convergence step 3 value 2.831e-08 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg:cg::Convergence step 0 value 0.000 +DEAL:2d:cg::Convergence step 4 value 2.625e-09 DEAL:2d::Testing FE_Q<2>(2) DEAL:2d::Number of degrees of freedom: 289 DEAL:2d:cg::Starting value 17.00 -DEAL:2d:cg:cg::Starting value 0.4815 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 9.432e-05 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 2.174e-07 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg::Convergence step 3 value 3.366e-07 +DEAL:2d:cg:cg::Starting value 3.765 +DEAL:2d:cg:cg::Convergence step 1 value 4.441e-16 +DEAL:2d:cg:cg::Starting value 0.0005314 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 3.806e-06 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 1.628e-08 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg::Convergence step 4 value 1.712e-08 DEAL:2d::Testing FE_Q<2>(2) DEAL:2d::Number of degrees of freedom: 1089 DEAL:2d:cg::Starting value 33.00 -DEAL:2d:cg:cg::Starting value 1.818 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 0.0001408 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg:cg::Starting value 3.548e-08 -DEAL:2d:cg:cg::Convergence step 1 value 0 -DEAL:2d:cg::Convergence step 3 value 8.040e-07 +DEAL:2d:cg:cg::Starting value 14.37 +DEAL:2d:cg:cg::Convergence step 1 value 1.776e-15 +DEAL:2d:cg:cg::Starting value 0.002280 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg:cg::Starting value 6.550e-06 +DEAL:2d:cg:cg::Convergence step 1 value 8.470e-22 +DEAL:2d:cg:cg::Starting value 5.084e-08 +DEAL:2d:cg:cg::Convergence step 1 value 0.000 +DEAL:2d:cg::Convergence step 4 value 4.315e-08 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 125 DEAL:3d:cg::Starting value 11.18 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg::Convergence step 3 value 9.624e-10 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg::Convergence step 3 value 4.383e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 729 DEAL:3d:cg::Starting value 27.00 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg:cg::Convergence step 0 value 0 -DEAL:3d:cg::Convergence step 3 value 1.308e-07 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg:cg::Convergence step 0 value 0.000 +DEAL:3d:cg::Convergence step 3 value 1.025e-06 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 729 DEAL:3d:cg::Starting value 27.00 -DEAL:3d:cg:cg::Starting value 1.147 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 4.360e-05 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 1.203e-07 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg::Convergence step 3 value 2.611e-08 +DEAL:3d:cg:cg::Starting value 0.3913 +DEAL:3d:cg:cg::Convergence step 1 value 5.551e-17 +DEAL:3d:cg:cg::Starting value 0.0006066 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 3.469e-07 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 5.798e-10 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg::Convergence step 4 value 5.998e-09 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 4913 DEAL:3d:cg::Starting value 70.09 -DEAL:3d:cg:cg::Starting value 6.424 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 0.0006099 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg:cg::Starting value 1.980e-06 -DEAL:3d:cg:cg::Convergence step 1 value 0 -DEAL:3d:cg::Convergence step 3 value 1.197e-06 +DEAL:3d:cg:cg::Starting value 2.274 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 0.0007566 +DEAL:3d:cg:cg::Convergence step 1 value 1.084e-19 +DEAL:3d:cg:cg::Starting value 3.302e-06 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg:cg::Starting value 1.183e-08 +DEAL:3d:cg:cg::Convergence step 1 value 0.000 +DEAL:3d:cg::Convergence step 4 value 5.811e-08 diff --git a/tests/matrix_free/parallel_multigrid_adaptive_01.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output b/tests/matrix_free/parallel_multigrid_adaptive_01.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output index 34ea63ce0d82..4e020c6122be 100644 --- a/tests/matrix_free/parallel_multigrid_adaptive_01.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output +++ b/tests/matrix_free/parallel_multigrid_adaptive_01.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output @@ -2,28 +2,28 @@ DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 507 DEAL:2d:cg::Starting value 21.93 -DEAL:2d:cg::Convergence step 5 value 7.800e-07 +DEAL:2d:cg::Convergence step 5 value 1.167e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 881 DEAL:2d:cg::Starting value 27.77 -DEAL:2d:cg::Convergence step 6 value 9.250e-07 +DEAL:2d:cg::Convergence step 6 value 1.190e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 2147 DEAL:2d:cg::Starting value 43.26 -DEAL:2d:cg::Convergence step 6 value 1.135e-06 +DEAL:2d:cg::Convergence step 6 value 1.886e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 6517 DEAL:2d:cg::Starting value 76.92 -DEAL:2d:cg::Convergence step 6 value 1.557e-06 +DEAL:2d:cg::Convergence step 6 value 3.143e-06 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 1103 DEAL:3d:cg::Starting value 31.21 -DEAL:3d:cg::Convergence step 6 value 3.602e-08 +DEAL:3d:cg::Convergence step 6 value 2.139e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 3694 DEAL:3d:cg::Starting value 55.00 -DEAL:3d:cg::Convergence step 7 value 3.930e-06 +DEAL:3d:cg::Convergence step 7 value 4.724e-06 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 9566 DEAL:3d:cg::Starting value 76.18 -DEAL:3d:cg::Convergence step 8 value 5.370e-06 +DEAL:3d:cg::Convergence step 8 value 6.234e-06 diff --git a/tests/matrix_free/parallel_multigrid_adaptive_01.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output b/tests/matrix_free/parallel_multigrid_adaptive_01.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output index 34ea63ce0d82..cd898e3eaf2b 100644 --- a/tests/matrix_free/parallel_multigrid_adaptive_01.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output +++ b/tests/matrix_free/parallel_multigrid_adaptive_01.with_mpi=true.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output @@ -2,28 +2,28 @@ DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 507 DEAL:2d:cg::Starting value 21.93 -DEAL:2d:cg::Convergence step 5 value 7.800e-07 +DEAL:2d:cg::Convergence step 5 value 1.145e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 881 DEAL:2d:cg::Starting value 27.77 -DEAL:2d:cg::Convergence step 6 value 9.250e-07 +DEAL:2d:cg::Convergence step 6 value 1.176e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 2147 DEAL:2d:cg::Starting value 43.26 -DEAL:2d:cg::Convergence step 6 value 1.135e-06 +DEAL:2d:cg::Convergence step 6 value 1.884e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 6517 DEAL:2d:cg::Starting value 76.92 -DEAL:2d:cg::Convergence step 6 value 1.557e-06 +DEAL:2d:cg::Convergence step 6 value 3.090e-06 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 1103 DEAL:3d:cg::Starting value 31.21 -DEAL:3d:cg::Convergence step 6 value 3.602e-08 +DEAL:3d:cg::Convergence step 6 value 2.139e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 3694 DEAL:3d:cg::Starting value 55.00 -DEAL:3d:cg::Convergence step 7 value 3.930e-06 +DEAL:3d:cg::Convergence step 7 value 4.739e-06 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 9566 DEAL:3d:cg::Starting value 76.18 -DEAL:3d:cg::Convergence step 8 value 5.370e-06 +DEAL:3d:cg::Convergence step 8 value 6.236e-06 diff --git a/tests/matrix_free/parallel_multigrid_adaptive_02.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=3.output b/tests/matrix_free/parallel_multigrid_adaptive_02.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=3.output index 16d865c56ac6..57d068da86c1 100644 --- a/tests/matrix_free/parallel_multigrid_adaptive_02.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=3.output +++ b/tests/matrix_free/parallel_multigrid_adaptive_02.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=3.output @@ -2,48 +2,48 @@ DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 507 DEAL:2d:cg::Starting value 21.93 -DEAL:2d:cg::Convergence step 5 value 7.781e-07 +DEAL:2d:cg::Convergence step 5 value 1.167e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 881 DEAL:2d:cg::Starting value 27.77 -DEAL:2d:cg::Convergence step 6 value 9.215e-07 +DEAL:2d:cg::Convergence step 6 value 1.190e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 2147 DEAL:2d:cg::Starting value 43.26 -DEAL:2d:cg::Convergence step 6 value 1.142e-06 +DEAL:2d:cg::Convergence step 6 value 1.886e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 6517 DEAL:2d:cg::Starting value 76.92 -DEAL:2d:cg::Convergence step 6 value 1.563e-06 +DEAL:2d:cg::Convergence step 6 value 3.143e-06 DEAL:2d::Testing FE_Q<2>(3) DEAL:2d::Number of degrees of freedom: 4259 DEAL:2d:cg::Starting value 64.26 -DEAL:2d:cg::Convergence step 5 value 1.632e-06 +DEAL:2d:cg::Convergence step 5 value 2.131e-06 DEAL:2d::Testing FE_Q<2>(3) DEAL:2d::Number of degrees of freedom: 7457 DEAL:2d:cg::Starting value 83.11 -DEAL:2d:cg::Convergence step 5 value 7.695e-06 +DEAL:2d:cg::Convergence step 6 value 5.783e-07 DEAL:2d::Testing FE_Q<2>(3) DEAL:2d::Number of degrees of freedom: 18535 DEAL:2d:cg::Starting value 131.0 -DEAL:2d:cg::Convergence step 5 value 6.059e-06 +DEAL:2d:cg::Convergence step 6 value 6.147e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 1103 DEAL:3d:cg::Starting value 31.21 -DEAL:3d:cg::Convergence step 6 value 3.615e-08 +DEAL:3d:cg::Convergence step 6 value 2.139e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 3694 DEAL:3d:cg::Starting value 55.00 -DEAL:3d:cg::Convergence step 7 value 3.941e-06 +DEAL:3d:cg::Convergence step 7 value 4.724e-06 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 9566 DEAL:3d:cg::Starting value 76.18 -DEAL:3d:cg::Convergence step 8 value 5.362e-06 +DEAL:3d:cg::Convergence step 8 value 6.234e-06 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 7494 DEAL:3d:cg::Starting value 82.90 -DEAL:3d:cg::Convergence step 7 value 8.682e-07 +DEAL:3d:cg::Convergence step 7 value 1.038e-06 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 26548 DEAL:3d:cg::Starting value 152.6 -DEAL:3d:cg::Convergence step 7 value 3.969e-06 +DEAL:3d:cg::Convergence step 7 value 4.360e-06 diff --git a/tests/matrix_free/parallel_multigrid_adaptive_02.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output b/tests/matrix_free/parallel_multigrid_adaptive_02.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output index 16d865c56ac6..e5e72f230291 100644 --- a/tests/matrix_free/parallel_multigrid_adaptive_02.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output +++ b/tests/matrix_free/parallel_multigrid_adaptive_02.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output @@ -2,48 +2,48 @@ DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 507 DEAL:2d:cg::Starting value 21.93 -DEAL:2d:cg::Convergence step 5 value 7.781e-07 +DEAL:2d:cg::Convergence step 5 value 1.145e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 881 DEAL:2d:cg::Starting value 27.77 -DEAL:2d:cg::Convergence step 6 value 9.215e-07 +DEAL:2d:cg::Convergence step 6 value 1.176e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 2147 DEAL:2d:cg::Starting value 43.26 -DEAL:2d:cg::Convergence step 6 value 1.142e-06 +DEAL:2d:cg::Convergence step 6 value 1.884e-06 DEAL:2d::Testing FE_Q<2>(1) DEAL:2d::Number of degrees of freedom: 6517 DEAL:2d:cg::Starting value 76.92 -DEAL:2d:cg::Convergence step 6 value 1.563e-06 +DEAL:2d:cg::Convergence step 6 value 3.090e-06 DEAL:2d::Testing FE_Q<2>(3) DEAL:2d::Number of degrees of freedom: 4259 DEAL:2d:cg::Starting value 64.26 -DEAL:2d:cg::Convergence step 5 value 1.632e-06 +DEAL:2d:cg::Convergence step 5 value 2.131e-06 DEAL:2d::Testing FE_Q<2>(3) DEAL:2d::Number of degrees of freedom: 7457 DEAL:2d:cg::Starting value 83.11 -DEAL:2d:cg::Convergence step 5 value 7.695e-06 +DEAL:2d:cg::Convergence step 6 value 5.788e-07 DEAL:2d::Testing FE_Q<2>(3) DEAL:2d::Number of degrees of freedom: 18535 DEAL:2d:cg::Starting value 131.0 -DEAL:2d:cg::Convergence step 5 value 6.059e-06 +DEAL:2d:cg::Convergence step 6 value 6.134e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 1103 DEAL:3d:cg::Starting value 31.21 -DEAL:3d:cg::Convergence step 6 value 3.615e-08 +DEAL:3d:cg::Convergence step 6 value 2.139e-07 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 3694 DEAL:3d:cg::Starting value 55.00 -DEAL:3d:cg::Convergence step 7 value 3.941e-06 +DEAL:3d:cg::Convergence step 7 value 4.739e-06 DEAL:3d::Testing FE_Q<3>(1) DEAL:3d::Number of degrees of freedom: 9566 DEAL:3d:cg::Starting value 76.18 -DEAL:3d:cg::Convergence step 8 value 5.362e-06 +DEAL:3d:cg::Convergence step 8 value 6.236e-06 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 7494 DEAL:3d:cg::Starting value 82.90 -DEAL:3d:cg::Convergence step 7 value 8.682e-07 +DEAL:3d:cg::Convergence step 7 value 1.039e-06 DEAL:3d::Testing FE_Q<3>(2) DEAL:3d::Number of degrees of freedom: 26548 DEAL:3d:cg::Starting value 152.6 -DEAL:3d:cg::Convergence step 7 value 3.969e-06 +DEAL:3d:cg::Convergence step 7 value 4.352e-06 diff --git a/tests/matrix_free/parallel_multigrid_adaptive_03.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=4.output b/tests/matrix_free/parallel_multigrid_adaptive_03.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=4.output index c7cff64778d9..877c9af81ae8 100644 --- a/tests/matrix_free/parallel_multigrid_adaptive_03.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=4.output +++ b/tests/matrix_free/parallel_multigrid_adaptive_03.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=4.output @@ -2,104 +2,104 @@ DEAL:nothread::Testing FE_Q<2>(1) DEAL:nothread::Number of degrees of freedom: 507 DEAL:nothread:cg::Starting value 21.9317 -DEAL:nothread:cg::Convergence step 5 value 7.78558e-07 +DEAL:nothread:cg::Convergence step 5 value 1.14537e-06 DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 507 DEAL:threaded:cg::Starting value 21.9317 -DEAL:threaded:cg::Convergence step 5 value 7.78558e-07 +DEAL:threaded:cg::Convergence step 5 value 1.14537e-06 DEAL:nothread::Testing FE_Q<2>(1) DEAL:nothread::Number of degrees of freedom: 881 DEAL:nothread:cg::Starting value 27.7669 -DEAL:nothread:cg::Convergence step 6 value 9.22164e-07 +DEAL:nothread:cg::Convergence step 6 value 1.18996e-06 DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 881 DEAL:threaded:cg::Starting value 27.7669 -DEAL:threaded:cg::Convergence step 6 value 9.22164e-07 +DEAL:threaded:cg::Convergence step 6 value 1.18996e-06 DEAL:nothread::Testing FE_Q<2>(1) DEAL:nothread::Number of degrees of freedom: 2147 DEAL:nothread:cg::Starting value 43.2551 -DEAL:nothread:cg::Convergence step 6 value 1.15108e-06 +DEAL:nothread:cg::Convergence step 6 value 1.86235e-06 DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 2147 DEAL:threaded:cg::Starting value 43.2551 -DEAL:threaded:cg::Convergence step 6 value 1.15108e-06 +DEAL:threaded:cg::Convergence step 6 value 1.86235e-06 DEAL:nothread::Testing FE_Q<2>(1) DEAL:nothread::Number of degrees of freedom: 6517 DEAL:nothread:cg::Starting value 76.9220 -DEAL:nothread:cg::Convergence step 6 value 1.56831e-06 +DEAL:nothread:cg::Convergence step 6 value 3.14118e-06 DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 6517 DEAL:threaded:cg::Starting value 76.9220 -DEAL:threaded:cg::Convergence step 6 value 1.56831e-06 +DEAL:threaded:cg::Convergence step 6 value 3.14118e-06 DEAL:nothread::Testing FE_Q<2>(2) DEAL:nothread::Number of degrees of freedom: 1935 DEAL:nothread:cg::Starting value 43.0929 -DEAL:nothread:cg::Convergence step 5 value 2.13384e-06 +DEAL:nothread:cg::Convergence step 5 value 3.22495e-06 DEAL:threaded::Testing FE_Q<2>(2) DEAL:threaded::Number of degrees of freedom: 1935 DEAL:threaded:cg::Starting value 43.0929 -DEAL:threaded:cg::Convergence step 5 value 2.13388e-06 +DEAL:threaded:cg::Convergence step 5 value 3.22504e-06 DEAL:nothread::Testing FE_Q<2>(2) DEAL:nothread::Number of degrees of freedom: 3403 DEAL:nothread:cg::Starting value 55.4346 -DEAL:nothread:cg::Convergence step 6 value 4.27828e-07 +DEAL:nothread:cg::Convergence step 6 value 8.67853e-07 DEAL:threaded::Testing FE_Q<2>(2) DEAL:threaded::Number of degrees of freedom: 3403 DEAL:threaded:cg::Starting value 55.4346 -DEAL:threaded:cg::Convergence step 6 value 4.27798e-07 +DEAL:threaded:cg::Convergence step 6 value 8.67861e-07 DEAL:nothread::Testing FE_Q<2>(2) DEAL:nothread::Number of degrees of freedom: 8417 DEAL:nothread:cg::Starting value 87.1149 -DEAL:nothread:cg::Convergence step 6 value 2.55138e-07 +DEAL:nothread:cg::Convergence step 6 value 5.47715e-07 DEAL:threaded::Testing FE_Q<2>(2) DEAL:threaded::Number of degrees of freedom: 8417 DEAL:threaded:cg::Starting value 87.1149 -DEAL:threaded:cg::Convergence step 6 value 2.55129e-07 +DEAL:threaded:cg::Convergence step 6 value 5.47726e-07 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 186 DEAL:nothread:cg::Starting value 12.3693 -DEAL:nothread:cg::Convergence step 3 value 2.26211e-07 +DEAL:nothread:cg::Convergence step 4 value 2.87808e-08 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 186 DEAL:threaded:cg::Starting value 12.3693 -DEAL:threaded:cg::Convergence step 3 value 2.26211e-07 +DEAL:threaded:cg::Convergence step 4 value 2.87808e-08 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 648 DEAL:nothread:cg::Starting value 21.1424 -DEAL:nothread:cg::Convergence step 6 value 1.11426e-07 +DEAL:nothread:cg::Convergence step 6 value 6.44935e-07 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 648 DEAL:threaded:cg::Starting value 21.1424 -DEAL:threaded:cg::Convergence step 6 value 1.11426e-07 +DEAL:threaded:cg::Convergence step 6 value 6.44935e-07 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 2930 DEAL:nothread:cg::Starting value 47.1699 -DEAL:nothread:cg::Convergence step 7 value 1.63079e-06 +DEAL:nothread:cg::Convergence step 7 value 2.56010e-06 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 2930 DEAL:threaded:cg::Starting value 47.1699 -DEAL:threaded:cg::Convergence step 7 value 1.63079e-06 +DEAL:threaded:cg::Convergence step 7 value 2.56010e-06 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 186 DEAL:nothread:cg::Starting value 12.3693 -DEAL:nothread:cg::Convergence step 3 value 2.24462e-07 +DEAL:nothread:cg::Convergence step 4 value 2.88983e-08 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 186 DEAL:threaded:cg::Starting value 12.3693 -DEAL:threaded:cg::Convergence step 3 value 2.24473e-07 +DEAL:threaded:cg::Convergence step 4 value 2.88980e-08 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 648 DEAL:nothread:cg::Starting value 21.1424 -DEAL:nothread:cg::Convergence step 6 value 1.06988e-07 +DEAL:nothread:cg::Convergence step 6 value 6.40524e-07 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 648 DEAL:threaded:cg::Starting value 21.1424 -DEAL:threaded:cg::Convergence step 6 value 1.06988e-07 +DEAL:threaded:cg::Convergence step 6 value 6.40523e-07 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 2930 DEAL:nothread:cg::Starting value 47.1699 -DEAL:nothread:cg::Convergence step 7 value 1.63550e-06 +DEAL:nothread:cg::Convergence step 7 value 2.56010e-06 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 2930 DEAL:threaded:cg::Starting value 47.1699 -DEAL:threaded:cg::Convergence step 7 value 1.63550e-06 +DEAL:threaded:cg::Convergence step 7 value 2.56010e-06 diff --git a/tests/matrix_free/parallel_multigrid_adaptive_03.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output b/tests/matrix_free/parallel_multigrid_adaptive_03.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output index fae3b8e1a7d2..d176be1ecf49 100644 --- a/tests/matrix_free/parallel_multigrid_adaptive_03.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output +++ b/tests/matrix_free/parallel_multigrid_adaptive_03.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output @@ -2,104 +2,104 @@ DEAL:nothread::Testing FE_Q<2>(1) DEAL:nothread::Number of degrees of freedom: 507 DEAL:nothread:cg::Starting value 21.9317 -DEAL:nothread:cg::Convergence step 5 value 7.76680e-07 +DEAL:nothread:cg::Convergence step 5 value 1.14539e-06 DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 507 DEAL:threaded:cg::Starting value 21.9317 -DEAL:threaded:cg::Convergence step 5 value 7.76680e-07 +DEAL:threaded:cg::Convergence step 5 value 1.14539e-06 DEAL:nothread::Testing FE_Q<2>(1) DEAL:nothread::Number of degrees of freedom: 881 DEAL:nothread:cg::Starting value 27.7669 -DEAL:nothread:cg::Convergence step 6 value 9.25965e-07 +DEAL:nothread:cg::Convergence step 6 value 1.17649e-06 DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 881 DEAL:threaded:cg::Starting value 27.7669 -DEAL:threaded:cg::Convergence step 6 value 9.25965e-07 +DEAL:threaded:cg::Convergence step 6 value 1.17649e-06 DEAL:nothread::Testing FE_Q<2>(1) DEAL:nothread::Number of degrees of freedom: 2147 DEAL:nothread:cg::Starting value 43.2551 -DEAL:nothread:cg::Convergence step 6 value 1.14972e-06 +DEAL:nothread:cg::Convergence step 6 value 1.88354e-06 DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 2147 DEAL:threaded:cg::Starting value 43.2551 -DEAL:threaded:cg::Convergence step 6 value 1.14972e-06 +DEAL:threaded:cg::Convergence step 6 value 1.88354e-06 DEAL:nothread::Testing FE_Q<2>(1) DEAL:nothread::Number of degrees of freedom: 6517 DEAL:nothread:cg::Starting value 76.9220 -DEAL:nothread:cg::Convergence step 6 value 1.56712e-06 +DEAL:nothread:cg::Convergence step 6 value 3.08982e-06 DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 6517 DEAL:threaded:cg::Starting value 76.9220 -DEAL:threaded:cg::Convergence step 6 value 1.56712e-06 +DEAL:threaded:cg::Convergence step 6 value 3.08982e-06 DEAL:nothread::Testing FE_Q<2>(2) DEAL:nothread::Number of degrees of freedom: 1935 DEAL:nothread:cg::Starting value 43.0929 -DEAL:nothread:cg::Convergence step 5 value 2.13377e-06 +DEAL:nothread:cg::Convergence step 5 value 3.19333e-06 DEAL:threaded::Testing FE_Q<2>(2) DEAL:threaded::Number of degrees of freedom: 1935 DEAL:threaded:cg::Starting value 43.0929 -DEAL:threaded:cg::Convergence step 5 value 2.13371e-06 +DEAL:threaded:cg::Convergence step 5 value 3.19334e-06 DEAL:nothread::Testing FE_Q<2>(2) DEAL:nothread::Number of degrees of freedom: 3403 DEAL:nothread:cg::Starting value 55.4346 -DEAL:nothread:cg::Convergence step 6 value 4.27767e-07 +DEAL:nothread:cg::Convergence step 6 value 8.71780e-07 DEAL:threaded::Testing FE_Q<2>(2) DEAL:threaded::Number of degrees of freedom: 3403 DEAL:threaded:cg::Starting value 55.4346 -DEAL:threaded:cg::Convergence step 6 value 4.27807e-07 +DEAL:threaded:cg::Convergence step 6 value 8.71685e-07 DEAL:nothread::Testing FE_Q<2>(2) DEAL:nothread::Number of degrees of freedom: 8417 DEAL:nothread:cg::Starting value 87.1149 -DEAL:nothread:cg::Convergence step 6 value 2.55168e-07 +DEAL:nothread:cg::Convergence step 6 value 5.47238e-07 DEAL:threaded::Testing FE_Q<2>(2) DEAL:threaded::Number of degrees of freedom: 8417 DEAL:threaded:cg::Starting value 87.1149 -DEAL:threaded:cg::Convergence step 6 value 2.55163e-07 +DEAL:threaded:cg::Convergence step 6 value 5.47227e-07 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 186 DEAL:nothread:cg::Starting value 12.3693 -DEAL:nothread:cg::Convergence step 3 value 2.28324e-07 +DEAL:nothread:cg::Convergence step 4 value 2.87808e-08 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 186 DEAL:threaded:cg::Starting value 12.3693 -DEAL:threaded:cg::Convergence step 3 value 2.28324e-07 +DEAL:threaded:cg::Convergence step 4 value 2.87808e-08 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 648 DEAL:nothread:cg::Starting value 21.1424 -DEAL:nothread:cg::Convergence step 6 value 1.11195e-07 +DEAL:nothread:cg::Convergence step 6 value 6.44905e-07 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 648 DEAL:threaded:cg::Starting value 21.1424 -DEAL:threaded:cg::Convergence step 6 value 1.11195e-07 +DEAL:threaded:cg::Convergence step 6 value 6.44905e-07 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 2930 DEAL:nothread:cg::Starting value 47.1699 -DEAL:nothread:cg::Convergence step 7 value 1.63163e-06 +DEAL:nothread:cg::Convergence step 7 value 2.56063e-06 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 2930 DEAL:threaded:cg::Starting value 47.1699 -DEAL:threaded:cg::Convergence step 7 value 1.63163e-06 +DEAL:threaded:cg::Convergence step 7 value 2.56063e-06 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 186 DEAL:nothread:cg::Starting value 12.3693 -DEAL:nothread:cg::Convergence step 3 value 1.58643e-07 +DEAL:nothread:cg::Convergence step 4 value 2.88986e-08 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 186 DEAL:threaded:cg::Starting value 12.3693 -DEAL:threaded:cg::Convergence step 3 value 1.58660e-07 +DEAL:threaded:cg::Convergence step 4 value 2.88984e-08 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 648 DEAL:nothread:cg::Starting value 21.1424 -DEAL:nothread:cg::Convergence step 6 value 1.06758e-07 +DEAL:nothread:cg::Convergence step 6 value 6.39127e-07 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 648 DEAL:threaded:cg::Starting value 21.1424 -DEAL:threaded:cg::Convergence step 6 value 1.06760e-07 +DEAL:threaded:cg::Convergence step 6 value 6.39130e-07 DEAL:nothread::Testing FE_Q<3>(1) DEAL:nothread::Number of degrees of freedom: 2930 DEAL:nothread:cg::Starting value 47.1699 -DEAL:nothread:cg::Convergence step 7 value 1.63203e-06 +DEAL:nothread:cg::Convergence step 7 value 2.55900e-06 DEAL:threaded::Testing FE_Q<3>(1) DEAL:threaded::Number of degrees of freedom: 2930 DEAL:threaded:cg::Starting value 47.1699 -DEAL:threaded:cg::Convergence step 7 value 1.63203e-06 +DEAL:threaded:cg::Convergence step 7 value 2.55899e-06 diff --git a/tests/matrix_free/parallel_multigrid_adaptive_05.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=4.output b/tests/matrix_free/parallel_multigrid_adaptive_05.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=4.output index 7916f86cb3b6..5563de929413 100644 --- a/tests/matrix_free/parallel_multigrid_adaptive_05.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=4.output +++ b/tests/matrix_free/parallel_multigrid_adaptive_05.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=4.output @@ -2,16 +2,16 @@ DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 507 DEAL:threaded:cg::Starting value 21.9317 -DEAL:threaded:cg::Convergence step 5 value 7.81205e-07 +DEAL:threaded:cg::Convergence step 5 value 1.14537e-06 DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 881 DEAL:threaded:cg::Starting value 27.7669 -DEAL:threaded:cg::Convergence step 6 value 9.24482e-07 +DEAL:threaded:cg::Convergence step 6 value 1.18996e-06 DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 2147 DEAL:threaded:cg::Starting value 43.2551 -DEAL:threaded:cg::Convergence step 6 value 1.14520e-06 +DEAL:threaded:cg::Convergence step 6 value 1.86235e-06 DEAL:threaded::Testing FE_Q<2>(1) DEAL:threaded::Number of degrees of freedom: 6517 DEAL:threaded:cg::Starting value 76.9220 -DEAL:threaded:cg::Convergence step 6 value 1.55925e-06 +DEAL:threaded:cg::Convergence step 6 value 3.14118e-06 diff --git a/tests/matrix_free/parallel_multigrid_mf.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output b/tests/matrix_free/parallel_multigrid_mf.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output index aa47ee8f4d2a..cd88f52b6e0d 100644 --- a/tests/matrix_free/parallel_multigrid_mf.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output +++ b/tests/matrix_free/parallel_multigrid_mf.with_mpi=true.with_p4est=true.with_lapack=true.mpirun=7.output @@ -2,32 +2,32 @@ DEAL::Testing FE_Q<2>(1) DEAL::Number of degrees of freedom: 81 DEAL:cg::Starting value 9.00000 -DEAL:cg::Convergence step 3 value 3.51890e-08 +DEAL:cg::Convergence step 3 value 6.75256e-07 DEAL::Testing FE_Q<2>(1) DEAL::Number of degrees of freedom: 289 DEAL:cg::Starting value 17.0000 -DEAL:cg::Convergence step 3 value 2.90115e-08 +DEAL:cg::Convergence step 4 value 2.62465e-09 DEAL::Testing FE_Q<2>(2) DEAL::Number of degrees of freedom: 289 DEAL:cg::Starting value 17.0000 -DEAL:cg::Convergence step 3 value 2.86879e-07 +DEAL:cg::Convergence step 4 value 1.71224e-08 DEAL::Testing FE_Q<2>(2) DEAL::Number of degrees of freedom: 1089 DEAL:cg::Starting value 33.0000 -DEAL:cg::Convergence step 3 value 7.11331e-07 +DEAL:cg::Convergence step 4 value 4.31534e-08 DEAL::Testing FE_Q<3>(1) DEAL::Number of degrees of freedom: 125 DEAL:cg::Starting value 11.1803 -DEAL:cg::Convergence step 3 value 0 +DEAL:cg::Convergence step 3 value 4.38307e-07 DEAL::Testing FE_Q<3>(1) DEAL::Number of degrees of freedom: 729 DEAL:cg::Starting value 27.0000 -DEAL:cg::Convergence step 3 value 1.30374e-07 +DEAL:cg::Convergence step 3 value 1.02520e-06 DEAL::Testing FE_Q<3>(2) DEAL::Number of degrees of freedom: 729 DEAL:cg::Starting value 27.0000 -DEAL:cg::Convergence step 3 value 2.75558e-08 +DEAL:cg::Convergence step 4 value 5.99244e-09 DEAL::Testing FE_Q<3>(2) DEAL::Number of degrees of freedom: 4913 DEAL:cg::Starting value 70.0928 -DEAL:cg::Convergence step 3 value 1.14078e-06 +DEAL:cg::Convergence step 4 value 5.81100e-08 diff --git a/tests/matrix_free/step-37-inhomogeneous-1.mpirun=4.with_p4est=true.output b/tests/matrix_free/step-37-inhomogeneous-1.mpirun=4.with_p4est=true.output index 6121bdd29e31..59dbf7d1ff29 100644 --- a/tests/matrix_free/step-37-inhomogeneous-1.mpirun=4.with_p4est=true.output +++ b/tests/matrix_free/step-37-inhomogeneous-1.mpirun=4.with_p4est=true.output @@ -2,149 +2,149 @@ Cycle 0 Number of degrees of freedom: 81 DEAL:0:cg::Starting value 45.0807 -DEAL:0:cg::Convergence step 6 value 2.23481e-13 +DEAL:0:cg::Convergence step 7 value 2.65304e-12 max error: 0.00772526 error ratio: 1.00000 Cycle 1 Number of degrees of freedom: 289 DEAL:0:cg::Starting value 68.5863 -DEAL:0:cg::Convergence step 6 value 4.06929e-13 +DEAL:0:cg::Convergence step 7 value 3.81082e-12 max error: 0.000971239 error ratio: 7.95402 Cycle 2 Number of degrees of freedom: 1089 DEAL:0:cg::Starting value 95.4381 -DEAL:0:cg::Convergence step 6 value 5.78305e-13 +DEAL:0:cg::Convergence step 7 value 7.14371e-12 max error: 0.000120278 error ratio: 8.07497 Cycle 3 Number of degrees of freedom: 4225 DEAL:0:cg::Starting value 131.732 -DEAL:0:cg::Convergence step 6 value 1.31602e-12 +DEAL:0:cg::Convergence step 7 value 1.44204e-11 max error: 1.49228e-05 error ratio: 8.05998 Cycle 4 Number of degrees of freedom: 16641 DEAL:0:cg::Starting value 183.473 -DEAL:0:cg::Convergence step 6 value 2.60867e-12 +DEAL:0:cg::Convergence step 7 value 2.54095e-11 max error: 1.85713e-06 error ratio: 8.03544 Cycle 5 Number of degrees of freedom: 66049 DEAL:0:cg::Starting value 257.379 -DEAL:0:cg::Convergence step 6 value 4.17156e-12 +DEAL:0:cg::Convergence step 7 value 3.94318e-11 max error: 2.31590e-07 error ratio: 8.01904 Cycle 0 Number of degrees of freedom: 125 DEAL:0:cg::Starting value 6.44073 -DEAL:0:cg::Convergence step 6 value 2.97002e-14 +DEAL:0:cg::Convergence step 7 value 4.64523e-13 max error: 0.0499110 error ratio: 1.00000 Cycle 1 Number of degrees of freedom: 729 DEAL:0:cg::Starting value 8.68642 -DEAL:0:cg::Convergence step 6 value 6.80139e-14 +DEAL:0:cg::Convergence step 7 value 5.79753e-13 max error: 0.00756448 error ratio: 6.59807 Cycle 2 Number of degrees of freedom: 4913 DEAL:0:cg::Starting value 9.47362 -DEAL:0:cg::Convergence step 6 value 6.56927e-14 +DEAL:0:cg::Convergence step 7 value 6.67651e-13 max error: 0.000965192 error ratio: 7.83728 Cycle 3 Number of degrees of freedom: 35937 DEAL:0:cg::Starting value 9.30402 -DEAL:0:cg::Convergence step 6 value 7.06917e-14 +DEAL:0:cg::Convergence step 7 value 9.36336e-13 max error: 0.000120048 error ratio: 8.04008 Cycle 4 Number of degrees of freedom: 274625 DEAL:0:cg::Starting value 8.99023 -DEAL:0:cg::Convergence step 6 value 8.15983e-14 +DEAL:0:cg::Convergence step 7 value 1.22268e-12 max error: 1.49140e-05 error ratio: 8.04933 DEAL:1:cg::Starting value 45.0807 -DEAL:1:cg::Convergence step 6 value 2.23481e-13 +DEAL:1:cg::Convergence step 7 value 2.65304e-12 DEAL:1:cg::Starting value 68.5863 -DEAL:1:cg::Convergence step 6 value 4.06929e-13 +DEAL:1:cg::Convergence step 7 value 3.81082e-12 DEAL:1:cg::Starting value 95.4381 -DEAL:1:cg::Convergence step 6 value 5.78305e-13 +DEAL:1:cg::Convergence step 7 value 7.14371e-12 DEAL:1:cg::Starting value 131.732 -DEAL:1:cg::Convergence step 6 value 1.31602e-12 +DEAL:1:cg::Convergence step 7 value 1.44204e-11 DEAL:1:cg::Starting value 183.473 -DEAL:1:cg::Convergence step 6 value 2.60867e-12 +DEAL:1:cg::Convergence step 7 value 2.54095e-11 DEAL:1:cg::Starting value 257.379 -DEAL:1:cg::Convergence step 6 value 4.17156e-12 +DEAL:1:cg::Convergence step 7 value 3.94318e-11 DEAL:1:cg::Starting value 6.44073 -DEAL:1:cg::Convergence step 6 value 2.97002e-14 +DEAL:1:cg::Convergence step 7 value 4.64523e-13 DEAL:1:cg::Starting value 8.68642 -DEAL:1:cg::Convergence step 6 value 6.80139e-14 +DEAL:1:cg::Convergence step 7 value 5.79753e-13 DEAL:1:cg::Starting value 9.47362 -DEAL:1:cg::Convergence step 6 value 6.56927e-14 +DEAL:1:cg::Convergence step 7 value 6.67651e-13 DEAL:1:cg::Starting value 9.30402 -DEAL:1:cg::Convergence step 6 value 7.06917e-14 +DEAL:1:cg::Convergence step 7 value 9.36336e-13 DEAL:1:cg::Starting value 8.99023 -DEAL:1:cg::Convergence step 6 value 8.15983e-14 +DEAL:1:cg::Convergence step 7 value 1.22268e-12 DEAL:2:cg::Starting value 45.0807 -DEAL:2:cg::Convergence step 6 value 2.23481e-13 +DEAL:2:cg::Convergence step 7 value 2.65304e-12 DEAL:2:cg::Starting value 68.5863 -DEAL:2:cg::Convergence step 6 value 4.06929e-13 +DEAL:2:cg::Convergence step 7 value 3.81082e-12 DEAL:2:cg::Starting value 95.4381 -DEAL:2:cg::Convergence step 6 value 5.78305e-13 +DEAL:2:cg::Convergence step 7 value 7.14371e-12 DEAL:2:cg::Starting value 131.732 -DEAL:2:cg::Convergence step 6 value 1.31602e-12 +DEAL:2:cg::Convergence step 7 value 1.44204e-11 DEAL:2:cg::Starting value 183.473 -DEAL:2:cg::Convergence step 6 value 2.60867e-12 +DEAL:2:cg::Convergence step 7 value 2.54095e-11 DEAL:2:cg::Starting value 257.379 -DEAL:2:cg::Convergence step 6 value 4.17156e-12 +DEAL:2:cg::Convergence step 7 value 3.94318e-11 DEAL:2:cg::Starting value 6.44073 -DEAL:2:cg::Convergence step 6 value 2.97002e-14 +DEAL:2:cg::Convergence step 7 value 4.64523e-13 DEAL:2:cg::Starting value 8.68642 -DEAL:2:cg::Convergence step 6 value 6.80139e-14 +DEAL:2:cg::Convergence step 7 value 5.79753e-13 DEAL:2:cg::Starting value 9.47362 -DEAL:2:cg::Convergence step 6 value 6.56927e-14 +DEAL:2:cg::Convergence step 7 value 6.67651e-13 DEAL:2:cg::Starting value 9.30402 -DEAL:2:cg::Convergence step 6 value 7.06917e-14 +DEAL:2:cg::Convergence step 7 value 9.36336e-13 DEAL:2:cg::Starting value 8.99023 -DEAL:2:cg::Convergence step 6 value 8.15983e-14 +DEAL:2:cg::Convergence step 7 value 1.22268e-12 DEAL:3:cg::Starting value 45.0807 -DEAL:3:cg::Convergence step 6 value 2.23481e-13 +DEAL:3:cg::Convergence step 7 value 2.65304e-12 DEAL:3:cg::Starting value 68.5863 -DEAL:3:cg::Convergence step 6 value 4.06929e-13 +DEAL:3:cg::Convergence step 7 value 3.81082e-12 DEAL:3:cg::Starting value 95.4381 -DEAL:3:cg::Convergence step 6 value 5.78305e-13 +DEAL:3:cg::Convergence step 7 value 7.14371e-12 DEAL:3:cg::Starting value 131.732 -DEAL:3:cg::Convergence step 6 value 1.31602e-12 +DEAL:3:cg::Convergence step 7 value 1.44204e-11 DEAL:3:cg::Starting value 183.473 -DEAL:3:cg::Convergence step 6 value 2.60867e-12 +DEAL:3:cg::Convergence step 7 value 2.54095e-11 DEAL:3:cg::Starting value 257.379 -DEAL:3:cg::Convergence step 6 value 4.17156e-12 +DEAL:3:cg::Convergence step 7 value 3.94318e-11 DEAL:3:cg::Starting value 6.44073 -DEAL:3:cg::Convergence step 6 value 2.97002e-14 +DEAL:3:cg::Convergence step 7 value 4.64523e-13 DEAL:3:cg::Starting value 8.68642 -DEAL:3:cg::Convergence step 6 value 6.80139e-14 +DEAL:3:cg::Convergence step 7 value 5.79753e-13 DEAL:3:cg::Starting value 9.47362 -DEAL:3:cg::Convergence step 6 value 6.56927e-14 +DEAL:3:cg::Convergence step 7 value 6.67651e-13 DEAL:3:cg::Starting value 9.30402 -DEAL:3:cg::Convergence step 6 value 7.06917e-14 +DEAL:3:cg::Convergence step 7 value 9.36336e-13 DEAL:3:cg::Starting value 8.99023 -DEAL:3:cg::Convergence step 6 value 8.15983e-14 +DEAL:3:cg::Convergence step 7 value 1.22268e-12 diff --git a/tests/matrix_free/step-37.with_lapack=true.output b/tests/matrix_free/step-37.with_lapack=true.output index f67b52a7ea0b..d4c371622ad2 100644 --- a/tests/matrix_free/step-37.with_lapack=true.output +++ b/tests/matrix_free/step-37.with_lapack=true.output @@ -2,30 +2,30 @@ DEAL:2d::Cycle 0 DEAL:2d::Number of degrees of freedom: 81 DEAL:2d:cg::Starting value 0.132 -DEAL:2d:cg::Convergence step 4 value 0 +DEAL:2d:cg::Convergence step 5 value 4.87e-15 DEAL:2d:: DEAL:2d::Cycle 1 DEAL:2d::Number of degrees of freedom: 289 DEAL:2d:cg::Starting value 0.0677 -DEAL:2d:cg::Convergence step 5 value 0 +DEAL:2d:cg::Convergence step 5 value 6.38e-14 DEAL:2d:: DEAL:2d::Cycle 2 DEAL:2d::Number of degrees of freedom: 1089 DEAL:2d:cg::Starting value 0.0343 -DEAL:2d:cg::Convergence step 5 value 0 +DEAL:2d:cg::Convergence step 6 value 8.43e-16 DEAL:2d:: DEAL:3d::Cycle 0 DEAL:3d::Number of degrees of freedom: 125 DEAL:3d:cg::Starting value 0.125 -DEAL:3d:cg::Convergence step 5 value 0 +DEAL:3d:cg::Convergence step 4 value 2.35e-14 DEAL:3d:: DEAL:3d::Cycle 1 DEAL:3d::Number of degrees of freedom: 729 DEAL:3d:cg::Starting value 0.0479 -DEAL:3d:cg::Convergence step 4 value 0 +DEAL:3d:cg::Convergence step 5 value 1.75e-17 DEAL:3d:: DEAL:3d::Cycle 2 DEAL:3d::Number of degrees of freedom: 4913 DEAL:3d:cg::Starting value 0.0176 -DEAL:3d:cg::Convergence step 4 value 0 +DEAL:3d:cg::Convergence step 5 value 1.68e-16 DEAL:3d:: diff --git a/tests/matrix_free/stokes_computation.with_mpi=true.with_p4est=true.mpirun=4.output b/tests/matrix_free/stokes_computation.with_mpi=true.with_p4est=true.mpirun=4.output index c33433cf2546..1f2687b42cdf 100644 --- a/tests/matrix_free/stokes_computation.with_mpi=true.with_p4est=true.mpirun=4.output +++ b/tests/matrix_free/stokes_computation.with_mpi=true.with_p4est=true.mpirun=4.output @@ -4,16 +4,16 @@ DEAL:2d::n_sinker: 4 max/min viscosity ratio: 1000.00 DEAL:2d:: DEAL:2d::Number of active cells: 1024 (on 6 levels) DEAL:2d::Number of degrees of freedom: 9539 (8450+1089) -DEAL:2d::Solved-in 62 iterations, final residual: 5.37736e-08 +DEAL:2d::Solved-in 69 iterations, final residual: 5.58979e-08 DEAL:2d:: DEAL:2d::Number of active cells: 4096 (on 7 levels) DEAL:2d::Number of degrees of freedom: 37507 (33282+4225) -DEAL:2d::Solved-in 61 iterations, final residual: 2.94930e-08 +DEAL:2d::Solved-in 69 iterations, final residual: 2.58019e-08 DEAL:2d:: DEAL:3d::Sinker problem in 3D. DEAL:3d::n_sinker: 4 max/min viscosity ratio: 1000.00 DEAL:3d:: DEAL:3d::Number of active cells: 512 (on 4 levels) DEAL:3d::Number of degrees of freedom: 15468 (14739+729) -DEAL:3d::Solved-in 54 iterations, final residual: 2.12652e-08 +DEAL:3d::Solved-in 62 iterations, final residual: 1.99453e-08 DEAL:3d:: diff --git a/tests/multigrid/step-16-04.cc b/tests/multigrid/step-16-04.cc index 39ddbad30c97..631b29fba58b 100644 --- a/tests/multigrid/step-16-04.cc +++ b/tests/multigrid/step-16-04.cc @@ -397,7 +397,7 @@ LaplaceProblem::solve() mg_smoother; typename Smoother::AdditionalData smoother_data; smoother_data.smoothing_range = 20.; - smoother_data.degree = 2; + smoother_data.degree = 3; smoother_data.eig_cg_n_iterations = 20; mg_smoother.initialize(mg_matrices, smoother_data); diff --git a/tests/multigrid/step-16-05.cc b/tests/multigrid/step-16-05.cc index dd7057ae91d3..3b3441a98905 100644 --- a/tests/multigrid/step-16-05.cc +++ b/tests/multigrid/step-16-05.cc @@ -398,7 +398,7 @@ LaplaceProblem::solve() mg_smoother; typename Smoother::AdditionalData smoother_data; smoother_data.smoothing_range = 20.; - smoother_data.degree = 2; + smoother_data.degree = 3; smoother_data.eig_cg_n_iterations = 20; mg_smoother.initialize(mg_matrices, smoother_data); diff --git a/tests/multigrid/step-16-06.cc b/tests/multigrid/step-16-06.cc index aa46cd7dba8e..d6a90ea82440 100644 --- a/tests/multigrid/step-16-06.cc +++ b/tests/multigrid/step-16-06.cc @@ -398,7 +398,7 @@ LaplaceProblem::solve() mg_smoother; typename Smoother::AdditionalData smoother_data; smoother_data.smoothing_range = 20.; - smoother_data.degree = 2; + smoother_data.degree = 3; smoother_data.eig_cg_n_iterations = 20; mg_smoother.initialize(mg_matrices, smoother_data); diff --git a/tests/multigrid/step-16-50-serial.cc b/tests/multigrid/step-16-50-serial.cc index 736b86d15a93..baa48db33bb3 100644 --- a/tests/multigrid/step-16-50-serial.cc +++ b/tests/multigrid/step-16-50-serial.cc @@ -470,6 +470,7 @@ int main() { initlog(); + deallog << std::setprecision(10); try { diff --git a/tests/multigrid/step-16-50-serial.output b/tests/multigrid/step-16-50-serial.output index 3f3684cfb080..42daab35f86c 100644 --- a/tests/multigrid/step-16-50-serial.output +++ b/tests/multigrid/step-16-50-serial.output @@ -2,25 +2,25 @@ DEAL::Cycle 0: DEAL:: Number of active cells: 256 DEAL:: Number of degrees of freedom: 289 (by level: 4, 9, 25, 81, 289) -DEAL:cg::Starting value 0.585938 -DEAL:cg::Convergence step 7 value 4.58200e-09 +DEAL:cg::Starting value 0.5859375000 +DEAL:cg::Convergence step 7 value 4.581996212e-09 DEAL::Cycle 1: DEAL:: Number of active cells: 418 DEAL:: Number of degrees of freedom: 495 (by level: 4, 9, 25, 81, 289, 305) -DEAL:cg::Starting value 0.533937 -DEAL:cg::Convergence step 10 value 7.40543e-10 +DEAL:cg::Starting value 0.5339372772 +DEAL:cg::Convergence step 10 value 7.405430549e-10 DEAL::Cycle 2: DEAL:: Number of active cells: 865 DEAL:: Number of degrees of freedom: 952 (by level: 4, 9, 25, 81, 289, 769, 153) -DEAL:cg::Starting value 0.378780 -DEAL:cg::Convergence step 11 value 1.39894e-09 +DEAL:cg::Starting value 0.3787800687 +DEAL:cg::Convergence step 11 value 1.398936158e-09 DEAL::Cycle 3: DEAL:: Number of active cells: 1219 DEAL:: Number of degrees of freedom: 1354 (by level: 4, 9, 25, 81, 289, 953, 277, 261) -DEAL:cg::Starting value 0.343729 -DEAL:cg::Convergence step 13 value 6.16552e-10 +DEAL:cg::Starting value 0.3437292109 +DEAL:cg::Convergence step 13 value 6.165515097e-10 DEAL::Cycle 4: DEAL:: Number of active cells: 1297 DEAL:: Number of degrees of freedom: 1446 (by level: 4, 9, 25, 81, 289, 961, 313, 349) -DEAL:cg::Starting value 0.339440 -DEAL:cg::Convergence step 13 value 7.00850e-10 +DEAL:cg::Starting value 0.3394403283 +DEAL:cg::Convergence step 13 value 7.008502779e-10 From 13c5efbcede00de082417c32f23925cd46b5afb3 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Fri, 8 Feb 2019 16:33:10 +0100 Subject: [PATCH 080/507] Add changelog. --- doc/news/changes/minor/20190208MartinKronbichler | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 doc/news/changes/minor/20190208MartinKronbichler 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) From 8fb857bde477c48e3db19a59875261e73502719b Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Fri, 8 Feb 2019 16:37:18 +0100 Subject: [PATCH 081/507] Add default constructor to SparsityPatternIterators::Accessor --- doc/news/changes/minor/20190208DenisDavydov | 3 +++ include/deal.II/lac/sparsity_pattern.h | 26 +++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 doc/news/changes/minor/20190208DenisDavydov 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/include/deal.II/lac/sparsity_pattern.h b/include/deal.II/lac/sparsity_pattern.h index 4182a1fd7349..89c507a31e16 100644 --- a/include/deal.II/lac/sparsity_pattern.h +++ b/include/deal.II/lac/sparsity_pattern.h @@ -146,6 +146,13 @@ namespace SparsityPatternIterators */ Accessor(const SparsityPattern *matrix); + /** + * Default constructor creating a dummy accessor. This constructor is here + * only to be able to store accessors in STL containers such as + * `std::vector`. + */ + Accessor(); + /** * Row number of the element represented by this object. This function can * only be called for entries for which is_valid_entry() is true. @@ -209,6 +216,12 @@ namespace SparsityPatternIterators operator<(const Accessor &) const; protected: + DeclExceptionMsg(DummyAccessor, + "The instance of this class was initialized" + " without SparsityPattern object, which" + " means that it is a dummy accessor that can" + " not do any operations."); + /** * The sparsity pattern we operate on accessed. */ @@ -1162,9 +1175,17 @@ namespace SparsityPatternIterators + inline Accessor::Accessor() + : container(nullptr) + , linear_index(numbers::invalid_size_type) + {} + + + inline bool Accessor::is_valid_entry() const { + Assert(container != nullptr, DummyAccessor()); return (linear_index < container->rowstart[container->rows] && container->colnums[linear_index] != SparsityPattern::invalid_entry); } @@ -1218,6 +1239,8 @@ namespace SparsityPatternIterators inline bool Accessor::operator==(const Accessor &other) const { + Assert(container != nullptr, DummyAccessor()); + Assert(other.container != nullptr, DummyAccessor()); return (container == other.container && linear_index == other.linear_index); } @@ -1226,6 +1249,8 @@ namespace SparsityPatternIterators inline bool Accessor::operator<(const Accessor &other) const { + Assert(container != nullptr, DummyAccessor()); + Assert(other.container != nullptr, DummyAccessor()); Assert(container == other.container, ExcInternalError()); return linear_index < other.linear_index; @@ -1236,6 +1261,7 @@ namespace SparsityPatternIterators inline void Accessor::advance() { + Assert(container != nullptr, DummyAccessor()); Assert(linear_index < container->rowstart[container->rows], ExcIteratorPastEnd()); ++linear_index; From 05d5673e3adf15c9844760ea9561e63b0bb82dcd Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Wed, 6 Feb 2019 12:53:20 +0100 Subject: [PATCH 082/507] Avoid underflow in MF::ShapeInfo for very large number of q points. --- .../matrix_free/shape_info.templates.h | 83 ++++++++++--------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/include/deal.II/matrix_free/shape_info.templates.h b/include/deal.II/matrix_free/shape_info.templates.h index 18ed6fba80fe..af18d30c80d5 100644 --- a/include/deal.II/matrix_free/shape_info.templates.h +++ b/include/deal.II/matrix_free/shape_info.templates.h @@ -266,44 +266,51 @@ namespace internal } // get gradient and Hessian transformation matrix for the polynomial - // space associated with the quadrature rule (collocation space) - { - const unsigned int stride = (n_q_points_1d + 1) / 2; - shape_gradients_collocation_eo.resize(n_q_points_1d * stride); - shape_hessians_collocation_eo.resize(n_q_points_1d * stride); - FE_DGQArbitraryNodes<1> fe(quad.get_points()); - for (unsigned int i = 0; i < n_q_points_1d / 2; ++i) - for (unsigned int q = 0; q < stride; ++q) - { - shape_gradients_collocation_eo[i * stride + q] = - 0.5 * - (fe.shape_grad(i, quad.get_points()[q])[0] + - fe.shape_grad(i, quad.get_points()[n_q_points_1d - 1 - q])[0]); - shape_gradients_collocation_eo[(n_q_points_1d - 1 - i) * stride + - q] = - 0.5 * - (fe.shape_grad(i, quad.get_points()[q])[0] - - fe.shape_grad(i, quad.get_points()[n_q_points_1d - 1 - q])[0]); - shape_hessians_collocation_eo[i * stride + q] = - 0.5 * (fe.shape_grad_grad(i, quad.get_points()[q])[0][0] + - fe.shape_grad_grad( - i, quad.get_points()[n_q_points_1d - 1 - q])[0][0]); - shape_hessians_collocation_eo[(n_q_points_1d - 1 - i) * stride + - q] = - 0.5 * (fe.shape_grad_grad(i, quad.get_points()[q])[0][0] - - fe.shape_grad_grad( - i, quad.get_points()[n_q_points_1d - 1 - q])[0][0]); - } - if (n_q_points_1d % 2 == 1) - for (unsigned int q = 0; q < stride; ++q) - { - shape_gradients_collocation_eo[n_q_points_1d / 2 * stride + q] = - fe.shape_grad(n_q_points_1d / 2, quad.get_points()[q])[0]; - shape_hessians_collocation_eo[n_q_points_1d / 2 * stride + q] = - fe.shape_grad_grad(n_q_points_1d / 2, - quad.get_points()[q])[0][0]; - } - } + // space associated with the quadrature rule (collocation space). We + // need to avoid the case with more than a few hundreds of quadrature + // points when the Lagrange polynomials constructed in + // FE_DGQArbitraryNodes underflow. + if (n_q_points_1d < 200) + { + const unsigned int stride = (n_q_points_1d + 1) / 2; + shape_gradients_collocation_eo.resize(n_q_points_1d * stride); + shape_hessians_collocation_eo.resize(n_q_points_1d * stride); + FE_DGQArbitraryNodes<1> fe(quad.get_points()); + for (unsigned int i = 0; i < n_q_points_1d / 2; ++i) + for (unsigned int q = 0; q < stride; ++q) + { + shape_gradients_collocation_eo[i * stride + q] = + 0.5 * + (fe.shape_grad(i, quad.get_points()[q])[0] + + fe.shape_grad(i, + quad.get_points()[n_q_points_1d - 1 - q])[0]); + shape_gradients_collocation_eo[(n_q_points_1d - 1 - i) * + stride + + q] = + 0.5 * + (fe.shape_grad(i, quad.get_points()[q])[0] - + fe.shape_grad(i, + quad.get_points()[n_q_points_1d - 1 - q])[0]); + shape_hessians_collocation_eo[i * stride + q] = + 0.5 * (fe.shape_grad_grad(i, quad.get_points()[q])[0][0] + + fe.shape_grad_grad( + i, quad.get_points()[n_q_points_1d - 1 - q])[0][0]); + shape_hessians_collocation_eo[(n_q_points_1d - 1 - i) * stride + + q] = + 0.5 * (fe.shape_grad_grad(i, quad.get_points()[q])[0][0] - + fe.shape_grad_grad( + i, quad.get_points()[n_q_points_1d - 1 - q])[0][0]); + } + if (n_q_points_1d % 2 == 1) + for (unsigned int q = 0; q < stride; ++q) + { + shape_gradients_collocation_eo[n_q_points_1d / 2 * stride + q] = + fe.shape_grad(n_q_points_1d / 2, quad.get_points()[q])[0]; + shape_hessians_collocation_eo[n_q_points_1d / 2 * stride + q] = + fe.shape_grad_grad(n_q_points_1d / 2, + quad.get_points()[q])[0][0]; + } + } if (element_type == tensor_general && check_1d_shapes_symmetric(n_q_points_1d)) From 856007a732bef1484b2eb540714e9c78b2ad3c08 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Wed, 6 Feb 2019 12:53:59 +0100 Subject: [PATCH 083/507] Do not use transformation to collocation for large n_q_points. --- .../deal.II/matrix_free/evaluation_kernels.h | 14 +++++- .../deal.II/matrix_free/evaluation_selector.h | 44 ++++++++++++++----- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/include/deal.II/matrix_free/evaluation_kernels.h b/include/deal.II/matrix_free/evaluation_kernels.h index 7cfa435b6ad3..3f47fbe06eb1 100644 --- a/include/deal.II/matrix_free/evaluation_kernels.h +++ b/include/deal.II/matrix_free/evaluation_kernels.h @@ -1337,6 +1337,16 @@ namespace internal typename Number> struct FEFaceEvaluationImpl { + // We enable a transformation to collocation for derivatives if it gives + // correct results (first two conditions), if it is the most efficient + // choice in terms of operation counts (third condition) and if we were + // able to initialize the fields in shape_info.templates.h from the + // polynomials (fourth condition). + static constexpr bool use_collocation = + symmetric_evaluate && + n_q_points_1d > fe_degree &&n_q_points_1d <= 3 * fe_degree / 2 + 1 && + n_q_points_1d < 200; + static void evaluate_in_face(const MatrixFreeFunctions::ShapeInfo &data, Number * values_dofs, @@ -1431,7 +1441,7 @@ namespace internal switch (dim) { case 3: - if (symmetric_evaluate && n_q_points_1d > fe_degree) + if (use_collocation) { eval1.template values<0, true, false>(values_dofs, values_quad); @@ -1590,7 +1600,7 @@ namespace internal 2 * n_q_points); eval1.template values<0, false, false>( gradients_quad + 2 * n_q_points, values_dofs + size_deg); - if (symmetric_evaluate && n_q_points_1d > fe_degree) + if (use_collocation) { internal::EvaluatorTensorProduct< internal::evaluate_evenodd, diff --git a/include/deal.II/matrix_free/evaluation_selector.h b/include/deal.II/matrix_free/evaluation_selector.h index 2fd382aa0647..30115e481be1 100644 --- a/include/deal.II/matrix_free/evaluation_selector.h +++ b/include/deal.II/matrix_free/evaluation_selector.h @@ -251,6 +251,17 @@ namespace internal n_q_points_1d, typename std::enable_if<(n_q_points_1d < degree + 3)>::type> { + /** + * We enable a transformation to collocation for derivatives if it gives + * correct results (first condition), if it is the most efficient choice + * in terms of operation counts (second condition) and if we were able + * to initialize the fields in shape_info.templates.h from the + * polynomials (third condition). + */ + static constexpr bool use_collocation = + n_q_points_1d > degree &&n_q_points_1d <= 3 * degree / 2 + 1 && + n_q_points_1d < 200; + static inline void evaluate( const internal::MatrixFreeFunctions::ShapeInfo &shape_info, @@ -280,7 +291,7 @@ namespace internal evaluate_values, evaluate_gradients, evaluate_hessians); - else if (degree < n_q_points_1d) + else if (use_collocation) internal::FEEvaluationImplTransformToCollocation< dim, degree, @@ -352,7 +363,7 @@ namespace internal integrate_values, integrate_gradients, sum_into_values_array); - else if (degree < n_q_points_1d) + else if (use_collocation) internal::FEEvaluationImplTransformToCollocation< dim, degree, @@ -481,6 +492,17 @@ template struct SelectEvaluator { + /** + * We enable a transformation to collocation for derivatives if it gives + * correct results (first condition), if it is the most efficient choice in + * terms of operation counts (second condition) and if we were able to + * initialize the fields in shape_info.templates.h from the polynomials + * (third condition). + */ + static constexpr bool use_collocation = + n_q_points_1d > fe_degree &&n_q_points_1d <= 3 * fe_degree / 2 + 1 && + n_q_points_1d < 200; + /** * Chooses an appropriate evaluation strategy for the evaluate function, i.e. * this calls internal::FEEvaluationImpl::evaluate(), @@ -606,9 +628,10 @@ SelectEvaluator::evaluate( evaluate_gradients, evaluate_hessians); } - else if (fe_degree < n_q_points_1d && - shape_info.element_type <= - internal::MatrixFreeFunctions::tensor_symmetric) + // '<=' on type means tensor_symmetric or tensor_symmetric_hermite, see + // shape_info.h for more details + else if (use_collocation && shape_info.element_type <= + internal::MatrixFreeFunctions::tensor_symmetric) { internal::FEEvaluationImplTransformToCollocation< dim, @@ -625,7 +648,7 @@ SelectEvaluator::evaluate( evaluate_gradients, evaluate_hessians); } - else if (shape_info.element_type == + else if (shape_info.element_type <= internal::MatrixFreeFunctions::tensor_symmetric) { internal::FEEvaluationImpl< @@ -739,9 +762,10 @@ SelectEvaluator::integrate( integrate_gradients, sum_into_values_array); } - else if (fe_degree < n_q_points_1d && - shape_info.element_type <= - internal::MatrixFreeFunctions::tensor_symmetric) + // '<=' on type means tensor_symmetric or tensor_symmetric_hermite, see + // shape_info.h for more details + else if (use_collocation && shape_info.element_type <= + internal::MatrixFreeFunctions::tensor_symmetric) { internal::FEEvaluationImplTransformToCollocation< dim, @@ -757,7 +781,7 @@ SelectEvaluator::integrate( integrate_gradients, sum_into_values_array); } - else if (shape_info.element_type == + else if (shape_info.element_type <= internal::MatrixFreeFunctions::tensor_symmetric) { internal::FEEvaluationImpl< From 054d440c7b363f2000a62d5b04238acdea09692d Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Wed, 6 Feb 2019 12:54:07 +0100 Subject: [PATCH 084/507] Add changelog. --- doc/news/changes/minor/20190206MartinKronbichler | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 doc/news/changes/minor/20190206MartinKronbichler 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) From 0e6ce56b46adbe4c05ecfe39e8871937ee1de210 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Wed, 6 Feb 2019 12:55:09 +0100 Subject: [PATCH 085/507] Add test case --- .../matrix_vector_large_degree_03.cc | 140 ++++++++++++++++++ .../matrix_vector_large_degree_03.output | 7 + 2 files changed, 147 insertions(+) create mode 100644 tests/matrix_free/matrix_vector_large_degree_03.cc create mode 100644 tests/matrix_free/matrix_vector_large_degree_03.output diff --git a/tests/matrix_free/matrix_vector_large_degree_03.cc b/tests/matrix_free/matrix_vector_large_degree_03.cc new file mode 100644 index 000000000000..36e945ab9ef9 --- /dev/null +++ b/tests/matrix_free/matrix_vector_large_degree_03.cc @@ -0,0 +1,140 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2017 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. +// +// --------------------------------------------------------------------- + + + +// test that FEEvaluation can correctly handle large polynomial degrees of 20 +// with 100, 200, 500 and 1000 quadrature points per direction in 2D. Since we +// have a constant-coefficient Laplacian, we can verify the implementation by +// comparing to the result with 21 quadrature points. + +#include "../tests.h" + +std::ofstream logfile("output"); + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include "matrix_vector_mf.h" + + +template +void +test() +{ + Triangulation tria; + GridGenerator::hyper_cube(tria); + tria.refine_global(1); + + FE_Q fe(fe_degree); + DoFHandler dof(tria); + dof.distribute_dofs(fe); + AffineConstraints constraints; + constraints.close(); + + deallog << "Testing " << dof.get_fe().get_name() << std::endl; + + Vector in(dof.n_dofs()), out(dof.n_dofs()), ref(dof.n_dofs()); + + for (unsigned int i = 0; i < dof.n_dofs(); ++i) + { + if (constraints.is_constrained(i)) + continue; + in(i) = static_cast(i % 13) / 11.; + } + + { + MatrixFree mf_data; + { + const QGauss<1> quad(fe_degree + 1); + typename MatrixFree::AdditionalData data; + data.tasks_parallel_scheme = + MatrixFree::AdditionalData::none; + mf_data.reinit(dof, constraints, quad, data); + } + + MatrixFreeTest, fe_degree + 1> mf( + mf_data); + mf.vmult(ref, in); + } + + typename MatrixFree::AdditionalData data; + data.tasks_parallel_scheme = MatrixFree::AdditionalData::none; + MatrixFree mf_data; + + { + mf_data.reinit(dof, constraints, QGauss<1>(fe_degree + 2), data); + MatrixFreeTest, fe_degree + 2> mf( + mf_data); + mf.vmult(out, in); + out -= ref; + deallog << "Error with " << fe_degree + 2 << "^" << dim + << " quadrature points: " << out.l2_norm() << std::endl; + } + + // unfortunately we cannot use for loops due to the template, so duplicate + // some code here + { + mf_data.reinit(dof, constraints, QGauss<1>(100), data); + MatrixFreeTest, 100> mf(mf_data); + mf.vmult(out, in); + out -= ref; + deallog << "Error with " << 100 << "^" << dim + << " quadrature points: " << out.l2_norm() << std::endl; + } + { + mf_data.reinit(dof, constraints, QGauss<1>(200), data); + MatrixFreeTest, 200> mf(mf_data); + mf.vmult(out, in); + out -= ref; + deallog << "Error with " << 200 << "^" << dim + << " quadrature points: " << out.l2_norm() << std::endl; + } + { + mf_data.reinit(dof, constraints, QGauss<1>(500), data); + MatrixFreeTest, 500> mf(mf_data); + mf.vmult(out, in); + out -= ref; + deallog << "Error with " << 500 << "^" << dim + << " quadrature points: " << out.l2_norm() << std::endl; + } + { + mf_data.reinit(dof, constraints, QGauss<1>(1000), data); + MatrixFreeTest, 1000> mf(mf_data); + mf.vmult(out, in); + out -= ref; + deallog << "Error with " << 1000 << "^" << dim + << " quadrature points: " << out.l2_norm() << std::endl; + } +} + + + +int +main() +{ + initlog(); + + test<2, 20>(); +} diff --git a/tests/matrix_free/matrix_vector_large_degree_03.output b/tests/matrix_free/matrix_vector_large_degree_03.output new file mode 100644 index 000000000000..d5272b9136b3 --- /dev/null +++ b/tests/matrix_free/matrix_vector_large_degree_03.output @@ -0,0 +1,7 @@ + +DEAL::Testing FE_Q<2>(20) +DEAL::Error with 22^2 quadrature points: 7.12679e-13 +DEAL::Error with 100^2 quadrature points: 3.09514e-13 +DEAL::Error with 200^2 quadrature points: 3.05924e-13 +DEAL::Error with 500^2 quadrature points: 3.28960e-13 +DEAL::Error with 1000^2 quadrature points: 3.39364e-13 From efcbebec5ef0c0ce1ddaa324df9a6965726f3392 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Sat, 9 Feb 2019 11:44:41 +0100 Subject: [PATCH 086/507] Comment on <= comparison for MatrixFree::ElementType. --- include/deal.II/matrix_free/shape_info.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/deal.II/matrix_free/shape_info.h b/include/deal.II/matrix_free/shape_info.h index 9533c9c94d4c..89c1f2902d0f 100644 --- a/include/deal.II/matrix_free/shape_info.h +++ b/include/deal.II/matrix_free/shape_info.h @@ -36,6 +36,15 @@ namespace internal * initialization. FEEvaluation will select the most efficient algorithm * based on the given element type. * + * There is an implied ordering in the type ElementType::tensor_symmetric + * in the sense that both ElementType::tensor_symmetric_collocation and + * ElementType::tensor_symmetric_hermite are also of type + * ElementType::tensor_symmetric. Likewise, a configuration of type + * ElementType::tensor_symmetric is also of type + * ElementType::tensor_general. As a consequence, we support `<=` + * operations between the types with this sorting, but not against the + * even higher indexed types such as ElementType::truncated_tensor. + * * @ingroup matrixfree */ enum ElementType From 666d0580a97aa250c0ad1c2e2270e804189b8f12 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Sun, 10 Feb 2019 17:23:56 -0700 Subject: [PATCH 087/507] [CI]: cleanup workspaces, document, simplify tidy - tidy job: use only one agent - add documentation - add cleanup of workspace (otherwise we run out of disk space, yay) --- contrib/ci/Jenkinsfile.mark | 16 +++++++++++----- contrib/ci/Jenkinsfile.osx | 10 ++++++++++ contrib/ci/Jenkinsfile.tidy | 33 +++++++++++++++++---------------- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/contrib/ci/Jenkinsfile.mark b/contrib/ci/Jenkinsfile.mark index 37aa15478cd7..78f8e02c676c 100644 --- a/contrib/ci/Jenkinsfile.mark +++ b/contrib/ci/Jenkinsfile.mark @@ -1,10 +1,14 @@ #!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. +/* + +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: @@ -28,6 +32,8 @@ pipeline } } + post { cleanup { cleanWs() } } + stages { stage("check") diff --git a/contrib/ci/Jenkinsfile.osx b/contrib/ci/Jenkinsfile.osx index fbee05a7686f..5a404aabb774 100644 --- a/contrib/ci/Jenkinsfile.osx +++ b/contrib/ci/Jenkinsfile.osx @@ -1,5 +1,13 @@ #!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) @@ -19,6 +27,8 @@ pipeline } } + post { cleanup { cleanWs() } } + stages { stage("check") diff --git a/contrib/ci/Jenkinsfile.tidy b/contrib/ci/Jenkinsfile.tidy index 05c013482631..82d7e69a39f2 100644 --- a/contrib/ci/Jenkinsfile.tidy +++ b/contrib/ci/Jenkinsfile.tidy @@ -1,5 +1,13 @@ #!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) @@ -13,7 +21,15 @@ Settings to apply inside Jenkins: pipeline { - agent none + agent + { + docker + { + image 'tjhei/candi-base-clang' + } + } + + post { cleanup { cleanWs() } } stages { @@ -25,14 +41,6 @@ pipeline } } - agent - { - docker - { - image 'dealii/indent' - } - } - steps { githubNotify context: 'tidy', description: 'pending...', status: 'PENDING' @@ -56,13 +64,6 @@ pipeline stage('build') { - agent - { - docker - { - image 'tjhei/candi-base-clang' - } - } steps { timeout(time: 2, unit: 'HOURS') From 64e934f2579478844ae950ce2dc1ccf8f11d5a3a Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 11 Feb 2019 01:52:05 +0100 Subject: [PATCH 088/507] Remove warnings generated by step-61 --- examples/step-61/step-61.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/step-61/step-61.cc b/examples/step-61/step-61.cc index 90ed9c019bee..13866adf300f 100644 --- a/examples/step-61/step-61.cc +++ b/examples/step-61/step-61.cc @@ -113,6 +113,7 @@ class Coefficient : public TensorFunction<2, dim> Coefficient() : TensorFunction<2, dim>() {} + virtual void value_list(const std::vector> &points, std::vector> & values) const override; }; @@ -138,6 +139,7 @@ class BoundaryValues : public Function BoundaryValues() : Function(2) {} + virtual double value(const Point & p, const unsigned int component = 0) const override; }; @@ -156,8 +158,9 @@ class RightHandSide : public Function RightHandSide() : Function() {} + virtual double value(const Point & p, - const unsigned int component = 0) const; + const unsigned int component = 0) const override; }; template @@ -176,7 +179,8 @@ class Solution : public Function Solution() : Function(1) {} - virtual double value(const Point &p, const unsigned int) const; + + virtual double value(const Point &p, const unsigned int) const override; }; template @@ -194,6 +198,7 @@ class Velocity : public TensorFunction<1, dim> Velocity() : TensorFunction<1, dim>() {} + virtual Tensor<1, dim> value(const Point &p) const override; }; From 1cc8f8e0ba6fb442598ed2fa7801fb57383e2404 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Sun, 10 Feb 2019 21:47:30 -0700 Subject: [PATCH 089/507] Use the usual grammar for make targets. --- cmake/macros/macro_deal_ii_invoke_autopilot.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/macros/macro_deal_ii_invoke_autopilot.cmake b/cmake/macros/macro_deal_ii_invoke_autopilot.cmake index ca5a1c0832a9..e93e95a0cf75 100644 --- a/cmake/macros/macro_deal_ii_invoke_autopilot.cmake +++ b/cmake/macros/macro_deal_ii_invoke_autopilot.cmake @@ -148,7 +148,7 @@ MACRO(DEAL_II_INVOKE_AUTOPILOT) 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 "Switch CMAKE_BUILD_TYPE to Debug" + COMMENT "Switching CMAKE_BUILD_TYPE to Debug" VERBATIM ) ENDIF() @@ -159,7 +159,7 @@ MACRO(DEAL_II_INVOKE_AUTOPILOT) 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 "Switch CMAKE_BUILD_TYPE to Release" + COMMENT "Switching CMAKE_BUILD_TYPE to Release" VERBATIM ) ENDIF() From 53bdfa8752c64cca0e640034063d4237442bc7e1 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 9 Feb 2019 15:20:44 +0100 Subject: [PATCH 090/507] Add make_const_array_view --- doc/news/changes/minor/20190209Arndt | 3 ++ include/deal.II/base/array_view.h | 19 +++++++++++ tests/base/array_view_07.cc | 50 ++++++++++++++++++++++++++++ tests/base/array_view_07.output | 3 ++ 4 files changed, 75 insertions(+) create mode 100644 doc/news/changes/minor/20190209Arndt create mode 100644 tests/base/array_view_07.cc create mode 100644 tests/base/array_view_07.output diff --git a/doc/news/changes/minor/20190209Arndt b/doc/news/changes/minor/20190209Arndt new file mode 100644 index 000000000000..d8bdf8fff554 --- /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/include/deal.II/base/array_view.h b/include/deal.II/base/array_view.h index 9fdcbb3b6b20..130e693f4bef 100644 --- a/include/deal.II/base/array_view.h +++ b/include/deal.II/base/array_view.h @@ -1134,6 +1134,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/tests/base/array_view_07.cc b/tests/base/array_view_07.cc new file mode 100644 index 000000000000..06d844ad8d2a --- /dev/null +++ b/tests/base/array_view_07.cc @@ -0,0 +1,50 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2017 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. +// +// --------------------------------------------------------------------- + + +// test make_const_array_view + +#include + +#include "../tests.h" + +template +void +const_foo(const ArrayView> &view) +{ + AssertThrow(view[0][0] == 1, ExcInternalError()); + deallog << "OK" << std::endl; +} + +template +void +foo(const ArrayView> &view) +{ + AssertThrow(view[0][0] == 1, ExcInternalError()); + deallog << "OK" << std::endl; +} + +int +main() +{ + initlog(); + std::vector> v(1, std::vector(1, 1)); + // this doesn't work + // const_foo(make_array_view(v)); + const_foo(make_const_array_view(v)); + foo(make_array_view(v)); + // this doesn't work + // foo(make_const_array_view(v)); +} diff --git a/tests/base/array_view_07.output b/tests/base/array_view_07.output new file mode 100644 index 000000000000..8b3b075900ce --- /dev/null +++ b/tests/base/array_view_07.output @@ -0,0 +1,3 @@ + +DEAL::OK +DEAL::OK From 4c84273983e81741f8eb6e987159a4ed5909167d Mon Sep 17 00:00:00 2001 From: Giovanni Alzetta Date: Fri, 11 Jan 2019 20:16:45 +0100 Subject: [PATCH 091/507] NonMatching::coupling_matrix now also skips useless cells --- source/non_matching/coupling.cc | 169 +++++++++++++++++++++++--------- 1 file changed, 124 insertions(+), 45 deletions(-) diff --git a/source/non_matching/coupling.cc b/source/non_matching/coupling.cc index 6673a1af544d..d8d31cf2d3c9 100644 --- a/source/non_matching/coupling.cc +++ b/source/non_matching/coupling.cc @@ -40,6 +40,92 @@ DEAL_II_NAMESPACE_OPEN namespace NonMatching { + namespace internal + { + /** + * Given two triangulations, the first immersed inside the other, this + * function computes and returns the real-space quadrature points of the + * immersed triangulation. + * + * For reference: + * cache->triangulation() is the imbdedding triangulation, which contains + * immersed_dh->get_triangulation() the embedded triangulation + * + * Mapping and quadrature are those of this second triangulation. + * + * If the triangulation inside @p cache is parallel, only points lying over + * locally onwed cells are returned. This is why a vector of unsigned int + * is returned: it describes the indices of cells from the immersed + * triangulation which have been used (relative to a loop over al cells). If + * embedding triangulation is not parallel, all cells shall be used. + */ + template + std::pair>, std::vector> + qpoints_over_locally_owned_cells( + const GridTools::Cache &cache, + const DoFHandler & immersed_dh, + const Quadrature & quad, + const Mapping & immersed_mapping, + const bool tria_is_parallel) + { + const auto & immersed_fe = immersed_dh.get_fe(); + std::vector> points_over_local_cells; + // Keep track of which cells we actually used + std::vector used_cells_ids; + { + FEValues fe_v(immersed_mapping, + immersed_fe, + quad, + update_quadrature_points); + unsigned int cell_id = 0; + for (const auto &cell : immersed_dh.active_cell_iterators()) + { + bool use_cell = false; + if (tria_is_parallel) + { + const auto bbox = cell->bounding_box(); + std::vector, + typename Triangulation::active_cell_iterator>> + out_vals; + cache.get_cell_bounding_boxes_rtree().query( + boost::geometry::index::intersects(bbox), + std::back_inserter(out_vals)); + // Each bounding box corresponds to an active cell + // of the imbedding triangulation: we now check if + // the current cell, of the imbedded triangulation, + // overlaps a locally owned cell of the imbedding one + for (const auto &bbox_it : out_vals) + if (bbox_it.second->is_locally_owned()) + { + use_cell = true; + used_cells_ids.emplace_back(cell_id); + break; + } + } + else + // for sequential triangulations, simply use all cells + use_cell = true; + + if (use_cell) + { + // Reinitialize the cell and the fe_values + fe_v.reinit(cell); + const std::vector> &x_points = + fe_v.get_quadrature_points(); + + // Insert the points to the vector + points_over_local_cells.insert(points_over_local_cells.end(), + x_points.begin(), + x_points.end()); + } + ++cell_id; + } + } + return {std::move(points_over_local_cells), std::move(used_cells_ids)}; + } + } // namespace internal + template *>( + &space_dh.get_triangulation()) != nullptr); const auto &space_fe = space_dh.get_fe(); const auto &immersed_fe = immersed_dh.get_fe(); @@ -134,27 +223,13 @@ namespace NonMatching const unsigned int n_q_points = quad.size(); const unsigned int n_active_c = immersed_dh.get_triangulation().n_active_cells(); - std::vector> all_points(n_active_c * n_q_points); - { - FEValues fe_v(immersed_mapping, - immersed_fe, - quad, - update_quadrature_points); - unsigned int c = 0; - for (const auto &cell : immersed_dh.active_cell_iterators()) - { - // Reinitialize the cell and the fe_values - fe_v.reinit(cell); - const std::vector> &x_points = - fe_v.get_quadrature_points(); - - // Copy the points to the vector - std::copy(x_points.begin(), - x_points.end(), - all_points.begin() + c * n_q_points); - ++c; - } - } + + const auto qpoints_cells_data = internal::qpoints_over_locally_owned_cells( + cache, immersed_dh, quad, immersed_mapping, tria_is_parallel); + + const auto &points_over_local_cells = std::get<0>(qpoints_cells_data); + const auto &used_cells_ids = std::get<1>(qpoints_cells_data); + // [TODO]: when the add_entries_local_to_global below will implement // the version with the dof_mask, this should be uncommented. // @@ -177,7 +252,8 @@ namespace NonMatching // Get a list of outer cells, qpoints and maps. - const auto cpm = GridTools::compute_point_locations(cache, all_points); + const auto cpm = + GridTools::compute_point_locations(cache, points_over_local_cells); const auto &all_cells = std::get<0>(cpm); const auto &maps = std::get<2>(cpm); @@ -191,10 +267,15 @@ namespace NonMatching // the following index keeps track of the last id // where the current cell was inserted unsigned int last_id = std::numeric_limits::max(); + unsigned int cell_id; for (const unsigned int idx : maps[i]) { - // Find in which cell the point lies - unsigned int cell_id = idx / n_q_points; + // Find in which cell of immersed triangulation the point lies + if (tria_is_parallel) + cell_id = used_cells_ids[idx / n_q_points]; + else + cell_id = idx / n_q_points; + if (last_id != cell_id) { cell_sets[cell_id].insert(all_cells[i]); @@ -285,6 +366,10 @@ namespace NonMatching &immersed_dh.get_triangulation()) == nullptr), ExcNotImplemented()); + const bool tria_is_parallel = + (dynamic_cast *>( + &space_dh.get_triangulation()) != nullptr); + const auto &space_fe = space_dh.get_fe(); const auto &immersed_fe = immersed_dh.get_fe(); @@ -330,28 +415,16 @@ namespace NonMatching const unsigned int n_q_points = quad.size(); const unsigned int n_active_c = immersed_dh.get_triangulation().n_active_cells(); - std::vector> all_points(n_active_c * n_q_points); - // Collecting all points - { - unsigned int c = 0; - for (const auto &cell : immersed_dh.active_cell_iterators()) - { - // Reinitialize the cell and the fe_values - fe_v.reinit(cell); - const std::vector> &x_points = - fe_v.get_quadrature_points(); - - // Copy the points to the vector - std::copy(x_points.begin(), - x_points.end(), - all_points.begin() + c * n_q_points); - ++c; - } - } + const auto used_cells_data = internal::qpoints_over_locally_owned_cells( + cache, immersed_dh, quad, immersed_mapping, tria_is_parallel); + + const auto &points_over_local_cells = std::get<0>(used_cells_data); + const auto &used_cells_ids = std::get<1>(used_cells_data); // Get a list of outer cells, qpoints and maps. - const auto cpm = GridTools::compute_point_locations(cache, all_points); + const auto cpm = + GridTools::compute_point_locations(cache, points_over_local_cells); const auto &all_cells = std::get<0>(cpm); const auto &all_qpoints = std::get<1>(cpm); const auto &all_maps = std::get<2>(cpm); @@ -372,8 +445,14 @@ namespace NonMatching { // Find the index of the "owner" cell and qpoint // with regard to the immersed mesh - const unsigned int cell_id = all_maps[o][j] / n_q_points; - const unsigned int n_pt = all_maps[o][j] % n_q_points; + // Find in which cell of immersed triangulation the point lies + unsigned int cell_id; + if (tria_is_parallel) + cell_id = used_cells_ids[all_maps[o][j] / n_q_points]; + else + cell_id = all_maps[o][j] / n_q_points; + + const unsigned int n_pt = all_maps[o][j] % n_q_points; // If there are no cells, we just add our data if (cell_container[cell_id].empty()) From b74d9d5ac89674e4ed0627f51aa8e93d3035d0cf Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Mon, 11 Feb 2019 18:43:54 +0100 Subject: [PATCH 092/507] Improve some documentation --- include/deal.II/differentiation/ad/ad_helpers.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index ff94ee962f1b..ba21b90be59e 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -934,8 +934,9 @@ namespace Differentiation * auto-differentiable numbers. These are the independent * variables $\mathbf{X}$ about which the solution is linearized. * - * It is indicated to the AD library that operations performed with these - * numbers are to be tracked, so they are considered "sensitive" + * This function indicates to the AD library that implements the + * auto-differentiable number type that operations performed on these + * numbers are to be tracked so they are considered "sensitive" * variables. This is, therefore, the set of variables with which one * would then perform computations, and based on which one can then * extract both the value of the function and its derivatives with the From 33fe4a9974851ce841b1f3ce9300646498ec08c3 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Mon, 11 Feb 2019 18:44:32 +0100 Subject: [PATCH 093/507] Mark a function as constant. --- include/deal.II/differentiation/ad/ad_helpers.h | 2 +- source/differentiation/ad/ad_helpers.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index ba21b90be59e..61bb85daeb07 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -950,7 +950,7 @@ namespace Differentiation * @note For taped AD numbers, this operation is only valid in recording mode. */ const std::vector & - get_sensitive_dof_values(); + get_sensitive_dof_values() const; //@} diff --git a/source/differentiation/ad/ad_helpers.cc b/source/differentiation/ad/ad_helpers.cc index e259ab6019c6..98f90b0aedf6 100644 --- a/source/differentiation/ad/ad_helpers.cc +++ b/source/differentiation/ad/ad_helpers.cc @@ -738,7 +738,7 @@ namespace Differentiation const std::vector< typename ADHelperCellLevelBase::ad_type> & ADHelperCellLevelBase::get_sensitive_dof_values() + ScalarType>::get_sensitive_dof_values() const { if (ADNumberTraits::is_taped == true) { From bfe7446fa892c036d63b9aa3c259895fe03bafe5 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Mon, 11 Feb 2019 18:45:09 +0100 Subject: [PATCH 094/507] ADHelpers: Remove an unnecessary function --- .../deal.II/differentiation/ad/ad_helpers.h | 30 ------------------- source/differentiation/ad/ad_helpers.cc | 24 --------------- 2 files changed, 54 deletions(-) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index 61bb85daeb07..bf3ea90c62f3 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -954,36 +954,6 @@ namespace Differentiation //@} - /** - * @name Post-processing - */ - //@{ - - /* - * Return the complete set of degree of freedom values of - * auto-differentiable number type. These store the same scalar values as - * the independent variables $\mathbf{X}$ about which the solution is - * linearized. - * - * Operations performed with these numbers are not tracked by the AD, - * libraries so they are considered "non-sensitive" variables. - * The values of the components of the returned object are initialized to - * the values set with register_dof_values(). - * - * @return An array of auto-differentiable type numbers representing the - * local degree of freedom values. - * - * @note This function is not typically used within the context of automatic - * differentation computations, but can make performing substutitions in - * other post-processing computations more straight forward. - * - * @note For taped AD numbers, this operation is only valid outside recording mode. - */ - std::vector - get_non_sensitive_dof_values() const; - - //@} - /** * @name Operations specific to taped mode: Reusing tapes */ diff --git a/source/differentiation/ad/ad_helpers.cc b/source/differentiation/ad/ad_helpers.cc index 98f90b0aedf6..2c3a9a5a47bd 100644 --- a/source/differentiation/ad/ad_helpers.cc +++ b/source/differentiation/ad/ad_helpers.cc @@ -760,30 +760,6 @@ namespace Differentiation - template - std::vector< - typename ADHelperCellLevelBase::ad_type> - ADHelperCellLevelBase::get_non_sensitive_dof_values() const - { - if (ADNumberTraits::is_taped == true) - { - Assert(this->active_tape_index() != - Numbers::invalid_tape_index, - ExcMessage("Invalid tape index")); - } - - std::vector out(this->n_independent_variables(), - dealii::internal::NumberType::value( - 0.0)); - for (unsigned int i = 0; i < this->n_independent_variables(); ++i) - this->initialize_non_sensitive_independent_variable(i, out[i]); - - return out; - } - - - template void ADHelperCellLevelBase::set_dof_values( From 9bac38c6ecafe3da017b9b49b013bd603866dc94 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Mon, 11 Feb 2019 18:46:21 +0100 Subject: [PATCH 095/507] AD Helpers: Add some internal functions to assist when using Extractors --- .../deal.II/differentiation/ad/ad_helpers.h | 970 ++++++++++++++++++ 1 file changed, 970 insertions(+) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index bf3ea90c62f3..5460362a72bf 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -21,6 +21,8 @@ #if defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO) # include +# include +# include # include # include @@ -29,6 +31,8 @@ # include # include +# include + # include # include @@ -1647,6 +1651,972 @@ namespace Differentiation }; // class ADHelperResidualLinearization + + namespace internal + { + /** + * A helper struct that assists with the extraction of data associated + * with fields that are defined by FEExtractors. + */ + template + struct Extractor; + + + /** + * A helper struct that assists with the extraction of data associated + * with fields that are defined by FEExtractors. + * This particular specialization is for scalar fields. + */ + template + struct Extractor + { + /** + * The number of components of the field. + */ + static const unsigned int n_components = 1; + + /** + * The tensor rank of the field. + */ + static const unsigned int rank = 0; + + /** + * The tensor type associated with this field. + */ + template + using tensor_type = Tensor; + + static_assert( + n_components == tensor_type::n_independent_components, + "The number of components doesn't match that of the corresponding tensor type."); + static_assert( + rank == tensor_type::rank, + "The rank doesn't match that of the corresponding tensor type."); + + /** + * The value type associated with this field. + */ + // Note: FEValuesViews::Scalar::tensor_type is double, so we can't + // use it (FEValuesViews) in this context. + // In fact, sadly, all FEValuesViews objects expect doubles as value + // types. + template + using value_type = NumberType; + + /** + * The gradient type associated with this field. + */ + template + using gradient_type = Tensor; // NumberType; + + /** + * Return the first global component of this field. + */ + static inline unsigned int + first_component(const FEValuesExtractors::Scalar &extractor) + { + return extractor.component; + } + + /** + * Return a flag that indicates if the input @p unrolled_index + * corresponds to a symmetric component of the field. + * + * For a scalar field, the single component is defined + * to not have a symmetric counterpart. + */ + static bool + symmetric_component(const unsigned int unrolled_index) + { + (void)unrolled_index; + return false; + } + + /** + * Return the local unrolled component corresponding to + * @p column_offset entry of the @p table_indices. + * + * For a scalar field, the local component is always + * equal to zero. + */ + template + static IndexType + local_component(const TableIndices &table_indices, + const unsigned int column_offset) + { + Assert(column_offset <= rank_in, ExcInternalError()); + (void)table_indices; + (void)column_offset; + return 0; + } + }; + + + /** + * A helper struct that assists with the extraction of data associated + * with fields that are defined by FEExtractors. + * This particular specialization is for vector fields. + */ + template + struct Extractor + { + /** + * The number of components of the field. + */ + static const unsigned int n_components = dim; + + /** + * The tensor rank of the field. + */ + static const unsigned int rank = 1; + + /** + * The tensor type associated with this field. + */ + template + using tensor_type = Tensor; + + static_assert( + n_components == tensor_type::n_independent_components, + "The number of components doesn't match that of the corresponding tensor type."); + static_assert( + rank == tensor_type::rank, + "The rank doesn't match that of the corresponding tensor type."); + + /** + * The value type associated with this field. + */ + template + using value_type = tensor_type; + + /** + * The gradient type associated with this field. + */ + template + using gradient_type = Tensor; + + /** + * Return the first global component of this field. + */ + static inline unsigned int + first_component(const FEValuesExtractors::Vector &extractor) + { + return extractor.first_vector_component; + } + + /** + * + * Return a flag that indicates if the input @p unrolled_index + * corresponds to a symmetric component of the field. + * + * For a vector field, the none of the vector components + * have a symmetric counterpart. + */ + static bool + symmetric_component(const unsigned int unrolled_index) + { + (void)unrolled_index; + return false; + } + + /** + * Return the table index corresponding to + * @p column_offset entry of the input @p table_indices. + */ + template + static TableIndices + table_index_view(const TableIndices &table_indices, + const unsigned int column_offset) + { + Assert(0 + column_offset < rank_in, ExcInternalError()); + return TableIndices(table_indices[column_offset]); + } + + /** + * Return the local unrolled component corresponding to + * @p column_offset entry of the @p table_indices. + * + * This function computes and returns a local component + * associated with the extractor's @p tensor_type from a + * set of @p table_indices that are generally associated + * with a tensor of equal or greater order. In effect, it + * creates a view of a selected number of indices of the + * input table, and interprets that subtable's indices as + * the local index to be returned. Since the @p table_indices + * may be of size greater than the extractor's @p rank, + * the @p column_offset specifies the first index of the + * input table to create the view from. + */ + template + static IndexType + local_component(const TableIndices &table_indices, + const unsigned int column_offset) + { + static_assert( + rank_in >= rank, + "Cannot extract more table indices than the input table has!"); + using TensorType = tensor_type; + return TensorType::component_to_unrolled_index( + table_index_view(table_indices, column_offset)); + } + }; + + + /** + * A helper struct that assists with the extraction of data associated + * with fields that are defined by FEExtractors. + * This particular specialization is for rank-1 tensor fields. + */ + template + struct Extractor> + { + /** + * The number of components of the field. + */ + static const unsigned int n_components = + Tensor<1, dim>::n_independent_components; + + /** + * The tensor rank of the field. + */ + static const unsigned int rank = 1; + + /** + * The tensor type associated with this field. + */ + template + using tensor_type = Tensor; + + /** + * The value type associated with this field. + */ + template + using value_type = tensor_type; + + /** + * The gradient type associated with this field. + */ + template + using gradient_type = Tensor; + + /** + * Return the first global component of this field. + */ + static inline unsigned int + first_component(const FEValuesExtractors::Tensor<1> &extractor) + { + return extractor.first_tensor_component; + } + + /** + * Return a flag that indicates if the input @p unrolled_index + * corresponds to a symmetric component of the field. + * + * For a vector field, the none of the vector components + * have a symmetric counterpart. + */ + static bool + symmetric_component(const unsigned int unrolled_index) + { + (void)unrolled_index; + return false; + } + + /** + * Return the table index corresponding to + * @p column_offset entry of the input @p table_indices. + */ + template + static TableIndices + table_index_view(const TableIndices &table_indices, + const unsigned int column_offset) + { + Assert(column_offset < rank_in, ExcInternalError()); + return TableIndices(table_indices[column_offset]); + } + + /** + * Return the local unrolled component corresponding to + * a subset of table indices from the input @p table_indices. + * + * This function computes and returns a local component + * associated with the extractor's @p tensor_type from a + * set of @p table_indices that are generally associated + * with a tensor of equal or greater order. In effect, it + * creates a view of a selected number of indices of the + * input table, and interprets that subtable's indices as + * the local index to be returned. Since the @p table_indices + * may be of size greater than the extractor's @p rank, + * the @p column_offset specifies the first index of the + * input table to create the view from. + */ + template + static IndexType + local_component(const TableIndices &table_indices, + const unsigned int column_offset) + { + static_assert( + rank_in >= rank, + "Cannot extract more table indices than the input table has!"); + using TensorType = tensor_type; + return TensorType::component_to_unrolled_index( + table_index_view(table_indices, column_offset)); + } + }; + + + /** + * A helper struct that assists with the extraction of data associated + * with fields that are defined by FEExtractors. + * This particular specialization is for rank-2 tensor fields. + */ + template + struct Extractor> + { + /** + * The number of components of the field. + */ + static const unsigned int n_components = + Tensor<2, dim>::n_independent_components; + + /** + * The tensor rank of the field. + */ + static const unsigned int rank = Tensor<2, dim>::rank; + + /** + * The tensor type associated with this field. + */ + template + using tensor_type = Tensor; + + /** + * The value type associated with this field. + */ + template + using value_type = tensor_type; + + /** + * The gradient type associated with this field. + */ + template + using gradient_type = Tensor; + + /** + * Return the first global component of this field. + */ + static inline unsigned int + first_component(const FEValuesExtractors::Tensor<2> &extractor) + { + return extractor.first_tensor_component; + } + + /** + * Return a flag that indicates if the input @p unrolled_index + * corresponds to a symmetric component of the field. + * + * For a rank-2 tensor field, the none of the tensor + * components have a symmetric counterpart. + */ + static bool + symmetric_component(const unsigned int unrolled_index) + { + (void)unrolled_index; + return false; + } + + /** + * Return the table indices corresponding to + * @p column_offset entry of the input @p table_indices. + */ + template + static TableIndices + table_index_view(const TableIndices &table_indices, + const unsigned int column_offset) + { + Assert(column_offset < rank_in, ExcInternalError()); + Assert(column_offset + 1 < rank_in, ExcInternalError()); + return TableIndices(table_indices[column_offset], + table_indices[column_offset + 1]); + } + + /** + * Return the local unrolled component corresponding to + * @p column_offset entry of the @p table_indices. + * + * This function computes and returns a local component + * associated with the extractor's @p tensor_type from a + * set of @p table_indices that are generally associated + * with a tensor of equal or greater order. In effect, it + * creates a view of a selected number of indices of the + * input table, and interprets that subtable's indices as + * the local index to be returned. Since the @p table_indices + * may be of size greater than the extractor's @p rank, + * the @p column_offset specifies the first index of the + * input table to create the view from. + */ + template + static IndexType + local_component(const TableIndices &table_indices, + const unsigned int column_offset) + { + static_assert( + rank_in >= rank, + "Cannot extract more table indices than the input table has!"); + using TensorType = tensor_type; + return TensorType::component_to_unrolled_index( + table_index_view(table_indices, column_offset)); + } + }; + + + /** + * A helper struct that assists with the extraction of data associated + * with fields that are defined by FEExtractors. + * This particular specialization is for rank-2 symmetric tensor fields. + */ + template + struct Extractor> + { + /** + * The number of components of the field. + */ + static const unsigned int n_components = + SymmetricTensor<2, dim>::n_independent_components; + + /** + * The tensor rank of the field. + */ + static const unsigned int rank = SymmetricTensor<2, dim>::rank; + + /** + * The tensor type associated with this field. + */ + template + using tensor_type = SymmetricTensor; + + /** + * The value type associated with this field. + */ + template + using value_type = tensor_type; + + /** + * The gradient type associated with this field. + */ + template + using gradient_type = Tensor; + + /** + * Return the first global component of this field. + */ + static inline unsigned int + first_component(const FEValuesExtractors::SymmetricTensor<2> &extractor) + { + return extractor.first_tensor_component; + } + + /** + * Return a flag that indicates if the input @p unrolled_index + * corresponds to a symmetric component of the field. + * + * For a rank-2 symmetric tensor field, each of the + * off-diagonal components have a symmetric counterpart, + * while the diagonal components do not. + */ + static bool + symmetric_component(const unsigned int unrolled_index) + { + const TableIndices<2> table_indices = + tensor_type::unrolled_to_component_indices(unrolled_index); + return table_indices[0] != table_indices[1]; + } + + /** + * Return the table indices corresponding to + * @p column_offset entry of the input @p table_indices. + */ + template + static TableIndices + table_index_view(const TableIndices &table_indices, + const unsigned int column_offset) + { + Assert(column_offset < rank_in, ExcInternalError()); + Assert(column_offset + 1 < rank_in, ExcInternalError()); + return TableIndices(table_indices[column_offset], + table_indices[column_offset + 1]); + } + + /** + * Return the local unrolled component corresponding to + * @p column_offset entry of the @p table_indices. + * + * This function computes and returns a local component + * associated with the extractor's @p tensor_type from a + * set of @p table_indices that are generally associated + * with a tensor of equal or greater order. In effect, it + * creates a view of a selected number of indices of the + * input table, and interprets that subtable's indices as + * the local index to be returned. Since the @p table_indices + * may be of size greater than the extractor's @p rank, + * the @p column_offset specifies the first index of the + * input table to create the view from. + */ + template + static IndexType + local_component(const TableIndices &table_indices, + const unsigned int column_offset) + { + static_assert( + rank_in >= rank, + "Cannot extract more table indices than the input table has!"); + using TensorType = tensor_type; + return TensorType::component_to_unrolled_index( + table_index_view(table_indices, column_offset)); + } + }; + + + /** + * A helper struct that defines the return type of gradient (first + * derivative) calculations of scalar fields with respect to a field + * defined by the @p ExtractorType template parameter. + */ + template + struct ScalarFieldGradient + { + /** + * The type associated with computing the gradient of a scalar + * field with respect to the given @p ExtractorType. + */ + using type = + typename Extractor::template tensor_type; + }; + + + /** + * An intermediate helper struct that defines the return type of Hessian + * (second derivative) calculations of scalar fields with respect to + * fields defined by the two extractor-type template parameters. + * The first, @p ExtractorType_Row, defines the field that the first + * derivatives are taken with respect to while the second, + * @p ExtractorType_Col, defines the field that the second derivatives + * are taken with respect to. + */ + template + struct HessianType + { + /** + * The type associated with computing the gradient of a scalar + * field with respect to the given @p ExtractorType_Row + * followed by the @p ExtractorType_Col. + * + * @note We set the return type for + * HessianType + * as a normal Tensor. This is because if one has two vector components, + * the coupling tensor (i.e. Hessian component) is in + * general not symmetric. + */ + template + using type = Tensor; + }; + + + /** + * An intermediate helper struct that defines the return type of Hessian + * (second derivative) calculations of scalar fields with respect to + * fields defined by the two extractor-type template parameters. This + * particular specialization is for taking the first derivative with + * respect to a symmetric tensor field, and the second with respect to a + * scalar field. + */ + template <> + struct HessianType, + FEValuesExtractors::Scalar> + { + /** + * The type associated with computing the gradient of a scalar + * field with respect to the given + * ExtractorType_Row = + * FEValuesExtractors::SymmetricTensor<2> followed by the + * ExtractorType_Col = FEValuesExtractors::Scalar. + */ + template + using type = SymmetricTensor<2 /*rank*/, dim, NumberType>; + }; + + + /** + * An intermediate helper struct that defines the return type of Hessian + * (second derivative) calculations of scalar fields with respect to + * fields defined by the two extractor-type template parameters. This + * particular specialization is for taking the first derivative with + * respect to a scalar field, and the second with respect to a symmetric + * tensor field. + */ + template <> + struct HessianType> + { + /** + * The type associated with computing the gradient of a scalar + * field with respect to the given + * ExtractorType_Row = FEValuesExtractors::Scalar + * followed by the + * ExtractorType_Col = + * FEValuesExtractors::SymmetricTensor<2>. + */ + template + using type = SymmetricTensor<2 /*rank*/, dim, NumberType>; + }; + + + /** + * An intermediate helper struct that defines the return type of Hessian + * (second derivative) calculations of scalar fields with respect to + * fields defined by the two extractor-type template parameters. This + * particular specialization is for taking both the first and second + * derivatives with respect to symmetric tensor fields. + */ + template <> + struct HessianType, + FEValuesExtractors::SymmetricTensor<2>> + { + /** + * The type associated with computing the gradient of a scalar + * field with respect to the given + * ExtractorType_Row = + * FEValuesExtractors::SymmetricTensor<2> followed by the + * ExtractorType_Col = + * FEValuesExtractors::SymmetricTensor<2>. + */ + template + using type = SymmetricTensor<4 /*rank*/, dim, NumberType>; + }; + + + /** + * A helper struct that defines the final return type of Hessian + * (second derivative) calculations of scalar fields with respect to + * fields defined by the two extractor-type + * template parameters. The first, @p ExtractorType_Row, defines the field + * that the first derivatives are taken with respect to while the second, + * @p ExtractorType_Col, defines the field that the second derivatives + * are taken with respect to. + */ + template + struct ScalarFieldHessian + { + /** + * The tensor rank of the resulting derivative computation. + */ + static const int rank = Extractor::rank + + Extractor::rank; + + /** + * The type associated with computing the Hessian of a scalar + * field with first respect to the field defined by the + * @p ExtractorType_Row and then with respect to the field defined by + * the @p ExtractorType_Col. + */ + using type = + typename HessianType:: + template type; + }; + + + /** + * A helper struct that defines the return type of value computations + * of vector fields the @p ExtractorType_Field template parameter. + */ + template + using VectorFieldValue = + ScalarFieldGradient; + + + /** + * A helper struct that defines the final return type of Jacobian + * (first derivative) calculations of vector fields with respect to + * fields as defined by the two extractor-type template parameters. + * The first, @p ExtractorType_Field, defines the field from which + * the initial field values are computed while the second, + * @p ExtractorType_Derivative, defines the field that the derivatives + * are taken with respect to. + */ + template + using VectorFieldJacobian = ScalarFieldHessian; + + + /** + * Return a global view of the field component indices that correspond to + * the input @p extractor. For this general function the + * @p ignore_symmetries flag has no effect. + */ + template + std::vector + extract_field_component_indices(const ExtractorType &extractor, + const bool ignore_symmetries = true) + { + (void)ignore_symmetries; + const IndexType n_components = + internal::Extractor::n_components; + const IndexType comp_first = + internal::Extractor::first_component(extractor); + std::vector indices(n_components); + std::iota(indices.begin(), indices.end(), comp_first); + return indices; + } + + + /** + * Return a global view of the field component indices that correspond to + * the input FEValuesExtractors::SymmetricTensor @p extractor_symm_tensor. + * If the @p ignore_symmetries is set true, then all + * component of the tensor are considered to be independent. If set to + * code>false, then the set of returned indices will contain + * duplicate entries for components that are symmetric. + */ + template + std::vector + extract_field_component_indices( + const FEValuesExtractors::SymmetricTensor<2> &extractor_symm_tensor, + const bool ignore_symmetries = true) + { + using ExtractorType = FEValuesExtractors::SymmetricTensor<2>; + const IndexType n_components = + internal::Extractor::n_components; + if (ignore_symmetries == true) + { + const IndexType comp_first = + internal::Extractor::first_component( + extractor_symm_tensor); + std::vector indices(n_components); + std::iota(indices.begin(), indices.end(), comp_first); + return indices; + } + else + { + // First get all of the indices of the non-symmetric tensor + const FEValuesExtractors::Tensor<2> extractor_tensor( + extractor_symm_tensor.first_tensor_component); + std::vector indices = + extract_field_component_indices(extractor_tensor, true); + + // Then we overwrite any illegal entries with the equivalent indices + // from the symmetric tensor + for (unsigned int i = 0; i < indices.size(); ++i) + { + if (indices[i] >= n_components) + { + const TableIndices<2> ti_tensor = + Tensor<2, dim>::unrolled_to_component_indices(indices[i]); + const IndexType sti_new_index = + SymmetricTensor<2, dim>::component_to_unrolled_index( + ti_tensor); + indices[i] = sti_new_index; + } + } + + return indices; + } + } + + + /** + * Set the unrolled component given by @p index in the generic tensor + * @p t to the given @p value. + */ + template + inline void + set_tensor_entry(TensorType & t, + const unsigned int &unrolled_index, + const NumberType & value) + { + // Where possible, set values using TableIndices + Assert(unrolled_index < t.n_independent_components, + ExcIndexRange(unrolled_index, 0, t.n_independent_components)); + t[TensorType::unrolled_to_component_indices(unrolled_index)] = value; + } + + + /** + * Set the unrolled component given by @p index in the rank-0 tensor + * @p t to the given @p value. + */ + template + inline void set_tensor_entry(Tensor<0, dim, NumberType> &t, + const unsigned int & unrolled_index, + const NumberType & value) + { + Assert(unrolled_index == 0, ExcIndexRange(unrolled_index, 0, 1)); + (void)unrolled_index; + t = value; + } + + + /** + * Set the value of @p t to the given @p value. + * This function exists to provide compatibility with similar functions + * that exist for use with the tensor classes. + */ + template + inline void + set_tensor_entry(NumberType & t, + const unsigned int &unrolled_index, + const NumberType & value) + { + Assert(unrolled_index == 0, ExcIndexRange(unrolled_index, 0, 1)); + (void)unrolled_index; + t = value; + } + + + /** + * Set the unrolled component given by the @p index_row and + * the @p index_col in the fourth-order symmetric tensor + * @p t to the given @p value. + */ + template + inline void set_tensor_entry(SymmetricTensor<4, dim, NumberType> &t, + const unsigned int &unrolled_index_row, + const unsigned int &unrolled_index_col, + const NumberType & value) + { + // Fourth order symmetric tensors require a specialized interface + // to extract values. + using SubTensorType = SymmetricTensor<2, dim, NumberType>; + Assert(unrolled_index_row < SubTensorType::n_independent_components, + ExcIndexRange(unrolled_index_row, + 0, + SubTensorType::n_independent_components)); + Assert(unrolled_index_col < SubTensorType::n_independent_components, + ExcIndexRange(unrolled_index_col, + 0, + SubTensorType::n_independent_components)); + const TableIndices<2> indices_row = + SubTensorType::unrolled_to_component_indices(unrolled_index_row); + const TableIndices<2> indices_col = + SubTensorType::unrolled_to_component_indices(unrolled_index_col); + t[indices_row[0]][indices_row[1]][indices_col[0]][indices_col[1]] = + value; + } + + + /** + * Return the value of the @p index'th unrolled component of the + * generic tensor @p t. + */ + template class TensorType> + inline NumberType + get_tensor_entry(const TensorType &t, + const unsigned int & unrolled_index) + { + // Where possible, get values using TableIndices + Assert(unrolled_index < t.n_independent_components, + ExcIndexRange(unrolled_index, 0, t.n_independent_components)); + return t[TensorType:: + unrolled_to_component_indices(unrolled_index)]; + } + + + /** + * Return the value of the @p index'th unrolled component of the + * rank-0 tensor @p t. + */ + template class TensorType> + inline NumberType + get_tensor_entry(const TensorType<0, dim, NumberType> &t, + const unsigned int & unrolled_index) + { + Assert(unrolled_index == 0, ExcIndexRange(unrolled_index, 0, 1)); + (void)unrolled_index; + return t; + } + + + /** + * Return the value of @p t. + * This function exists to provide compatibility with similar functions + * that exist for use with the tensor classes. + */ + template + inline const NumberType & + get_tensor_entry(const NumberType &t, const unsigned int &unrolled_index) + { + Assert(unrolled_index == 0, ExcIndexRange(unrolled_index, 0, 1)); + (void)unrolled_index; + return t; + } + + + /** + * Return a reference to the entry stored in the @p index'th unrolled + * component of the generic tensor @p t. + */ + template class TensorType> + inline NumberType & + get_tensor_entry(TensorType &t, + const unsigned int & unrolled_index) + { + // Where possible, get values using TableIndices + Assert(unrolled_index < t.n_independent_components, + ExcIndexRange(unrolled_index, 0, t.n_independent_components)); + return t[TensorType:: + unrolled_to_component_indices(unrolled_index)]; + } + + + /** + * Return a reference to the entry stored in the @p index'th unrolled + * component of the rank-0 tensor @p t. + */ + template class TensorType> + NumberType &get_tensor_entry(TensorType<0, dim, NumberType> &t, + const unsigned int & index) + { + Assert(index == 0, ExcIndexRange(index, 0, 1)); + (void)index; + return t; + } + + + /** + * Return a reference to @p t. + * This function exists to provide compatibility with similar functions + * that exist for use with the tensor classes. + */ + template + inline NumberType & + get_tensor_entry(NumberType &t, const unsigned int &index) + { + Assert(index == 0, ExcIndexRange(index, 0, 1)); + (void)index; + return t; + } + + } // namespace internal } // namespace AD } // namespace Differentiation From b001e6dfcda04dfacc64e20dc48f3bb31d3e808b Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Mon, 11 Feb 2019 18:47:04 +0100 Subject: [PATCH 096/507] AD Helpers: Introduce base class for QP-level helper classes --- .../deal.II/differentiation/ad/ad_helpers.h | 424 ++++++++++++++++++ source/differentiation/ad/ad_helpers.cc | 169 +++++++ source/differentiation/ad/ad_helpers.inst1.in | 39 ++ source/differentiation/ad/ad_helpers.inst2.in | 52 +++ 4 files changed, 684 insertions(+) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index 5460362a72bf..4f36c1dbfe11 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -2617,6 +2617,323 @@ namespace Differentiation } } // namespace internal + + + + /** + * A base helper class that facilitates the evaluation of point-wise defined + * functions. This is the point-wise counterpart of the + * ADHelperCellLevelBase class, and was conceived for computations at a + * continuum point, or quadrature point, rather than for finite-element + * level calculations. That being said, the interface to this and the + * derived classes are sufficiently generic that the dependent function(s) + * and their argument(s), that are the independent variables, can be + * interpreted in any manner that the user may choose. + * + * As it offers a field-based interface, this class would + * typically be used to compute the derivatives of a constitutive law + * defined at a quadrature point; however, it may also be used in other + * contexts, such as to compute the linearization of a set of local + * nonlinear equations. + * + * @warning ADOL-C does not support the standard threading models used by + * deal.II, so this class should @b not be embedded within a multithreaded + * function when using ADOL-C number types. It is, however, suitable for use + * in both serial and MPI routines. + * + * @author Jean-Paul Pelteret, 2016, 2017, 2018 + */ + template + class ADHelperPointLevelFunctionsBase + : public ADHelperBase + { + public: + /** + * Type definition for the dimension of the associated input and output + * tensor types. + */ + static const unsigned int dimension = dim; + + /** + * Type definition for the floating point number type that is used in, + * and results from, all computations. + */ + using scalar_type = + typename ADHelperBase::scalar_type; + + /** + * Type definition for the auto-differentiation number type that is used + * in all computations. + */ + using ad_type = + typename ADHelperBase::ad_type; + + /** + * @name Constructor / destructor + */ + //@{ + + /** + * The constructor for the class. + * + * @param[in] n_independent_variables The number of independent variables + * that will be used in the definition of the functions that it is + * desired to compute the sensitivities of. In the computation of + * $\mathbf{f}(\mathbf{X})$, this will be the number of inputs + * $\mathbf{X}$, i.e. the dimension of the domain space. + * @param[in] n_dependent_variables The number of scalar functions to be + * defined that will have a sensitivity to the given independent + * variables. In the computation of $\mathbf{f}(\mathbf{X})$, this will + * be the number of outputs $\mathbf{f}$, i.e. the dimension of the + * image space. + */ + ADHelperPointLevelFunctionsBase( + const unsigned int n_independent_variables, + const unsigned int n_dependent_variables); + + /** + * Destructor + */ + virtual ~ADHelperPointLevelFunctionsBase() = default; + + //@} + + /** + * @name Independent variables + */ + //@{ + + /** + * @copydoc ADHelperBase::reset() + */ + virtual void + reset(const unsigned int n_independent_variables = + dealii::numbers::invalid_unsigned_int, + const unsigned int n_dependent_variables = + dealii::numbers::invalid_unsigned_int, + const bool clear_registered_tapes = true) override; + + /** + * Register the complete set of independent variables $\mathbf{X}$. + * + * @param[in] values A field that defines the values of all independent + * variables. When considering taped AD numbers with branching functions, + * to avoid potential issues with branch switching it may be a good idea + * to choose these values close or equal to those that will be later + * evaluated and differentiated around. + * + * @note The input value type must correspond to this class's @p scalar_type. + * Depending on the selected @p ADNumberTypeCode, this may or may not + * correspond with the @p ScalarType prescribed as a template argument. + * + * @note For taped AD numbers, this operation is only valid in recording mode. + */ + void + register_independent_variables(const std::vector &values); + + /** + * Register the subset of independent variables + * $\mathbf{A} \subset \mathbf{X}$. + * + * @param[in] value A field that defines a number of independent + * variables. When considering taped AD numbers with branching functions, + * to avoid potential issues with branch switching it may be a good idea + * to choose these values close or equal to those that will be later + * evaluated and differentiated around. + * @param[in] extractor An extractor associated with the input field + * variables. This effectively defines which components of the global set + * of independent variables this field is associated with. + * + * @note The input value type must correspond to this class's @p scalar_type. + * Depending on the selected @p ADNumberTypeCode, this may or may not + * correspond with the @p ScalarType prescribed as a template argument. + * + * @note The input extractor must correspond to the input @p ValueType. + * So, for example, if a value is a rank-1 tensor + * (i.e. of type Tensor<1,dim,scalar_type>), then the extractor must + * be an FEValuesExtractors::Vector or FEValuesExtractors::Tensor<1>. + * + * @note This function may be repeatedly used until a call to + * finalize_sensitive_independent_variables() or + * get_sensitive_variables() is made. + * + * @note For taped AD numbers, this operation is only valid in recording mode. + */ + template + void + register_independent_variable(const ValueType & value, + const ExtractorType &extractor); + + /** + * Return the complete set of independent variables as represented by + * auto-differentiable numbers. These are the independent + * variables $\mathbf{X}$ at which the dependent values are evaluated + * and differentiated. + * + * This function indicates to the AD library that implements the + * auto-differentiable number type that operations performed on these + * numbers are to be tracked so they are considered "sensitive" + * variables. This is, therefore, the set of variables with which one + * would then perform computations, and based on which one can then + * extract both the value of the function and its derivatives with the + * member functions below. The values of the components of the returned + * object are initialized to the values set with + * register_independent_variable(). + * + * @return An array of auto-differentiable type numbers. + * + * @note For taped AD numbers, this operation is only valid in recording mode. + */ + const std::vector & + get_sensitive_variables() const; + + /* + * Extract a subset of the independent variables as represented by + * auto-differentiable numbers. These are the independent + * variables $\mathbf{A} \subset \mathbf{X}$ at which the dependent values + * are evaluated and differentiated. + * + * This function indicates to the AD library that implements the + * auto-differentiable number type that operations performed on these + * numbers are to be tracked so they are considered "sensitive" + * variables. This is, therefore, the set of variables with which one + * would then perform computations, and based on which one can then + * extract both the value of the function and its derivatives with the + * member functions below. The values of the components of the returned + * object are initialized to the values set with + * register_independent_variable(). + * + * @param[in] extractor An extractor associated with the input field + * variables. This effectively defines which components of the global set + * of independent variables this field is associated with. + * @return An object of auto-differentiable type numbers. The return type is + * based on the input extractor, and will be either a scalar, + * Tensor<1,dim>, Tensor<2,dim>, or SymmetricTensor<2,dim>. + * + * @note For taped AD numbers, this operation is only valid in recording mode. + */ + template + typename internal::Extractor::template tensor_type + get_sensitive_variables(const ExtractorType &extractor) const; + + //@} + + /** + * @name Operations specific to taped mode: Reusing tapes + */ + //@{ + + /** + * Set the values for the independent variables $\mathbf{X}$. + * + * @param[in] values A vector that defines the values of all + * independent variables. + * + * @note The input value type must correspond to this class's @p scalar_type. + * Depending on the selected @p ADNumberTypeCode, this may or may not + * correspond with the @p ScalarType prescribed as a template argument. + * + * @note If the @p keep_independent_values flag has been set when + * ADHelperBase::start_recording_operations() is called then the tape is + * immediately usable after creation, and the values of the independent + * variables set by register_independent_variables() are those at which + * the function is to be evaluated. In this case, a separate call to this + * function is not strictly necessary. + */ + void + set_independent_variables(const std::vector &values); + + /** + * Set the values for a subset of independent variables + * $\mathbf{A} \subset \mathbf{X}$. + * + * @param[in] value A field that defines the values of a number of + * independent variables. + * @param[in] extractor An extractor associated with the input field + * variables. This effectively defines which components of the global set + * of independent variables this field is associated with. + * + * @note The input value type must correspond to this class's @p scalar_type. + * Depending on the selected @p ADNumberTypeCode, this may or may not + * correspond with the @p ScalarType prescribed as a template argument. + * + * @note The input extractor must correspond to the input @p ValueType. + * So, for example, if a value is a rank-1 tensor + * (i.e. of type Tensor<1,dim,scalar_type>), then the extractor must + * be an FEValuesExtractors::Vector or FEValuesExtractors::Tensor<1>. + * + * @note If the @p keep_independent_values flag has been set when + * ADHelperBase::start_recording_operations() is called then the tape is + * immediately usable after creation, and the values of the independent + * variables set by register_independent_variable() are those at which the + * function is to be evaluated. In this case, a separate call to this + * function is not strictly necessary. + */ + template + void + set_independent_variable(const ValueType & value, + const ExtractorType &extractor); + + //@} + + protected: + /** + * @name Independent variables + */ + //@{ + + /** + * Set the actual value of the independent variable $X_{i}$. + * + * @param[in] index The index in the vector of independent variables. + * @param[in] symmetric_component Mark whether this index relates to a + * component of a field that has a symmetric counterpart + * (e.g. if @p index represents an off-diagonal entry in a symmetric + * tensor). + * @param[in] value The value to set the index'd independent variable to. + */ + void + set_sensitivity_value(const unsigned int index, + const bool symmetric_component, + const scalar_type &value); + + /** + * Return whether the @p index'th independent variables is one for which + * we must take into account symmetry when extracting their gradient or + * Hessian values. + */ + bool + is_symmetric_independent_variable(const unsigned int index) const; + + /** + * Return the number of independent variables that have been marked as + * being components of a symmetric field. + */ + unsigned int + n_symmetric_independent_variables() const; + + //@} + + private: + /** + * @name Independent variables + */ + //@{ + + /** + * The independent variables for which we must take into account symmetry + * when extracting their gradient or Hessian values. + */ + std::vector symmetric_independent_variables; + + //@} + + }; // class ADHelperPointLevelFunctionsBase + + } // namespace AD } // namespace Differentiation @@ -2675,6 +2992,113 @@ namespace Differentiation } + + /* ----------------- ADHelperPointLevelFunctionsBase ----------------- */ + + + + template + template + void + ADHelperPointLevelFunctionsBase:: + register_independent_variable(const ValueType & value, + const ExtractorType &extractor) + { + // This is actually the same thing as the set_independent_variable + // function, in the sense that we simply populate our array of independent + // values with a meaningful number. However, in this case we need to + // double check that we're not registering these variables twice +# ifdef DEBUG + const std::vector index_set( + internal::extract_field_component_indices(extractor)); + for (unsigned int i = 0; i < index_set.size(); ++i) + { + Assert( + this->registered_independent_variable_values[index_set[i]] == false, + ExcMessage( + "Overlapping indices for independent variables. " + "One or more indices associated with the field that " + "is being registered as an independent variable have " + "already been associated with another field. This suggests " + "that the component offsets used to construct their counterpart " + "extractors are incompatible with one another. Make sure that " + "the first component for each extractor properly takes into " + "account the dimensionality of the preceeding fields.")); + } +# endif + set_independent_variable(value, extractor); + } + + + + template + template + void + ADHelperPointLevelFunctionsBase:: + set_independent_variable(const ValueType & value, + const ExtractorType &extractor) + { + const std::vector index_set( + internal::extract_field_component_indices(extractor)); + for (unsigned int i = 0; i < index_set.size(); ++i) + { + set_sensitivity_value( + index_set[i], + internal::Extractor::symmetric_component(i), + internal::get_tensor_entry(value, i)); + } + } + + + + template + template + typename internal::Extractor::template tensor_type< + typename ADHelperBase::ad_type> + ADHelperPointLevelFunctionsBase:: + get_sensitive_variables(const ExtractorType &extractor) const + { + if (ADNumberTraits::is_taped == true) + { + Assert(this->active_tape_index() != + Numbers::invalid_tape_index, + ExcMessage("Invalid tape index")); + } + + // If necessary, finalize the internally stored vector of + // AD numbers that represents the independent variables + this->finalize_sensitive_independent_variables(); + Assert(this->independent_variables.size() == + this->n_independent_variables(), + ExcDimensionMismatch(this->independent_variables.size(), + this->n_independent_variables())); + + const std::vector index_set( + internal::extract_field_component_indices(extractor)); + typename internal::Extractor::template tensor_type + out; + + for (unsigned int i = 0; i < index_set.size(); ++i) + { + const unsigned int index = index_set[i]; + Assert(index < this->n_independent_variables(), ExcInternalError()); + Assert(this->registered_independent_variable_values[index] == true, + ExcInternalError()); + internal::get_tensor_entry(out, i) = + this->independent_variables[index]; + } + + return out; + } + + } // namespace AD } // namespace Differentiation diff --git a/source/differentiation/ad/ad_helpers.cc b/source/differentiation/ad/ad_helpers.cc index 2c3a9a5a47bd..7789a475430b 100644 --- a/source/differentiation/ad/ad_helpers.cc +++ b/source/differentiation/ad/ad_helpers.cc @@ -1143,6 +1143,175 @@ namespace Differentiation } + + /* ----------------- ADHelperPointLevelFunctionsBase ----------------- */ + + + + template + ADHelperPointLevelFunctionsBase:: + ADHelperPointLevelFunctionsBase( + const unsigned int n_independent_variables, + const unsigned int n_dependent_variables) + : ADHelperBase(n_independent_variables, + n_dependent_variables) + , symmetric_independent_variables(n_independent_variables, false) + {} + + + + template + void + ADHelperPointLevelFunctionsBase::reset( + const unsigned int n_independent_variables, + const unsigned int n_dependent_variables, + const bool clear_registered_tapes) + { + ADHelperBase::reset(n_independent_variables, + n_dependent_variables, + clear_registered_tapes); + + const unsigned int new_n_independent_variables = + (n_independent_variables != dealii::numbers::invalid_unsigned_int ? + n_independent_variables : + this->n_independent_variables()); + symmetric_independent_variables = + std::vector(new_n_independent_variables, false); + } + + + + template + bool + ADHelperPointLevelFunctionsBase:: + is_symmetric_independent_variable(const unsigned int index) const + { + Assert(index < symmetric_independent_variables.size(), + ExcInternalError()); + return symmetric_independent_variables[index]; + } + + + + template + unsigned int + ADHelperPointLevelFunctionsBase:: + n_symmetric_independent_variables() const + { + return std::count(symmetric_independent_variables.begin(), + symmetric_independent_variables.end(), + true); + } + + + + template + void + ADHelperPointLevelFunctionsBase:: + register_independent_variables(const std::vector &values) + { + // This is actually the same thing the set_independent_variable function, + // in the sense that we simply populate our array of independent values + // with a meaningful number. However, in this case we need to double check + // that we're not registering these variables twice + Assert(values.size() == this->n_independent_variables(), + ExcMessage( + "Vector size does not match number of independent variables")); + for (unsigned int i = 0; i < this->n_independent_variables(); ++i) + { + Assert(this->registered_independent_variable_values[i] == false, + ExcMessage("Independent variable value already registered.")); + } + set_independent_variables(values); + } + + + + template + const std::vector< + typename ADHelperPointLevelFunctionsBase::ad_type> & + ADHelperPointLevelFunctionsBase:: + get_sensitive_variables() const + { + if (ADNumberTraits::is_taped == true) + { + Assert(this->active_tape_index() != + Numbers::invalid_tape_index, + ExcMessage("Invalid tape index")); + } + + // Just in case the user has not done so, we repeat the call to + // initialize the internally stored vector of AD numbers that + // represents the independent variables. + this->finalize_sensitive_independent_variables(); + Assert(this->independent_variables.size() == + this->n_independent_variables(), + ExcDimensionMismatch(this->independent_variables.size(), + this->n_independent_variables())); + + return this->independent_variables; + } + + + + template + void + ADHelperPointLevelFunctionsBase:: + set_sensitivity_value(const unsigned int index, + const bool symmetric_component, + const scalar_type &value) + { + ADHelperBase::set_sensitivity_value(index, + value); + Assert( + index < this->n_independent_variables(), + ExcMessage( + "Trying to set the symmetry flag of a non-existent independent variable.")); + Assert(index < symmetric_independent_variables.size(), + ExcInternalError()); + symmetric_independent_variables[index] = symmetric_component; + } + + + + template + void + ADHelperPointLevelFunctionsBase:: + set_independent_variables(const std::vector &values) + { + if (ADNumberTraits::is_taped == true) + { + Assert(this->active_tape_index() != + Numbers::invalid_tape_index, + ExcMessage("Invalid tape index")); + } + Assert(values.size() == this->n_independent_variables(), + ExcMessage( + "Vector size does not match number of independent variables")); + for (unsigned int i = 0; i < this->n_independent_variables(); ++i) + ADHelperBase::set_sensitivity_value( + i, values[i]); + } + + } // namespace AD } // namespace Differentiation diff --git a/source/differentiation/ad/ad_helpers.inst1.in b/source/differentiation/ad/ad_helpers.inst1.in index bf91f88855b7..ef44c9398496 100644 --- a/source/differentiation/ad/ad_helpers.inst1.in +++ b/source/differentiation/ad/ad_helpers.inst1.in @@ -101,3 +101,42 @@ for () \} \} } + + +for (deal_II_dimension : DIMENSIONS ; number : REAL_SCALARS) +{ + namespace Differentiation + \{ + namespace AD + \{ + // -------------------------- ADHelperPointLevelFunctionsBase ---------------------- + + template + class ADHelperPointLevelFunctionsBase; + + template + class ADHelperPointLevelFunctionsBase; + + \} + \} +} + +// Instantiations for ADHelpers for which the underlying number type is fixed +for (deal_II_dimension : DIMENSIONS) +{ + namespace Differentiation + \{ + namespace AD + \{ + + // -------------------------- ADHelperPointLevelFunctionsBase ---------------------- + + template + class ADHelperPointLevelFunctionsBase::ad_type>; + + template + class ADHelperPointLevelFunctionsBase::ad_type>; + + \} + \} +} diff --git a/source/differentiation/ad/ad_helpers.inst2.in b/source/differentiation/ad/ad_helpers.inst2.in index 30c30a054ce3..5fa4b2511e37 100644 --- a/source/differentiation/ad/ad_helpers.inst2.in +++ b/source/differentiation/ad/ad_helpers.inst2.in @@ -149,3 +149,55 @@ for () \} \} } + + +for (deal_II_dimension : DIMENSIONS ; number : REAL_SCALARS) +{ + namespace Differentiation + \{ + namespace AD + \{ + + // -------------------------- ADHelperPointLevelFunctionsBase ---------------------- + + template + class ADHelperPointLevelFunctionsBase; + + template + class ADHelperPointLevelFunctionsBase; + + template + class ADHelperPointLevelFunctionsBase; + + template + class ADHelperPointLevelFunctionsBase; + + \} + \} +} + +// Instantiations for ADHelpers for which the underlying number type is fixed +for (deal_II_dimension : DIMENSIONS) +{ + namespace Differentiation + \{ + namespace AD + \{ + + // -------------------------- ADHelperPointLevelFunctionsBase ---------------------- + + template + class ADHelperPointLevelFunctionsBase::ad_type>; + + template + class ADHelperPointLevelFunctionsBase::ad_type>; + + template + class ADHelperPointLevelFunctionsBase::ad_type>; + + template + class ADHelperPointLevelFunctionsBase::ad_type>; + + \} + \} +} From 5f482f9cdd1a822f6a7b7f1bb3458d68382ad6ec Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 12 Feb 2019 01:21:37 +0100 Subject: [PATCH 097/507] Fix changelog entry --- doc/news/changes/minor/20190209Arndt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/news/changes/minor/20190209Arndt b/doc/news/changes/minor/20190209Arndt index d8bdf8fff554..b781c4394355 100644 --- a/doc/news/changes/minor/20190209Arndt +++ b/doc/news/changes/minor/20190209Arndt @@ -1,3 +1,3 @@ -New: make_const_array_view creates a constant view from a non-const object. +New: make_const_array_view() creates a constant view from a non-const object.
(Daniel Arndt, 2019/02/09) From 62db86d737aaa557822b411340268352d25e8ada Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Fri, 8 Feb 2019 13:50:16 -0600 Subject: [PATCH 098/507] examples/step-20: Update introduction - Introduce LinearOperator and PackagedOperation - Explain in detail how to solve the Schur complement using this functionality. --- examples/step-20/doc/intro.dox | 380 ++++++++++++++++----------------- 1 file changed, 185 insertions(+), 195 deletions(-) diff --git a/examples/step-20/doc/intro.dox b/examples/step-20/doc/intro.dox index b9a7bde9cf4e..f090523b020d 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 how they can be implemented in deal.II.

Solving using the Schur complement

@@ -439,115 +440,162 @@ 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 -class SchurComplement : public Subscriptor -{ - 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 -{ - 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 -} + 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); -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. + PreconditionJacobi<> preconditioner_M; + preconditioner_M.initialize(M); -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. + ReductionControl reduction_control_M(2000, 1.0e-18, 1.0e-10); + SolverCG<> solver_M(reduction_control_M); -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: + 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 +have vastly differing norms. 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 + 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). +@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 -template -void MixedLaplaceProblem::solve () +class SchurComplement { - InverseMatrix > inverse_mass (system_matrix.block(0,0)); - Vector tmp (solution.block(0).size()); + public: - { - 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); - } + // ... + void SchurComplement::vmult (Vector &dst, + const Vector &src) const { - system_matrix.block(0,1).vmult (tmp, solution.block(1)); - tmp *= -1; - tmp += system_rhs.block(0); - - inverse_mass.vmult (solution.block(0), tmp); + B.vmult (tmp1, src); + solver_M(M, tmp2, tmp1, preconditioner_M); + B.Tvmult (dst, tmp2); } -} +}; +@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. -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. +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 + Vector schur_rhs (U.size()); + Vector tmp (P.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. +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; + + const auto op_S_inv = inverse_operator(op_S, solver_S, preconditioner_S); + + P = op_S_inv * schur_rhs; + U = op_M_inv * (F - op_B * P); +@endcode

A preconditioner for the Schur complement

@@ -579,82 +627,34 @@ 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 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 nearly already have the preconditioner: it should be the -inverse of the approximate Schur complement. We implement this with -the InverseMatrix class: - +inverse of the approximate Schur complement. We implement this again with +the inverse_operator() function @code - ApproximateSchurComplement approximate_schur (system_matrix); - InverseMatrix approximate_inverse - (approximate_schur); + ReductionControl reduction_control_aS(2000, 1.e-18, 1.0e-6); + SolverCG<> solver_aS(reduction_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 @@ -670,16 +670,6 @@ six times refined mesh and using elements of order 2 yields an improvement of 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. - -

Definition of the test case

In this tutorial program, we will solve the Laplace equation in mixed From f21656e3fd265a36fd53616888bffca7601600e5 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Fri, 8 Feb 2019 13:51:36 -0600 Subject: [PATCH 099/507] examples/step-20: Actually use LinearOperator in the example step --- examples/step-20/step-20.cc | 240 ++++++++++-------------------------- 1 file changed, 66 insertions(+), 174 deletions(-) diff --git a/examples/step-20/step-20.cc b/examples/step-20/step-20.cc index 8710392acae2..20ddcb621d42 100644 --- a/examples/step-20/step-20.cc +++ b/examples/step-20/step-20.cc @@ -14,7 +14,8 @@ * --------------------------------------------------------------------- * - * Author: Wolfgang Bangerth, Texas A&M University, 2005, 2006 + * Authors: Wolfgang Bangerth, Texas A&M University, 2005, 2006; + * (port to LinearOperator:) Matthias Maier, 2019 */ @@ -27,12 +28,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 @@ -559,206 +566,91 @@ 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) - {} - + // 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. - 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} + // @sect4{MixedLaplace::solve} - // 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 + // 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() { - 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; - }; + // 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); - 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()) - {} + auto &U = solution.block(0); + auto &P = solution.block(1); + // Then, we will create corresponding LinearOperator objects and create + // the op_M_inv operator: - void SchurComplement::vmult(Vector & dst, - const Vector &src) const - { - system_matrix->block(0, 1).vmult(tmp1, src); - m_inverse->vmult(tmp2, tmp1); - system_matrix->block(1, 0).vmult(dst, tmp2); - } + const auto op_M = linear_operator(M); + const auto op_B = linear_operator(B); + ReductionControl reduction_control_M(2000, 1.0e-18, 1.0e-10); + SolverCG<> solver_M(reduction_control_M); + PreconditionJacobi<> preconditioner_M; - // @sect4{The ApproximateSchurComplement class} + preconditioner_M.initialize(M); - // 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); + const auto op_M_inv = inverse_operator(op_M, solver_M, preconditioner_M); - void vmult(Vector &dst, const Vector &src) const; + // This puts us in the position to be able to declare the Schur + // complement op_S and the approximate Schur complement + // op_aS: - private: - const SmartPointer> system_matrix; + 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; - mutable Vector tmp1, tmp2; - }; + // We now create a preconditioner out of op_aS that + // applies a few number of CG iterations (until a very modest relative + // reduction of $10^{-16}$ is reached): + ReductionControl reduction_control_aS(2000, 1.e-18, 1.0e-6); + SolverCG<> solver_aS(reduction_control_aS); + PreconditionIdentity preconditioner_aS; + const auto preconditioner_S = + inverse_operator(op_aS, solver_aS, preconditioner_aS); - ApproximateSchurComplement::ApproximateSchurComplement( - const BlockSparseMatrix &A) - : system_matrix(&A) - , tmp1(A.block(0, 0).m()) - , tmp2(A.block(0, 0).m()) - {} + // 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); } From e2b7c60bcbde35ad934d38d29a30137f6a6a5d6e Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Fri, 8 Feb 2019 14:09:50 -0600 Subject: [PATCH 100/507] doc: add a changes entry --- doc/news/changes/major/20190208MatthiasMaier | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 doc/news/changes/major/20190208MatthiasMaier diff --git a/doc/news/changes/major/20190208MatthiasMaier b/doc/news/changes/major/20190208MatthiasMaier new file mode 100644 index 000000000000..b1cd3de01f22 --- /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. +
+(2019/02/08, Matthias Maier) From 6836468408ed5ecfdc2c4ffd0336cce70a9dde55 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Fri, 8 Feb 2019 14:36:08 -0600 Subject: [PATCH 101/507] remove unnecessary whitespace --- examples/step-20/step-20.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/step-20/step-20.cc b/examples/step-20/step-20.cc index 20ddcb621d42..7c6d13494ecb 100644 --- a/examples/step-20/step-20.cc +++ b/examples/step-20/step-20.cc @@ -596,7 +596,6 @@ namespace Step20 // 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); @@ -611,7 +610,6 @@ namespace Step20 // This puts us in the position to be able 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; @@ -619,7 +617,6 @@ namespace Step20 // We now create a preconditioner out of op_aS that // applies a few number of CG iterations (until a very modest relative // reduction of $10^{-16}$ is reached): - ReductionControl reduction_control_aS(2000, 1.e-18, 1.0e-6); SolverCG<> solver_aS(reduction_control_aS); PreconditionIdentity preconditioner_aS; @@ -631,7 +628,6 @@ namespace Step20 // $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; SolverControl solver_control_S(2000, 1.e-12); @@ -649,7 +645,6 @@ namespace Step20 // 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: - U = op_M_inv * (F - op_B * P); } From 3d625c92024b0b1e92e7d1be300d52f5e6294696 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Fri, 8 Feb 2019 16:40:03 -0600 Subject: [PATCH 102/507] Address Martin's comments - Change preconditioner reduction to a relative tolerance of 10^-3 - Increase initial resolution to 5 global refinement steps - Update results section to reflect changes --- examples/step-20/doc/intro.dox | 4 ++-- examples/step-20/doc/results.dox | 35 ++++++++++++++++---------------- examples/step-20/step-20.cc | 8 ++++---- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/examples/step-20/doc/intro.dox b/examples/step-20/doc/intro.dox index f090523b020d..2f3209618b80 100644 --- a/examples/step-20/doc/intro.dox +++ b/examples/step-20/doc/intro.dox @@ -554,8 +554,8 @@ 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 - Vector schur_rhs (U.size()); - Vector tmp (P.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; diff --git a/examples/step-20/doc/results.dox b/examples/step-20/doc/results.dox index 42dbf4517127..85700efea3e6 100644 --- a/examples/step-20/doc/results.dox +++ b/examples/step-20/doc/results.dox @@ -3,33 +3,34 @@

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 7c6d13494ecb..2c4ef1733f02 100644 --- a/examples/step-20/step-20.cc +++ b/examples/step-20/step-20.cc @@ -327,7 +327,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); @@ -615,9 +615,9 @@ namespace Step20 transpose_operator(op_B) * linear_operator(preconditioner_M) * op_B; // We now create a preconditioner out of op_aS that - // applies a few number of CG iterations (until a very modest relative - // reduction of $10^{-16}$ is reached): - ReductionControl reduction_control_aS(2000, 1.e-18, 1.0e-6); + // applies a few CG iterations (until a very modest relative reduction + // of $10^{-3}$ is reached): + ReductionControl reduction_control_aS(2000, 1.e-18, 1.0e-3); SolverCG<> solver_aS(reduction_control_aS); PreconditionIdentity preconditioner_aS; From 6c3aa3848b44d9405e05ca11064cf1de090f02ce Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Mon, 11 Feb 2019 18:27:15 -0600 Subject: [PATCH 103/507] Update discussion about preconditioner performance The numbers here were seriously outdated :-D (For example with a modern CPU the refinement step of 5 global refinement and lowest order elements converges nowadays in about 0.8 total runtime seconds instead of 28 seconds (0.4 seconds of thise total runtime is by the way the dynamic linker starting up the program...) --- examples/step-20/doc/intro.dox | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/examples/step-20/doc/intro.dox b/examples/step-20/doc/intro.dox index 2f3209618b80..97bcb989cfaf 100644 --- a/examples/step-20/doc/intro.dox +++ b/examples/step-20/doc/intro.dox @@ -659,15 +659,16 @@ 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. +typical run on 7 times refined meshes using elements of order 0, the number of +outer iterations drops from 592 to 25. 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.48 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 28 outer iterations, at a runtime +of 168 seconds to 78 seconds. Not earth shattering, but significant.

Definition of the test case

From c09b8083217dbf2a06ba4af9b6223a45f3218bed Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Mon, 11 Feb 2019 18:42:10 -0600 Subject: [PATCH 104/507] Address Wolfgang's comments - fix wording - remove author statement (the generic copyright is enough). --- examples/step-20/doc/intro.dox | 36 +++++++++++++++++++++------------- examples/step-20/step-20.cc | 15 +++++--------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/examples/step-20/doc/intro.dox b/examples/step-20/doc/intro.dox index 97bcb989cfaf..7a836f0edf1f 100644 --- a/examples/step-20/doc/intro.dox +++ b/examples/step-20/doc/intro.dox @@ -384,7 +384,8 @@ 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 how they can be implemented in deal.II. +introduce new solution techniques and how they can be implemented in +deal.II.

Solving using the Schur complement

@@ -494,8 +495,8 @@ 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 -have vastly differing norms. This makes control by an absolute tolerance -very error prone. +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$. @@ -515,7 +516,11 @@ similar to the following code: 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). +(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 @@ -539,9 +544,11 @@ class SchurComplement @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, +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; @@ -570,13 +577,14 @@ us. Similarly in spirit to LinearOperator, a PackagedOperation stores a 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: +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 diff --git a/examples/step-20/step-20.cc b/examples/step-20/step-20.cc index 2c4ef1733f02..5879d3b6a1f9 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,10 +12,6 @@ * the top level directory of deal.II. * * --------------------------------------------------------------------- - - * - * Authors: Wolfgang Bangerth, Texas A&M University, 2005, 2006; - * (port to LinearOperator:) Matthias Maier, 2019 */ @@ -607,16 +603,15 @@ namespace Step20 const auto op_M_inv = inverse_operator(op_M, solver_M, preconditioner_M); - // This puts us in the position to be able to declare the Schur - // complement op_S and the approximate Schur complement - // op_aS: + // 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 few CG iterations (until a very modest relative reduction - // of $10^{-3}$ is reached): + // applies a small number of CG iterations (until a very modest + // relative reduction of $10^{-3}$ is reached): ReductionControl reduction_control_aS(2000, 1.e-18, 1.0e-3); SolverCG<> solver_aS(reduction_control_aS); PreconditionIdentity preconditioner_aS; From 8443f7fe715e0a6f44e87e0cb2f4bc10ff2dc3b6 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Mon, 11 Feb 2019 18:46:19 -0600 Subject: [PATCH 105/507] Address J.-P.'s comments --- examples/step-20/doc/intro.dox | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/step-20/doc/intro.dox b/examples/step-20/doc/intro.dox index 7a836f0edf1f..844507e93f30 100644 --- a/examples/step-20/doc/intro.dox +++ b/examples/step-20/doc/intro.dox @@ -605,6 +605,10 @@ creating another solver and inverse: U = op_M_inv * (F - op_B * P); @endcode +@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

From 20e6c36535105ed10156388384573eaf51b29d94 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Mon, 11 Feb 2019 18:53:20 -0600 Subject: [PATCH 106/507] examples/step-22: adjust sizes of pictures showing result --- examples/step-20/doc/results.dox | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/step-20/doc/results.dox b/examples/step-20/doc/results.dox index 85700efea3e6..573fe46f9f09 100644 --- a/examples/step-20/doc/results.dox +++ b/examples/step-20/doc/results.dox @@ -28,9 +28,13 @@ 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: - - - + + + + + + +
From 42021d3a02ff37efd241e0b77b1ebd05bb01daa8 Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Fri, 8 Feb 2019 14:36:02 +0000 Subject: [PATCH 107/507] Change API of a few functions cuda_kernel for consistency --- include/deal.II/base/partitioner.templates.h | 2 +- include/deal.II/lac/cuda_kernels.h | 14 ++-- include/deal.II/lac/cuda_kernels.templates.h | 14 ++-- .../lac/la_parallel_vector.templates.h | 6 +- source/lac/cuda_kernels.cu | 64 +++++++++---------- 5 files changed, 50 insertions(+), 50 deletions(-) diff --git a/include/deal.II/base/partitioner.templates.h b/include/deal.II/base/partitioner.templates.h index 7ccedad7379a..582034a7bc35 100644 --- a/include/deal.II/base/partitioner.templates.h +++ b/include/deal.II/base/partitioner.templates.h @@ -161,8 +161,8 @@ namespace Utilities ::dealii::LinearAlgebra::CUDAWrappers::kernel:: gather<<>>( temp_array_ptr, - locally_owned_array.data(), import_indices_plain_dev[i].first.get(), + locally_owned_array.data(), import_indices_plain_dev[i].second); } else diff --git a/include/deal.II/lac/cuda_kernels.h b/include/deal.II/lac/cuda_kernels.h index 20c5c361ec33..963a9461702a 100644 --- a/include/deal.II/lac/cuda_kernels.h +++ b/include/deal.II/lac/cuda_kernels.h @@ -451,12 +451,12 @@ namespace LinearAlgebra * * @ingroup CUDAWrappers */ - template + template __global__ void - set_permutated(Number * val, + set_permutated(const IndexType *indices, + Number * val, const Number * v, - const size_type *indices, - const size_type N); + const IndexType N); @@ -469,8 +469,8 @@ namespace LinearAlgebra template __global__ void gather(Number * val, - const Number * v, const IndexType *indices, + const Number * v, const IndexType N); @@ -483,9 +483,9 @@ namespace LinearAlgebra */ template __global__ void - add_permutated(Number * val, + add_permutated(const size_type *indices, + Number * val, const Number * v, - const size_type *indices, const size_type N); } // namespace kernel } // namespace CUDAWrappers diff --git a/include/deal.II/lac/cuda_kernels.templates.h b/include/deal.II/lac/cuda_kernels.templates.h index 5d196ddc5cfc..cd522131ba9c 100644 --- a/include/deal.II/lac/cuda_kernels.templates.h +++ b/include/deal.II/lac/cuda_kernels.templates.h @@ -533,12 +533,12 @@ namespace LinearAlgebra - template + template __global__ void - set_permutated(Number * val, + set_permutated(const IndexType *indices, + Number * val, const Number * v, - const size_type *indices, - const size_type N) + const IndexType N) { const size_type idx_base = threadIdx.x + blockIdx.x * (blockDim.x * chunk_size); @@ -555,8 +555,8 @@ namespace LinearAlgebra template __global__ void gather(Number * val, - const Number * v, const IndexType *indices, + const Number * v, const IndexType N) { const IndexType idx_base = @@ -573,9 +573,9 @@ namespace LinearAlgebra template __global__ void - add_permutated(Number * val, + add_permutated(const size_type *indices, + Number * val, const Number * v, - const size_type *indices, const size_type N) { const size_type idx_base = diff --git a/include/deal.II/lac/la_parallel_vector.templates.h b/include/deal.II/lac/la_parallel_vector.templates.h index ae0ec7c9612a..b2e890c30ee5 100644 --- a/include/deal.II/lac/la_parallel_vector.templates.h +++ b/include/deal.II/lac/la_parallel_vector.templates.h @@ -301,7 +301,7 @@ namespace LinearAlgebra ::dealii::CUDAWrappers::block_size); ::dealii::LinearAlgebra::CUDAWrappers::kernel::set_permutated <<>>( - tmp_vector.begin(), V_dev, indices_dev, n_elements); + indices_dev, tmp_vector.begin(), V_dev, n_elements); tmp_vector.compress(operation); @@ -319,16 +319,16 @@ namespace LinearAlgebra if (operation == VectorOperation::add) ::dealii::LinearAlgebra::CUDAWrappers::kernel::add_permutated< Number><<>>( + indices_dev, data.values_dev.get(), tmp_vector.begin(), - indices_dev, tmp_n_elements); else ::dealii::LinearAlgebra::CUDAWrappers::kernel::set_permutated< Number><<>>( + indices_dev, data.values_dev.get(), tmp_vector.begin(), - indices_dev, tmp_n_elements); ::dealii::Utilities::CUDA::free(indices_dev); diff --git a/source/lac/cuda_kernels.cu b/source/lac/cuda_kernels.cu index 317399c74d42..a1c83d59352d 100644 --- a/source/lac/cuda_kernels.cu +++ b/source/lac/cuda_kernels.cu @@ -94,12 +94,12 @@ namespace LinearAlgebra const float * V_val, const size_type N); template __global__ void - equ(float * val, - const float a, - const float * V_val, - const float b, - const float * W_val, - const size_type N); + equ(float * val, + const float a, + const float * V_val, + const float b, + const float * W_val, + const size_type N); template __global__ void add_and_dot(float * res, float * v1, @@ -110,19 +110,19 @@ namespace LinearAlgebra template __global__ void set(float *val, const float s, const size_type N); template __global__ void - set_permutated(float * val, - const float * v, - const size_type *indices, - const size_type N); + set_permutated(const size_type *indices, + float * val, + const float * v, + const size_type N); template __global__ void - gather(float * val, - const float * v, - const size_type *indices, - const size_type N); + gather(float * val, + const size_type *indices, + const float * v, + const size_type N); template __global__ void - add_permutated(float * val, + add_permutated(const size_type *indices, + float * val, const float * v, - const size_type *indices, const size_type N); @@ -194,12 +194,12 @@ namespace LinearAlgebra const double * V_val, const size_type N); template __global__ void - equ(double * val, - const double a, - const double * V_val, - const double b, - const double * W_val, - const size_type N); + equ(double * val, + const double a, + const double * V_val, + const double b, + const double * W_val, + const size_type N); template __global__ void add_and_dot(double * res, double * v1, @@ -210,19 +210,19 @@ namespace LinearAlgebra template __global__ void set(double *val, const double s, const size_type N); template __global__ void - set_permutated(double * val, - const double * v, - const size_type *indices, - const size_type N); + set_permutated(const size_type *indices, + double * val, + const double * v, + const size_type N); template __global__ void - gather(double * val, - const double * v, - const size_type *indices, - const size_type N); + gather(double * val, + const size_type *indices, + const double * v, + const size_type N); template __global__ void - add_permutated(double * val, + add_permutated(const size_type *indices, + double * val, const double * v, - const size_type *indices, const size_type N); } // namespace kernel } // namespace CUDAWrappers From 17a59dbcc69f88d87e048c515cd276619671f7b3 Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Fri, 8 Feb 2019 14:44:36 +0000 Subject: [PATCH 108/507] Move initialization of import_indices_plain_dev into a separate function --- include/deal.II/base/partitioner.h | 7 ++++ include/deal.II/base/partitioner.templates.h | 44 ++------------------ source/base/partitioner.cu | 44 ++++++++++++++++++++ 3 files changed, 54 insertions(+), 41 deletions(-) diff --git a/include/deal.II/base/partitioner.h b/include/deal.II/base/partitioner.h index 2c0db0955f33..c98454dcbec5 100644 --- a/include/deal.II/base/partitioner.h +++ b/include/deal.II/base/partitioner.h @@ -571,6 +571,13 @@ namespace Utilities << " elements for this partitioner."); private: + /** + * Initialize import_indices_plain_dev from import_indices_data. This + * function is only used when using CUDA-aware MPI. + */ + void + initialize_import_indices_plain_dev() const; + /** * The global size of the vector over all processors */ diff --git a/include/deal.II/base/partitioner.templates.h b/include/deal.II/base/partitioner.templates.h index 582034a7bc35..48432cfcbc5f 100644 --- a/include/deal.II/base/partitioner.templates.h +++ b/include/deal.II/base/partitioner.templates.h @@ -105,47 +105,9 @@ namespace Utilities // performance reasons as this can significantly decrease the number of // kernel launched. The indices are expanded the first time the function // is called. - if (std::is_same::value) - { - if (import_indices_plain_dev.size() == 0) - { - import_indices_plain_dev.reserve(n_import_targets); - for (unsigned int i = 0; i < n_import_targets; i++) - { - // Expand the indices on the host - std::vector>:: - const_iterator my_imports = - import_indices_data.begin() + - import_indices_chunks_by_rank_data[i], - end_my_imports = - import_indices_data.begin() + - import_indices_chunks_by_rank_data[i + 1]; - std::vector import_indices_plain_host; - for (; my_imports != end_my_imports; ++my_imports) - { - const unsigned int chunk_size = - my_imports->second - my_imports->first; - for (unsigned int j = 0; j < chunk_size; ++j) - import_indices_plain_host.push_back(my_imports->first + - j); - } - - // Move the indices to the device - import_indices_plain_dev.emplace_back(std::make_pair( - std::unique_ptr( - nullptr, - Utilities::CUDA::delete_device_data), - import_indices_plain_host.size())); - - import_indices_plain_dev[i].first.reset( - Utilities::CUDA::allocate_device_data( - import_indices_plain_dev[i].second)); - Utilities::CUDA::copy_to_dev( - import_indices_plain_host, - import_indices_plain_dev[i].first.get()); - } - } - } + if ((std::is_same::value) && + (import_indices_plain_dev.size() == 0)) + initialize_import_indices_plain_dev(); # endif for (unsigned int i = 0; i < n_import_targets; i++) diff --git a/source/base/partitioner.cu b/source/base/partitioner.cu index ed02193e8914..4788e7571d01 100644 --- a/source/base/partitioner.cu +++ b/source/base/partitioner.cu @@ -18,6 +18,50 @@ DEAL_II_NAMESPACE_OPEN + + +namespace Utilities +{ + namespace MPI + { + void + Partitioner::initialize_import_indices_plain_dev() const + { + const unsigned int n_import_targets = import_targets_data.size(); + import_indices_plain_dev.reserve(n_import_targets); + for (unsigned int i = 0; i < n_import_targets; i++) + { + // Expand the indices on the host + std::vector>::const_iterator + my_imports = import_indices_data.begin() + + import_indices_chunks_by_rank_data[i], + end_my_imports = import_indices_data.begin() + + import_indices_chunks_by_rank_data[i + 1]; + std::vector import_indices_plain_host; + for (; my_imports != end_my_imports; ++my_imports) + { + const unsigned int chunk_size = + my_imports->second - my_imports->first; + for (unsigned int j = 0; j < chunk_size; ++j) + import_indices_plain_host.push_back(my_imports->first + j); + } + + // Move the indices to the device + import_indices_plain_dev.emplace_back(std::make_pair( + std::unique_ptr( + nullptr, Utilities::CUDA::delete_device_data), + import_indices_plain_host.size())); + + import_indices_plain_dev[i].first.reset( + Utilities::CUDA::allocate_device_data( + import_indices_plain_dev[i].second)); + Utilities::CUDA::copy_to_dev(import_indices_plain_host, + import_indices_plain_dev[i].first.get()); + } + } + } // namespace MPI +} // namespace Utilities + // explicit instantiations from .templates.h file #include "partitioner.cuda.inst" From 5cb0fe6b2dcc72ded68ec91519e388382c184fe0 Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Fri, 8 Feb 2019 14:47:25 +0000 Subject: [PATCH 109/507] Add new cuda kernel function to execute a binary operation on a subset of the vector --- include/deal.II/lac/cuda_kernels.h | 17 +++++++++++++++++ include/deal.II/lac/cuda_kernels.templates.h | 18 ++++++++++++++++++ source/lac/cuda_kernels.cu | 20 ++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/include/deal.II/lac/cuda_kernels.h b/include/deal.II/lac/cuda_kernels.h index 963a9461702a..c3470a5749d9 100644 --- a/include/deal.II/lac/cuda_kernels.h +++ b/include/deal.II/lac/cuda_kernels.h @@ -181,6 +181,23 @@ namespace LinearAlgebra + /** + * Apply the functor @tparam Binop to the elements of @p v1 that have + * indices in @p mask and @p v2. The size of @p mask should be greater + * than the size of @p v1. @p mask and @p v2 should have the same size @p + * N. + * + * @ingroup CUDAWrappers + */ + template class Binop> + __global__ void + masked_vector_bin_op(const unsigned int *mask, + Number * v1, + const Number * v2, + const size_type N); + + + /** * Structure implementing the functions used to add elements when * using a reduction. diff --git a/include/deal.II/lac/cuda_kernels.templates.h b/include/deal.II/lac/cuda_kernels.templates.h index cd522131ba9c..cadeb4d11a39 100644 --- a/include/deal.II/lac/cuda_kernels.templates.h +++ b/include/deal.II/lac/cuda_kernels.templates.h @@ -60,6 +60,24 @@ namespace LinearAlgebra + template class Binop> + __global__ void + masked_vector_bin_op(const unsigned int *mask, + Number * v1, + const Number * v2, + const size_type N) + { + const size_type idx_base = + threadIdx.x + blockIdx.x * (blockDim.x * chunk_size); + for (unsigned int i = 0; i < chunk_size; ++i) + { + const size_type idx = idx_base + i * block_size; + if (idx < N) + v1[mask[idx]] = Binop::operation(v1[mask[idx]], v2[idx]); + } + } + + template __device__ Number ElemSum::reduction_op(const Number a, const Number b) diff --git a/source/lac/cuda_kernels.cu b/source/lac/cuda_kernels.cu index a1c83d59352d..c7bfb9b020e3 100644 --- a/source/lac/cuda_kernels.cu +++ b/source/lac/cuda_kernels.cu @@ -37,6 +37,16 @@ namespace LinearAlgebra vector_bin_op(float * v1, const float * v2, const size_type N); + template __global__ void + masked_vector_bin_op(const unsigned int *mask, + float * v1, + const float * v2, + const size_type N); + template __global__ void + masked_vector_bin_op(const unsigned int *mask, + float * v1, + const float * v2, + const size_type N); template struct ElemSum; template struct L1Norm; template struct LInfty; @@ -137,6 +147,16 @@ namespace LinearAlgebra vector_bin_op(double * v1, const double * v2, const size_type N); + template __global__ void + masked_vector_bin_op(const unsigned int *mask, + double * v1, + const double * v2, + const size_type N); + template __global__ void + masked_vector_bin_op(const unsigned int *mask, + double * v1, + const double * v2, + const size_type N); template struct ElemSum; template struct L1Norm; template struct LInfty; From 55026d64f095b6214e9b8635ab83c427345c3758 Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Fri, 8 Feb 2019 14:49:12 +0000 Subject: [PATCH 110/507] Improve compress when using CUDA-aware MPI Reduce the number of kernel launch in a way similar to what is done for update_ghost. --- include/deal.II/base/partitioner.templates.h | 128 +++++++++++-------- 1 file changed, 76 insertions(+), 52 deletions(-) diff --git a/include/deal.II/base/partitioner.templates.h b/include/deal.II/base/partitioner.templates.h index 48432cfcbc5f..4d4b55108dc8 100644 --- a/include/deal.II/base/partitioner.templates.h +++ b/include/deal.II/base/partitioner.templates.h @@ -530,6 +530,18 @@ namespace Utilities const unsigned int n_import_targets = import_targets_data.size(); const unsigned int n_ghost_targets = ghost_targets_data.size(); +# if (defined(DEAL_II_COMPILER_CUDA_AWARE) && \ + defined(DEAL_II_WITH_CUDA_AWARE_MPI)) + // When using CUDAs-aware MPI, the set of local indices that are ghosts + // indices on other processors is expanded in arrays. This is for + // performance reasons as this can significantly decrease the number of + // kernel launched. The indices are expanded the first time the function + // is called. + if ((std::is_same::value) && + (import_indices_plain_dev.size() == 0)) + initialize_import_indices_plain_dev(); +# endif + if (vector_operation != dealii::VectorOperation::insert) AssertDimension(n_ghost_targets + n_import_targets, requests.size()); // first wait for the receive to complete @@ -595,70 +607,82 @@ namespace Utilities # else if (vector_operation == dealii::VectorOperation::add) { - for (const auto &import_range : import_indices_data) + for (auto const &import_indices_plain : import_indices_plain_dev) { - const auto chunk_size = - import_range.second - import_range.first; + const auto chunk_size = import_indices_plain.second; const int n_blocks = 1 + (chunk_size - 1) / (::dealii::CUDAWrappers::chunk_size * ::dealii::CUDAWrappers::block_size); - dealii::LinearAlgebra::CUDAWrappers::kernel::vector_bin_op< - Number, - dealii::LinearAlgebra::CUDAWrappers::kernel::Binop_Addition> + dealii::LinearAlgebra::CUDAWrappers::kernel:: + masked_vector_bin_op <<>>( - locally_owned_array.data() + import_range.first, + import_indices_plain.first.get(), + locally_owned_array.data(), read_position, chunk_size); read_position += chunk_size; } } else if (vector_operation == dealii::VectorOperation::min) - for (const auto &import_range : import_indices_data) - { - const auto chunk_size = - import_range.second - import_range.first; - const int n_blocks = - 1 + (chunk_size - 1) / (::dealii::CUDAWrappers::chunk_size * - ::dealii::CUDAWrappers::block_size); - dealii::LinearAlgebra::CUDAWrappers::kernel::vector_bin_op< - Number, - dealii::LinearAlgebra::CUDAWrappers::kernel::Binop_Min> - <<>>( - locally_owned_array.data() + import_range.first, - read_position, - chunk_size); - read_position += chunk_size; - } + { + for (auto const &import_indices_plain : import_indices_plain_dev) + { + const auto chunk_size = import_indices_plain.second; + const int n_blocks = + 1 + (chunk_size - 1) / (::dealii::CUDAWrappers::chunk_size * + ::dealii::CUDAWrappers::block_size); + dealii::LinearAlgebra::CUDAWrappers::kernel:: + masked_vector_bin_op< + Number, + dealii::LinearAlgebra::CUDAWrappers::kernel::Binop_Min> + <<>>( + import_indices_plain.first.get(), + locally_owned_array.data(), + read_position, + chunk_size); + read_position += chunk_size; + } + } else if (vector_operation == dealii::VectorOperation::max) - for (const auto &import_range : import_indices_data) - { - const auto chunk_size = - import_range.second - import_range.first; - const int n_blocks = - 1 + (chunk_size - 1) / (::dealii::CUDAWrappers::chunk_size * - ::dealii::CUDAWrappers::block_size); - dealii::LinearAlgebra::CUDAWrappers::kernel::vector_bin_op< - Number, - dealii::LinearAlgebra::CUDAWrappers::kernel::Binop_Max> - <<>>( - locally_owned_array.data() + import_range.first, - read_position, - chunk_size); - read_position += chunk_size; - } - else // TODO - for (const auto &import_range : import_indices_data) - { - const auto chunk_size = - import_range.second - import_range.first; - const cudaError_t cuda_error_code = - cudaMemcpy(locally_owned_array.data() + import_range.first, - read_position, - chunk_size * sizeof(Number), - cudaMemcpyDeviceToDevice); - AssertCuda(cuda_error_code); - read_position += chunk_size; - } + { + for (auto const &import_indices_plain : import_indices_plain_dev) + { + const auto chunk_size = import_indices_plain.second; + const int n_blocks = + 1 + (chunk_size - 1) / (::dealii::CUDAWrappers::chunk_size * + ::dealii::CUDAWrappers::block_size); + dealii::LinearAlgebra::CUDAWrappers::kernel:: + masked_vector_bin_op< + Number, + dealii::LinearAlgebra::CUDAWrappers::kernel::Binop_Max> + <<>>( + import_indices_plain.first.get(), + locally_owned_array.data(), + read_position, + chunk_size); + read_position += chunk_size; + } + } + else + { + for (auto const &import_indices_plain : import_indices_plain_dev) + { + const auto chunk_size = import_indices_plain.second; + const int n_blocks = + 1 + (chunk_size - 1) / (::dealii::CUDAWrappers::chunk_size * + ::dealii::CUDAWrappers::block_size); + dealii::LinearAlgebra::CUDAWrappers::kernel:: + set_permutated<<>>( + import_indices_plain.first.get(), + locally_owned_array.data(), + read_position, + chunk_size); + read_position += chunk_size; + } + } # endif AssertDimension(read_position - temporary_storage.data(), n_import_indices()); From 6dd31bf3b49e405dce3c4f66e85d575cccd24b25 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Tue, 12 Feb 2019 00:19:47 -0600 Subject: [PATCH 111/507] examples/step-20: Change preconditioner to a fixed number of iterations This improves the total runtime performance with preconditioner significantly! (Even though the total number of iterations increases significantly.) --- examples/step-20/doc/intro.dox | 27 ++++++++++++++++++--------- examples/step-20/step-20.cc | 9 ++++----- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/examples/step-20/doc/intro.dox b/examples/step-20/doc/intro.dox index 844507e93f30..773141dfcc73 100644 --- a/examples/step-20/doc/intro.dox +++ b/examples/step-20/doc/intro.dox @@ -654,12 +654,21 @@ 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 nearly already have the preconditioner: it should be the -inverse of the approximate Schur complement. We implement this again with -the inverse_operator() function +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 - ReductionControl reduction_control_aS(2000, 1.e-18, 1.0e-6); - SolverCG<> solver_aS(reduction_control_aS); + 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); @@ -672,15 +681,15 @@ 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 7 times refined meshes using elements of order 0, the number of -outer iterations drops from 592 to 25. On the other hand, we now have to apply +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.48 seconds for this test case. That doesn't seem too +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 28 outer iterations, at a runtime -of 168 seconds to 78 seconds. Not earth shattering, but significant. +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/step-20.cc b/examples/step-20/step-20.cc index 5879d3b6a1f9..f1b12f6e185d 100644 --- a/examples/step-20/step-20.cc +++ b/examples/step-20/step-20.cc @@ -610,11 +610,10 @@ namespace Step20 transpose_operator(op_B) * linear_operator(preconditioner_M) * op_B; // We now create a preconditioner out of op_aS that - // applies a small number of CG iterations (until a very modest - // relative reduction of $10^{-3}$ is reached): - ReductionControl reduction_control_aS(2000, 1.e-18, 1.0e-3); - SolverCG<> solver_aS(reduction_control_aS); - PreconditionIdentity preconditioner_aS; + // 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); + PreconditionIdentity preconditioner_aS; const auto preconditioner_S = inverse_operator(op_aS, solver_aS, preconditioner_aS); From 8a6f81ce9302d587b878abcdf390dd42b72e8fad Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Thu, 7 Feb 2019 12:23:56 +0100 Subject: [PATCH 112/507] Clean up iteration of PreconditionChebyshev. --- include/deal.II/lac/precondition.h | 523 ++++++++++++++++------------- 1 file changed, 284 insertions(+), 239 deletions(-) diff --git a/include/deal.II/lac/precondition.h b/include/deal.II/lac/precondition.h index be50dd34a702..94ecb0e76f65 100644 --- a/include/deal.II/lac/precondition.h +++ b/include/deal.II/lac/precondition.h @@ -871,13 +871,26 @@ class PreconditionPSOR : public PreconditionRelaxation * matrices. This preconditioner is based on an iteration of an inner * preconditioner of type @p PreconditionerType with coefficients that are * adapted to optimally cover an eigenvalue range between the largest - * eigenvalue down to a given lower eigenvalue specified by the optional - * parameter @p smoothing_range. The typical use case for the preconditioner - * is a Jacobi preconditioner specified through DiagonalMatrix, which is also - * the default value for the preconditioner. Note that if the degree variable - * is set to zero, the Chebyshev iteration corresponds to a Jacobi - * preconditioner (or the underlying preconditioner type) with relaxation - * parameter according to the specified smoothing range. + * eigenvalue $\lambda_{\max{}}$ down to a given lower eigenvalue + * $\lambda_{\min{}}$ specified by the optional parameter + * @p smoothing_range. The algorithm is based on the following three-term + * recurrence: + * @f[ + * x^{n+1} = x^{n} + \rho_n \rho_{n-1} (x^{n} - x^{n-1}) + + * \frac{\rho_n}{\lambda_{\max{}}-\lambda_{\min{}}} P^{-1} (b-Ax^n). + * @f] + * where the parameter $rho_0$ is set to $rho_0 = + * \frac{\lambda_{\max{}}-\lambda_{\min{}}}{\lambda_{\max{}}+\lambda_{\min{}}}$ + * for the maximal eigenvalue $\lambda_{\max{}}$ and updated via $\rho_n = + * \left(2\frac{\lambda_{\max{}}+\lambda_{\min{}}} + * {\lambda_{\max{}}-\lambda_{\min{}}} - \rho_{n-1}\right)^{-1}$. + * + * The typical use case for the preconditioner is a Jacobi preconditioner + * specified through DiagonalMatrix, which is also the default value for the + * preconditioner. Note that if the degree variable is set to zero, the + * Chebyshev iteration corresponds to a Jacobi preconditioner (or the + * underlying preconditioner type) with relaxation parameter according to the + * specified smoothing range. * * Besides the default choice of a pointwise Jacobi preconditioner, this class * also allows for more advanced types of preconditioners, for example @@ -895,11 +908,13 @@ class PreconditionPSOR : public PreconditionRelaxation * The Chebyshev method relies on an estimate of the eigenvalues of the matrix * which are computed during the first invocation of vmult(). The algorithm * invokes a conjugate gradient solver so symmetry and positive definiteness - * of the (preconditioned) matrix system are strong requirements. The - * computation of eigenvalues needs to be deferred until the first vmult() - * invocation because temporary vectors of the same layout as the source and - * destination vectors are necessary for these computations and this - * information gets only available through vmult(). + * of the (preconditioned) matrix system are strong requirements. As a + * consequence, this class only makes sense if it is applied repeatedly, + * e.g. in a smoother for a multigrid algorithm. The computation of + * eigenvalues needs to be deferred until the first vmult() invocation because + * temporary vectors of the same layout as the source and destination vectors + * are necessary for these computations and this information gets only + * available through vmult(). * * The estimation of eigenvalues can also be bypassed by setting * PreconditionChebyshev::AdditionalData::eig_cg_n_iterations to zero and @@ -976,7 +991,7 @@ class PreconditionChebyshev : public Subscriptor /** * Constructor. */ - AdditionalData(const unsigned int degree = 0, + AdditionalData(const unsigned int degree = 1, const double smoothing_range = 0., const bool nonzero_starting = false, const unsigned int eig_cg_n_iterations = 8, @@ -986,7 +1001,7 @@ class PreconditionChebyshev : public Subscriptor /** * This determines the degree of the Chebyshev polynomial. The degree of * the polynomial gives the number of matrix-vector products to be - * performed for one application of the vmult() operation. Degree zero + * performed for one application of the vmult() operation. Degree one * corresponds to a damped Jacobi method. * * If the degree is set to numbers::invalid_unsigned_int, the algorithm @@ -1132,17 +1147,17 @@ class PreconditionChebyshev : public Subscriptor /** * Internal vector used for the vmult operation. */ - mutable VectorType update1; + mutable VectorType solution_old; /** * Internal vector used for the vmult operation. */ - mutable VectorType update2; + mutable VectorType temp_vector1; /** * Internal vector used for the vmult operation. */ - mutable VectorType update3; + mutable VectorType temp_vector2; /** * Stores the additional data passed to the initialize function, obtained @@ -1173,22 +1188,6 @@ class PreconditionChebyshev : public Subscriptor */ mutable Threads::Mutex mutex; - /** - * Runs the inner loop of the Chebyshev preconditioner that is the same for - * vmult() and step() methods. - */ - void - do_chebyshev_loop(VectorType &dst, const VectorType &src) const; - - /** - * Runs the inner loop of the Chebyshev preconditioner that is the same for - * vmult() and step() methods. Uses a separate function to not force users - * to provide both vmult() and Tvmult() in case only one variant is - * requested in subsequent calls. - */ - void - do_transpose_chebyshev_loop(VectorType &dst, const VectorType &src) const; - /** * Initializes the factors theta and delta based on an eigenvalue * computation. If the user set provided values for the largest eigenvalue @@ -1760,33 +1759,42 @@ namespace internal // generic part for non-deal.II vectors template inline void - vector_updates(const VectorType & src, + vector_updates(const VectorType & rhs, const PreconditionerType &preconditioner, - const bool start_zero, + const unsigned int iteration_index, const double factor1, const double factor2, - VectorType & update1, - VectorType & update2, - VectorType & update3, - VectorType & dst) + VectorType & solution_old, + VectorType & temp_vector1, + VectorType & temp_vector2, + VectorType & solution) { - if (start_zero) + if (iteration_index == 0) { - update1.equ(factor2, src); - preconditioner.vmult(dst, update1); - update1.equ(-1., dst); + solution.equ(factor2, rhs); + preconditioner.vmult(solution_old, solution); + } + else if (iteration_index == 1) + { + // compute t = P^{-1} * (b-A*x^{n}) + temp_vector1.sadd(-1.0, 1.0, rhs); + preconditioner.vmult(solution_old, temp_vector1); + + // compute x^{n+1} = x^{n} + f_1 * x^{n} + f_2 * t + solution_old.sadd(factor2, 1 + factor1, solution); } else { - update2 -= src; - preconditioner.vmult(update3, update2); - update2 = update3; - if (factor1 == 0.) - update1.equ(factor2, update2); - else - update1.sadd(factor1, factor2, update2); - dst -= update1; + // compute t = P^{-1} * (b-A*x^{n}) + temp_vector1.sadd(-1.0, 1.0, rhs); + preconditioner.vmult(temp_vector2, temp_vector1); + + // compute x^{n+1} = x^{n} + f_1 * (x^{n}-x^{n-1}) + f_2 * t + solution_old.sadd(-factor1, factor2, temp_vector2); + solution_old.add(1 + factor1, solution); } + + solution.swap(solution_old); } // worker routine for deal.II vectors. Because of vectorization, we need @@ -1795,23 +1803,22 @@ namespace internal template struct VectorUpdater { - VectorUpdater(const Number *src, - const Number *matrix_diagonal_inverse, - const bool start_zero, - const Number factor1, - const Number factor2, - Number * update1, - Number * update2, - Number * dst) - : src(src) + VectorUpdater(const Number * rhs, + const Number * matrix_diagonal_inverse, + const unsigned int iteration_index, + const Number factor1, + const Number factor2, + Number * solution_old, + Number * tmp_vector, + Number * solution) + : rhs(rhs) , matrix_diagonal_inverse(matrix_diagonal_inverse) - , do_startup(factor1 == Number()) - , start_zero(start_zero) + , iteration_index(iteration_index) , factor1(factor1) , factor2(factor2) - , update1(update1) - , update2(update2) - , dst(dst) + , solution_old(solution_old) + , tmp_vector(tmp_vector) + , solution(solution) {} void @@ -1821,46 +1828,46 @@ namespace internal // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63945), we create // copies of the variables factor1 and factor2 and do not check based on // factor1. - const Number factor1 = this->factor1; - const Number factor2 = this->factor2; - if (do_startup) + const Number factor1 = this->factor1; + const Number factor1_plus_1 = 1. + this->factor1; + const Number factor2 = this->factor2; + if (iteration_index == 0) { - if (start_zero) - DEAL_II_OPENMP_SIMD_PRAGMA + DEAL_II_OPENMP_SIMD_PRAGMA for (std::size_t i = begin; i < end; ++i) - { - dst[i] = factor2 * src[i] * matrix_diagonal_inverse[i]; - update1[i] = -dst[i]; - } - else DEAL_II_OPENMP_SIMD_PRAGMA for (std::size_t i = begin; i < end; - ++i) - { - update1[i] = - ((update2[i] - src[i]) * factor2 * matrix_diagonal_inverse[i]); - dst[i] -= update1[i]; - } + solution[i] = factor2 * matrix_diagonal_inverse[i] * rhs[i]; + } + else if (iteration_index == 1) + { + // x^{n+1} = x^{n} + f_1 * x^{n} + f_2 * P^{-1} * (b-A*x^{n}) + DEAL_II_OPENMP_SIMD_PRAGMA + for (std::size_t i = begin; i < end; ++i) + // for efficiency reason, write back to temp_vector that is + // already read (avoid read-for-ownership) + tmp_vector[i] = + factor1_plus_1 * solution[i] + + factor2 * matrix_diagonal_inverse[i] * (rhs[i] - tmp_vector[i]); } else - DEAL_II_OPENMP_SIMD_PRAGMA - for (std::size_t i = begin; i < end; ++i) { - const Number update = - factor1 * update1[i] + - factor2 * ((update2[i] - src[i]) * matrix_diagonal_inverse[i]); - update1[i] = update; - dst[i] -= update; + // x^{n+1} = x^{n} + f_1 * (x^{n}-x^{n-1}) + // + f_2 * P^{-1} * (b-A*x^{n}) + DEAL_II_OPENMP_SIMD_PRAGMA + for (std::size_t i = begin; i < end; ++i) + solution_old[i] = + factor1_plus_1 * solution[i] - factor1 * solution_old[i] + + factor2 * matrix_diagonal_inverse[i] * (rhs[i] - tmp_vector[i]); } } - const Number * src; - const Number * matrix_diagonal_inverse; - const bool do_startup; - const bool start_zero; - const Number factor1; - const Number factor2; - mutable Number *update1; - mutable Number *update2; - mutable Number *dst; + const Number * rhs; + const Number * matrix_diagonal_inverse; + const unsigned int iteration_index; + const Number factor1; + const Number factor2; + mutable Number * solution_old; + mutable Number * tmp_vector; + mutable Number * solution; }; template @@ -1894,51 +1901,69 @@ namespace internal // selection for diagonal matrix around deal.II vector template inline void - vector_updates(const ::dealii::Vector & src, + vector_updates(const ::dealii::Vector & rhs, const DiagonalMatrix<::dealii::Vector> &jacobi, - const bool start_zero, - const double factor1, - const double factor2, - ::dealii::Vector & update1, - ::dealii::Vector & update2, + const unsigned int iteration_index, + const double factor1, + const double factor2, + ::dealii::Vector &solution_old, + ::dealii::Vector &temp_vector1, ::dealii::Vector &, - ::dealii::Vector &dst) + ::dealii::Vector &solution) { - VectorUpdater upd(src.begin(), + VectorUpdater upd(rhs.begin(), jacobi.get_vector().begin(), - start_zero, + iteration_index, factor1, factor2, - update1.begin(), - update2.begin(), - dst.begin()); - VectorUpdatesRange(upd, src.size()); + solution_old.begin(), + temp_vector1.begin(), + solution.begin()); + VectorUpdatesRange(upd, rhs.size()); + + // swap vectors x^{n+1}->x^{n}, given the updates in the function above + if (iteration_index == 1) + { + solution.swap(temp_vector1); + solution_old.swap(temp_vector1); + } + else if (iteration_index > 1) + solution.swap(solution_old); } // selection for diagonal matrix around parallel deal.II vector template inline void vector_updates( - const LinearAlgebra::distributed::Vector &src, + const LinearAlgebra::distributed::Vector &rhs, const DiagonalMatrix< LinearAlgebra::distributed::Vector> &jacobi, - const bool start_zero, - const double factor1, - const double factor2, - LinearAlgebra::distributed::Vector & update1, - LinearAlgebra::distributed::Vector & update2, + const unsigned int iteration_index, + const double factor1, + const double factor2, + LinearAlgebra::distributed::Vector &solution_old, + LinearAlgebra::distributed::Vector &temp_vector1, LinearAlgebra::distributed::Vector &, - LinearAlgebra::distributed::Vector &dst) + LinearAlgebra::distributed::Vector &solution) { - VectorUpdater upd(src.begin(), + VectorUpdater upd(rhs.begin(), jacobi.get_vector().begin(), - start_zero, + iteration_index, factor1, factor2, - update1.begin(), - update2.begin(), - dst.begin()); - VectorUpdatesRange(upd, src.local_size()); + solution_old.begin(), + temp_vector1.begin(), + solution.begin()); + VectorUpdatesRange(upd, rhs.local_size()); + + // swap vectors x^{n+1}->x^{n}, given the updates in the function above + if (iteration_index == 1) + { + solution.swap(temp_vector1); + solution_old.swap(temp_vector1); + } + else if (iteration_index > 1) + solution.swap(solution_old); } template ::initialize( { matrix_ptr = &matrix; data = additional_data; + Assert(data.degree > 0, + ExcMessage("The degree of the Chebyshev method must be positive.")); internal::PreconditionChebyshevImplementation::initialize_preconditioner( matrix, data.preconditioner, data.matrix_diagonal_inverse); eigenvalues_are_initialized = false; @@ -2112,9 +2139,9 @@ PreconditionChebyshev::clear() { VectorType empty_vector; data.matrix_diagonal_inverse.reinit(empty_vector); - update1.reinit(empty_vector); - update2.reinit(empty_vector); - update3.reinit(empty_vector); + solution_old.reinit(empty_vector); + temp_vector1.reinit(empty_vector); + temp_vector2.reinit(empty_vector); } data.preconditioner.reset(); } @@ -2129,8 +2156,8 @@ PreconditionChebyshev:: Assert(eigenvalues_are_initialized == false, ExcInternalError()); Assert(data.preconditioner.get() != nullptr, ExcNotInitialized()); - update1.reinit(src); - update2.reinit(src, true); + solution_old.reinit(src); + temp_vector1.reinit(src, true); // calculate largest eigenvalue using a hand-tuned CG iteration on the // matrix weighted by its diagonal. we start with a vector that consists of @@ -2161,11 +2188,15 @@ PreconditionChebyshev:: // set an initial guess which is close to the constant vector but where // one entry is different to trigger high frequencies - internal::PreconditionChebyshevImplementation::set_initial_guess(update2); + internal::PreconditionChebyshevImplementation::set_initial_guess( + temp_vector1); try { - solver.solve(*matrix_ptr, update1, update2, *data.preconditioner); + solver.solve(*matrix_ptr, + solution_old, + temp_vector1, + *data.preconditioner); } catch (SolverControl::NoConvergence &) {} @@ -2219,24 +2250,21 @@ PreconditionChebyshev:: PreconditionChebyshev *>(this) ->theta = (max_eigenvalue + alpha) * 0.5; - // We do not need the third auxiliary vector in case we have a + // We do not need the second temporary vector in case we have a // DiagonalMatrix as preconditioner and use deal.II's own vectors + using NumberType = typename VectorType::value_type; if (std::is_same>::value == false || - (std::is_same>::value == - false && - ((std::is_same< - VectorType, - LinearAlgebra::distributed::Vector>::value == + (std::is_same>::value == false && + ((std::is_same>::value == false) || - (std::is_same< - VectorType, - LinearAlgebra::distributed::Vector>::value == + (std::is_same>::value == false)))) - update3.reinit(src, true); + temp_vector2.reinit(src, true); const_cast< PreconditionChebyshev *>(this) @@ -2247,34 +2275,47 @@ PreconditionChebyshev:: template inline void -PreconditionChebyshev:: - do_chebyshev_loop(VectorType &dst, const VectorType &src) const +PreconditionChebyshev::vmult( + VectorType & solution, + const VectorType &rhs) const { - if (data.degree < 2) - return; + std::lock_guard lock(mutex); + if (eigenvalues_are_initialized == false) + estimate_eigenvalues(rhs); + + internal::PreconditionChebyshevImplementation::vector_updates( + rhs, + *data.preconditioner, + 0, + 0., + 1. / theta, + solution_old, + temp_vector1, + temp_vector2, + solution); // if delta is zero, we do not need to iterate because the updates will be // zero - if (std::abs(delta) < 1e-40) + if (data.degree < 2 || std::abs(delta) < 1e-40) return; double rhok = delta / theta, sigma = theta / delta; for (unsigned int k = 0; k < data.degree - 1; ++k) { - matrix_ptr->vmult(update2, dst); + matrix_ptr->vmult(temp_vector1, solution); const double rhokp = 1. / (2. * sigma - rhok); const double factor1 = rhokp * rhok, factor2 = 2. * rhokp / delta; rhok = rhokp; internal::PreconditionChebyshevImplementation::vector_updates( - src, + rhs, *data.preconditioner, - false, + k + 1, factor1, factor2, - update1, - update2, - update3, - dst); + solution_old, + temp_vector1, + temp_vector2, + solution); } } @@ -2282,109 +2323,93 @@ PreconditionChebyshev:: template inline void -PreconditionChebyshev:: - do_transpose_chebyshev_loop(VectorType &dst, const VectorType &src) const +PreconditionChebyshev::Tvmult( + VectorType & solution, + const VectorType &rhs) const { - if (data.degree < 2) + std::lock_guard lock(mutex); + if (eigenvalues_are_initialized == false) + estimate_eigenvalues(rhs); + + internal::PreconditionChebyshevImplementation::vector_updates( + rhs, + *data.preconditioner, + 0, + 0., + 1. / theta, + solution_old, + temp_vector1, + temp_vector2, + solution); + + if (data.degree < 2 || std::abs(delta) < 1e-40) return; double rhok = delta / theta, sigma = theta / delta; for (unsigned int k = 0; k < data.degree - 1; ++k) { - matrix_ptr->Tvmult(update2, dst); + matrix_ptr->Tvmult(temp_vector1, solution); const double rhokp = 1. / (2. * sigma - rhok); const double factor1 = rhokp * rhok, factor2 = 2. * rhokp / delta; rhok = rhokp; internal::PreconditionChebyshevImplementation::vector_updates( - src, + rhs, *data.preconditioner, - false, + k + 1, factor1, factor2, - update1, - update2, - update3, - dst); + solution_old, + temp_vector1, + temp_vector2, + solution); } } -template -inline void -PreconditionChebyshev::vmult( - VectorType & dst, - const VectorType &src) const -{ - std::lock_guard lock(mutex); - if (eigenvalues_are_initialized == false) - estimate_eigenvalues(src); - - internal::PreconditionChebyshevImplementation::vector_updates( - src, - *data.preconditioner, - true, - 0., - 1. / theta, - update1, - update2, - update3, - dst); - - do_chebyshev_loop(dst, src); -} - - - -template -inline void -PreconditionChebyshev::Tvmult( - VectorType & dst, - const VectorType &src) const -{ - std::lock_guard lock(mutex); - if (eigenvalues_are_initialized == false) - estimate_eigenvalues(src); - - internal::PreconditionChebyshevImplementation::vector_updates( - src, - *data.preconditioner, - true, - 0., - 1. / theta, - update1, - update2, - update3, - dst); - - do_transpose_chebyshev_loop(dst, src); -} - - - template inline void PreconditionChebyshev::step( - VectorType & dst, - const VectorType &src) const + VectorType & solution, + const VectorType &rhs) const { std::lock_guard lock(mutex); if (eigenvalues_are_initialized == false) - estimate_eigenvalues(src); + estimate_eigenvalues(rhs); - matrix_ptr->vmult(update2, dst); + matrix_ptr->vmult(temp_vector1, solution); internal::PreconditionChebyshevImplementation::vector_updates( - src, + rhs, *data.preconditioner, - false, + 1, 0., 1. / theta, - update1, - update2, - update3, - dst); + solution_old, + temp_vector1, + temp_vector2, + solution); + + if (data.degree < 2 || std::abs(delta) < 1e-40) + return; - do_chebyshev_loop(dst, src); + double rhok = delta / theta, sigma = theta / delta; + for (unsigned int k = 0; k < data.degree - 1; ++k) + { + matrix_ptr->vmult(temp_vector1, solution); + const double rhokp = 1. / (2. * sigma - rhok); + const double factor1 = rhokp * rhok, factor2 = 2. * rhokp / delta; + rhok = rhokp; + internal::PreconditionChebyshevImplementation::vector_updates( + rhs, + *data.preconditioner, + k + 2, + factor1, + factor2, + solution_old, + temp_vector1, + temp_vector2, + solution); + } } @@ -2392,26 +2417,46 @@ PreconditionChebyshev::step( template inline void PreconditionChebyshev::Tstep( - VectorType & dst, - const VectorType &src) const + VectorType & solution, + const VectorType &rhs) const { std::lock_guard lock(mutex); if (eigenvalues_are_initialized == false) - estimate_eigenvalues(src); + estimate_eigenvalues(rhs); - matrix_ptr->Tvmult(update2, dst); + matrix_ptr->Tvmult(temp_vector1, solution); internal::PreconditionChebyshevImplementation::vector_updates( - src, + rhs, *data.preconditioner, - false, + 1, 0., 1. / theta, - update1, - update2, - update3, - dst); + solution_old, + temp_vector1, + temp_vector2, + solution); + + if (data.degree < 2 || std::abs(delta) < 1e-40) + return; - do_transpose_chebyshev_loop(dst, src); + double rhok = delta / theta, sigma = theta / delta; + for (unsigned int k = 0; k < data.degree - 1; ++k) + { + matrix_ptr->Tvmult(temp_vector1, solution); + const double rhokp = 1. / (2. * sigma - rhok); + const double factor1 = rhokp * rhok, factor2 = 2. * rhokp / delta; + rhok = rhokp; + internal::PreconditionChebyshevImplementation::vector_updates( + rhs, + *data.preconditioner, + k + 2, + factor1, + factor2, + solution_old, + temp_vector1, + temp_vector2, + solution); + } } From 63f795652168082d5ed2124258500b8e454e2d5b Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Thu, 7 Feb 2019 12:26:11 +0100 Subject: [PATCH 113/507] Add changelog. --- doc/news/changes/minor/20190207MartinKronbichler | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 doc/news/changes/minor/20190207MartinKronbichler 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) From 1b3760abe97fe7dbe6efaaccebd356ccc7a35402 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Thu, 7 Feb 2019 18:09:54 +0100 Subject: [PATCH 114/507] Augment documentation about eigenvalue computation. --- include/deal.II/lac/precondition.h | 73 ++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/include/deal.II/lac/precondition.h b/include/deal.II/lac/precondition.h index 94ecb0e76f65..7d21d2cc0c95 100644 --- a/include/deal.II/lac/precondition.h +++ b/include/deal.II/lac/precondition.h @@ -883,7 +883,10 @@ class PreconditionPSOR : public PreconditionRelaxation * \frac{\lambda_{\max{}}-\lambda_{\min{}}}{\lambda_{\max{}}+\lambda_{\min{}}}$ * for the maximal eigenvalue $\lambda_{\max{}}$ and updated via $\rho_n = * \left(2\frac{\lambda_{\max{}}+\lambda_{\min{}}} - * {\lambda_{\max{}}-\lambda_{\min{}}} - \rho_{n-1}\right)^{-1}$. + * {\lambda_{\max{}}-\lambda_{\min{}}} - \rho_{n-1}\right)^{-1}$. The + * Chebyshev polynomial is constructed to strongly damp the eigenvalue range + * between $\lambda_{\min{}}$ and $\lambda_{\max{}}$ and is visualized e.g. in + * Utilities::LinearAlgebra::chebyshev_filter(). * * The typical use case for the preconditioner is a Jacobi preconditioner * specified through DiagonalMatrix, which is also the default value for the @@ -903,28 +906,52 @@ class PreconditionPSOR : public PreconditionRelaxation * products are %parallel and the inner preconditioner is %parallel). Its use * is demonstrated in the step-37 tutorial program. * - *

Algorithm execution

+ *

Estimation of the eigenvalues

* * The Chebyshev method relies on an estimate of the eigenvalues of the matrix * which are computed during the first invocation of vmult(). The algorithm * invokes a conjugate gradient solver so symmetry and positive definiteness - * of the (preconditioned) matrix system are strong requirements. As a - * consequence, this class only makes sense if it is applied repeatedly, - * e.g. in a smoother for a multigrid algorithm. The computation of - * eigenvalues needs to be deferred until the first vmult() invocation because + * of the (preconditioned) matrix system are requirements. The eigenvalue + * algorithm can be controlled by + * PreconditionChebyshev::AdditionalData::eig_cg_n_iterations specifying how + * many iterations should be performed. The iterations are started from an + * initial vector that depends on the vector type. For the classes + * dealii::Vector or dealii::LinearAlgebra::distributed::Vector, which have + * fast element access, it is either a vector with entries `(-5.5, -4.5, -3.5, + * -2.5, ..., 3.5, 4.5, 5.5)` with appropriate epilogue and adjusted such that + * its mean is always zero, which works well for the Laplacian. For other + * vector types, the initial vector contains all ones, scaled by the length of + * the vector, except for the very first entry that is zero, triggering + * high-frequency content again. + * + * The computation of eigenvalues happens the first time one of the + * vmult(), Tvmult(), step() or Tstep() functions is called. This is because * temporary vectors of the same layout as the source and destination vectors * are necessary for these computations and this information gets only * available through vmult(). * - * The estimation of eigenvalues can also be bypassed by setting - * PreconditionChebyshev::AdditionalData::eig_cg_n_iterations to zero and - * providing sensible values for the largest eigenvalues in the field - * PreconditionChebyshev::AdditionalData::max_eigenvalue. If the range - * [max_eigenvalue/smoothing_range, max_eigenvalue] contains all - * eigenvalues of the preconditioned matrix system and the degree (i.e., - * number of iterations) is high enough, this class can also be used as a - * direct solver. For an error estimation of the Chebyshev iteration that can - * be used to determine the number of iteration, see Varga (2009). + * Due to the cost of the eigenvalue estimate in the first vmult(), this class + * is most appropriate if it is applied repeatedly, e.g. in a smoother for a + * algorithm. + * + *

Bypassing the eigenvalue computation

+ * + * In some contexts, the automatic eigenvalue computation of this class may + * result in bad quality, or it may be unstable when used in parallel with + * different enumerations of the degrees of freedom, making computations + * strongly dependent on the parallel configuration. It is possible to bypass + * the automatic eigenvalue computation by setting + * AdditionalData::eig_cg_n_iterations to zero, and provide the variable + * AdditionalData::max_eigenvalue instead. The minimal eigenvalue is + * implicitly specified via `max_eigenvalue/smoothing_range`. + + *

Using the PreconditionChebyshev as a solver

+ * + * If the range [max_eigenvalue/smoothing_range, max_eigenvalue] + * contains all eigenvalues of the preconditioned matrix system and the degree + * (i.e., number of iterations) is high enough, this class can also be used as + * a direct solver. For an error estimation of the Chebyshev iteration that + * can be used to determine the number of iteration, see Varga (2009). * * In order to use Chebyshev as a solver, set the degree to * numbers::invalid_unsigned_int to force the automatic computation of the @@ -953,11 +980,11 @@ class PreconditionPSOR : public PreconditionRelaxation * PreconditionChebyshev. The preconditioner is held in a shared_ptr that is * copied into the AdditionalData member variable of the class, so the * variable used for initialization can safely be discarded after calling - * initialize(). Both the matrix and the preconditioner need to provide @p - * vmult functions for the matrix-vector product and @p m functions for + * initialize(). Both the matrix and the preconditioner need to provide + * @p vmult() functions for the matrix-vector product and @p m() functions for * accessing the number of rows in the (square) matrix. Furthermore, the * matrix must provide el(i,i) methods for accessing the matrix - * diagonal in case the preconditioner type is a diagonal matrix. Even though + * diagonal in case the preconditioner type is DiagonalMatrix. Even though * it is highly recommended to pass the inverse diagonal entries inside a * separate preconditioner object for implementing the Jacobi method (which is * the only possible way to operate this class when computing in %parallel @@ -1040,8 +1067,9 @@ class PreconditionChebyshev : public Subscriptor /** * Maximum number of CG iterations performed for finding the maximum - * eigenvalue. If set to zero, no computations are performed and the - * eigenvalues according to the given input are used instead. + * eigenvalue. If set to zero, no computations are performed. Instead, the + * user must supply a largest eigenvalue via the variable + * PreconditionChebyshev::AdditionalData::max_eigenvalue. */ unsigned int eig_cg_n_iterations; @@ -2265,6 +2293,11 @@ PreconditionChebyshev:: Vector>::value == false)))) temp_vector2.reinit(src, true); + else + { + VectorType empty_vector; + temp_vector2.reinit(empty_vector); + } const_cast< PreconditionChebyshev *>(this) From d3b96e1585d4a698ff9684fc3225d24cb9dabb3f Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Sat, 9 Feb 2019 11:02:01 +0100 Subject: [PATCH 115/507] Adjust test to definition of Chebyshev degree. --- tests/matrix_free/parallel_multigrid_adaptive_08.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/matrix_free/parallel_multigrid_adaptive_08.cc b/tests/matrix_free/parallel_multigrid_adaptive_08.cc index 4fb6c2b0c433..8c6b201129c1 100644 --- a/tests/matrix_free/parallel_multigrid_adaptive_08.cc +++ b/tests/matrix_free/parallel_multigrid_adaptive_08.cc @@ -342,7 +342,7 @@ do_test(const DoFHandler &dof) ++level) { smoother_data[level].smoothing_range = 15.; - smoother_data[level].degree = 5; + smoother_data[level].degree = 6; smoother_data[level].eig_cg_n_iterations = 15; smoother_data[level].preconditioner = mg_matrices[level].get_matrix_diagonal_inverse(); From 75eec859751d6275780b23015c6943087acbc5ed Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Sat, 9 Feb 2019 18:48:16 +0100 Subject: [PATCH 116/507] Add a comment about iteration 0. --- include/deal.II/lac/precondition.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/include/deal.II/lac/precondition.h b/include/deal.II/lac/precondition.h index 7d21d2cc0c95..900c474fc7a6 100644 --- a/include/deal.II/lac/precondition.h +++ b/include/deal.II/lac/precondition.h @@ -1950,12 +1950,17 @@ namespace internal VectorUpdatesRange(upd, rhs.size()); // swap vectors x^{n+1}->x^{n}, given the updates in the function above - if (iteration_index == 1) + if (iteration_index == 0) + { + // nothing to do here because we can immediately write into the + // solution vector without remembering any of the other vectors + } + else if (iteration_index == 1) { solution.swap(temp_vector1); solution_old.swap(temp_vector1); } - else if (iteration_index > 1) + else solution.swap(solution_old); } @@ -1985,12 +1990,17 @@ namespace internal VectorUpdatesRange(upd, rhs.local_size()); // swap vectors x^{n+1}->x^{n}, given the updates in the function above - if (iteration_index == 1) + if (iteration_index == 0) + { + // nothing to do here because we can immediately write into the + // solution vector without remembering any of the other vectors + } + else if (iteration_index == 1) { solution.swap(temp_vector1); solution_old.swap(temp_vector1); } - else if (iteration_index > 1) + else solution.swap(solution_old); } From 286a2d867a44c85e83dc60b5dafff424f35ebcbe Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Mon, 11 Feb 2019 16:11:08 -0700 Subject: [PATCH 117/507] reserve step-63 --- examples/step-63/CMakeLists.txt | 39 ++ examples/step-63/doc/builds-on | 1 + examples/step-63/doc/intro.dox | 9 + examples/step-63/doc/kind | 1 + examples/step-63/doc/results.dox | 2 + examples/step-63/doc/tooltip | 1 + examples/step-63/step-63.cc | 715 +++++++++++++++++++++++++++++++ 7 files changed, 768 insertions(+) create mode 100644 examples/step-63/CMakeLists.txt create mode 100644 examples/step-63/doc/builds-on create mode 100644 examples/step-63/doc/intro.dox create mode 100644 examples/step-63/doc/kind create mode 100644 examples/step-63/doc/results.dox create mode 100644 examples/step-63/doc/tooltip create mode 100644 examples/step-63/step-63.cc 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/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..b8535c110b50 --- /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. For now, this is just step-16. 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/step-63.cc b/examples/step-63/step-63.cc new file mode 100644 index 000000000000..86234e2ac7b0 --- /dev/null +++ b/examples/step-63/step-63.cc @@ -0,0 +1,715 @@ +/* --------------------------------------------------------------------- + * + * Copyright (C) 2003 - 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. + * + * --------------------------------------------------------------------- + * + * 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. For now, this is just step-16. + +// @sect3{Include files} + +// Again, the first few include files are already known, so we won't comment +// on them: +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +// These, now, are the include necessary for the multilevel methods. The first +// one declares how to handle Dirichlet boundary conditions on each of the +// levels of the multigrid method. For the actual description of the degrees +// of freedom, we do not need any new include file because DoFHandler already +// has all necessary methods implemented. We will only need to distribute the +// DoFs for the levels further down. +// +// The rest of the include files deals with the mechanics of multigrid as a +// linear operator (solver or preconditioner). +#include +#include +#include +#include +#include +#include +#include + +// We will be using MeshWorker::mesh_loop to loop over the cells, so include it +// here: +#include + + +// This is C++: +#include +#include + +using namespace dealii; + +namespace Step16 +{ + // @sect3{The Scratch and Copy objects} + // + // We use MeshWorker::mesh_loop() to assemble our matrices. For this, we + // need a ScratchData object to store temporary data on each cell (this is + // just the FEValues object) and a CopyData object that will contain the + // output of each cell assembly. For more details about the usage of scratch + // and copy objects, see the WorkStream namespace. + template + struct ScratchData + { + ScratchData(const Mapping & mapping, + const FiniteElement &fe, + const unsigned int quadrature_degree, + const UpdateFlags update_flags) + : fe_values(mapping, fe, QGauss(quadrature_degree), update_flags) + {} + + ScratchData(const ScratchData &scratch_data) + : fe_values(scratch_data.fe_values.get_mapping(), + scratch_data.fe_values.get_fe(), + scratch_data.fe_values.get_quadrature(), + scratch_data.fe_values.get_update_flags()) + {} + + FEValues fe_values; + }; + + struct CopyData + { + unsigned int level; + FullMatrix cell_matrix; + Vector cell_rhs; + std::vector local_dof_indices; + + template + void reinit(const Iterator &cell, unsigned int dofs_per_cell) + { + cell_matrix.reinit(dofs_per_cell, dofs_per_cell); + cell_rhs.reinit(dofs_per_cell); + + local_dof_indices.resize(dofs_per_cell); + cell->get_active_or_mg_dof_indices(local_dof_indices); + level = cell->level(); + } + }; + + // @sect3{The LaplaceProblem class template} + + // This main class is similar to the same class in step-6. As far as + // member functions is concerned, the only additions are: + // - The assemble_multigrid function that assembles the matrices + // that correspond to the discrete operators on intermediate levels. + // - The cell_worker function that assembles our PDE on a single + // cell. + template + class LaplaceProblem + { + public: + LaplaceProblem(const unsigned int degree); + void run(); + + private: + template + void cell_worker(const Iterator & cell, + ScratchData &scratch_data, + CopyData & copy_data); + + void setup_system(); + void assemble_system(); + void assemble_multigrid(); + void solve(); + void refine_grid(); + void output_results(const unsigned int cycle) const; + + Triangulation triangulation; + FE_Q fe; + DoFHandler dof_handler; + + SparsityPattern sparsity_pattern; + SparseMatrix system_matrix; + + AffineConstraints constraints; + + Vector solution; + Vector system_rhs; + + const unsigned int degree; + + // The following members are the essential data structures for the multigrid + // method. The first four represent the sparsity patterns and the matrices + // on individual levels of the multilevel hierarchy, very much like the + // objects for the global mesh above. + // + // Then we have two new matrices only needed for multigrid methods with + // local smoothing on adaptive meshes. They convey data between the interior + // part of the refined region and the refinement edge, as outlined in detail + // in the @ref mg_paper "multigrid paper". + // + // The last object stores information about the boundary indices on each + // level and information about indices lying on a refinement edge between + // two different refinement levels. It thus serves a similar purpose as + // AffineConstraints, but on each level. + MGLevelObject mg_sparsity_patterns; + MGLevelObject mg_interface_sparsity_patterns; + + MGLevelObject> mg_matrices; + MGLevelObject> mg_interface_matrices; + MGConstrainedDoFs mg_constrained_dofs; + }; + + + // @sect3{The LaplaceProblem class implementation} + + // Just one short remark about the constructor of the Triangulation: + // by convention, all adaptively refined triangulations in deal.II never + // change by more than one level across a face between cells. For our + // multigrid algorithms, however, we need a slightly stricter guarantee, + // namely that the mesh also does not change by more than refinement level + // across vertices that might connect two cells. In other words, we must + // prevent the following situation: + // + // @image html limit_level_difference_at_vertices.png "" + // + // This is achieved by passing the + // Triangulation::limit_level_difference_at_vertices flag to the constructor + // of the triangulation class. + template + LaplaceProblem::LaplaceProblem(const unsigned int degree) + : triangulation(Triangulation::limit_level_difference_at_vertices) + , fe(degree) + , dof_handler(triangulation) + , degree(degree) + {} + + + + // @sect4{LaplaceProblem::setup_system} + + // In addition to just distributing the degrees of freedom in + // the DoFHandler, we do the same on each level. Then, we follow the + // same procedure as before to set up the system on the leaf mesh. + template + void LaplaceProblem::setup_system() + { + dof_handler.distribute_dofs(fe); + dof_handler.distribute_mg_dofs(); + + std::cout << " Number of degrees of freedom: " << dof_handler.n_dofs() + << " (by level: "; + for (unsigned int level = 0; level < triangulation.n_levels(); ++level) + std::cout << dof_handler.n_dofs(level) + << (level == triangulation.n_levels() - 1 ? ")" : ", "); + std::cout << std::endl; + + + solution.reinit(dof_handler.n_dofs()); + system_rhs.reinit(dof_handler.n_dofs()); + + constraints.clear(); + DoFTools::make_hanging_node_constraints(dof_handler, constraints); + + std::set dirichlet_boundary_ids = {0}; + Functions::ZeroFunction homogeneous_dirichlet_bc; + const std::map *> + dirichlet_boundary_functions = { + {types::boundary_id(0), &homogeneous_dirichlet_bc}}; + VectorTools::interpolate_boundary_values(dof_handler, + dirichlet_boundary_functions, + constraints); + constraints.close(); + + { + DynamicSparsityPattern dsp(dof_handler.n_dofs(), dof_handler.n_dofs()); + DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints); + sparsity_pattern.copy_from(dsp); + } + system_matrix.reinit(sparsity_pattern); + + // The multigrid constraints have to be initialized. They need to know + // where Dirichlet boundary conditions are prescribed. + mg_constrained_dofs.clear(); + mg_constrained_dofs.initialize(dof_handler); + mg_constrained_dofs.make_zero_boundary_constraints(dof_handler, + dirichlet_boundary_ids); + + + // Now for the things that concern the multigrid data structures. First, we + // resize the multilevel objects to hold matrices and sparsity patterns for + // every level. The coarse level is zero (this is mandatory right now but + // may change in a future revision). Note that these functions take a + // complete, inclusive range here (not a starting index and size), so the + // finest level is n_levels-1. We first have to resize the + // container holding the SparseMatrix classes, since they have to release + // their SparsityPattern before the can be destroyed upon resizing. + const unsigned int n_levels = triangulation.n_levels(); + + mg_interface_matrices.resize(0, n_levels - 1); + mg_matrices.resize(0, n_levels - 1); + mg_sparsity_patterns.resize(0, n_levels - 1); + mg_interface_sparsity_patterns.resize(0, n_levels - 1); + + // Now, we have to provide a matrix on each level. To this end, we first use + // the MGTools::make_sparsity_pattern function to generate a preliminary + // compressed sparsity pattern on each level (see the @ref Sparsity module + // for more information on this topic) and then copy it over to the one we + // really want. The next step is to initialize the interface matrices with + // the fitting sparsity pattern. + // + // It may be worth pointing out that the interface matrices only have + // entries for degrees of freedom that sit at or next to the interface + // between coarser and finer levels of the mesh. They are therefore even + // sparser than the matrices on the individual levels of our multigrid + // hierarchy. Therefore, we use a function specifically build for this + // purpose to generate it. + 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); + mg_interface_matrices[level].reinit( + mg_interface_sparsity_patterns[level]); + } + } + } + + + // @sect4{LaplaceProblem::cell_worker} + + // The cell_worker function is used to assemble the matrix and right-hand side + // on the given cell. This function is used for the active cells to generate + // the system_matrix and on each level to build the level matrices. + // + // Note that we also assemble a right-hand side when called from + // assemble_multigrid() even though it is not used. + template + template + void LaplaceProblem::cell_worker(const Iterator & cell, + ScratchData &scratch_data, + CopyData & copy_data) + { + FEValues &fe_values = scratch_data.fe_values; + fe_values.reinit(cell); + + const unsigned int dofs_per_cell = fe_values.get_fe().dofs_per_cell; + const unsigned int n_q_points = fe_values.get_quadrature().size(); + + copy_data.reinit(cell, dofs_per_cell); + + const std::vector &JxW = fe_values.get_JxW_values(); + + for (unsigned int q = 0; q < n_q_points; ++q) + { + const double coefficient = + (fe_values.get_quadrature_points()[q][0] < 0.0) ? 1.0 : 0.1; + //(cell->center().square() < 0.5 * 0.5) ? 10.0:1.0; + + 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) += + coefficient * + (fe_values.shape_grad(i, q) * fe_values.shape_grad(j, q)) * + JxW[q]; + } + copy_data.cell_rhs(i) += 1.0 * fe_values.shape_value(i, q) * JxW[q]; + } + } + } + + + + // @sect4{LaplaceProblem::assemble_system} + + // The following function assembles the linear system on the active cells of + // the mesh. For this, we pass two lambda functions to the mesh_loop() + // function. The cell_worker function redirects to the class member function + // of the same name, while the copier is specific to this function and copies + // local matrix and vector to the corresponding global ones using the + // constraints. + template + void LaplaceProblem::assemble_system() + { + MappingQ1 mapping; + + auto cell_worker = + [&](const typename DoFHandler::active_cell_iterator &cell, + ScratchData & scratch_data, + CopyData & copy_data) { + this->cell_worker(cell, scratch_data, copy_data); + }; + + auto copier = [&](const CopyData &cd) { + this->constraints.distribute_local_to_global(cd.cell_matrix, + cd.cell_rhs, + cd.local_dof_indices, + system_matrix, + system_rhs); + }; + + const unsigned int n_gauss_points = degree + 1; + + ScratchData scratch_data(mapping, + fe, + n_gauss_points, + update_values | update_gradients | + update_JxW_values | + update_quadrature_points); + + MeshWorker::mesh_loop(dof_handler.begin_active(), + dof_handler.end(), + cell_worker, + copier, + scratch_data, + CopyData(), + MeshWorker::assemble_own_cells); + } + + + // @sect4{LaplaceProblem::assemble_multigrid} + + // The next function is the one that builds the matrices + // that define the multigrid method on each level of the mesh. The integration + // core is the same as above, but the loop below will go over all existing + // cells instead of just the active ones, and the results must be entered into + // the correct level matrices. Fortunately, MeshWorker hides most of that from + // us, and thus the difference between this function and the previous lies + // only in the setup of the assembler and the different iterators in the loop. + // + // We generate an AffineConstraints<> object for each level containing the + // boundary and interface dofs as constrained entries. The corresponding + // object is then used to generate the level matrices. + template + void LaplaceProblem::assemble_multigrid() + { + MappingQ1 mapping; + const unsigned int n_levels = triangulation.n_levels(); + + std::vector> boundary_constraints(n_levels); + for (unsigned int level = 0; level < n_levels; ++level) + { + IndexSet dofset; + DoFTools::extract_locally_relevant_level_dofs(dof_handler, + level, + dofset); + boundary_constraints[level].reinit(dofset); + 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 = + [&](const typename DoFHandler::level_cell_iterator &cell, + ScratchData & scratch_data, + CopyData & copy_data) { + this->cell_worker(cell, scratch_data, copy_data); + }; + + auto copier = [&](const CopyData &cd) { + boundary_constraints[cd.level].distribute_local_to_global( + cd.cell_matrix, cd.local_dof_indices, mg_matrices[cd.level]); + + const unsigned int dofs_per_cell = cd.local_dof_indices.size(); + + // TODO EXPLAIN: + + for (unsigned int i = 0; i < dofs_per_cell; ++i) + for (unsigned int j = 0; j < dofs_per_cell; ++j) + if (mg_constrained_dofs.is_interface_matrix_entry( + cd.level, cd.local_dof_indices[i], cd.local_dof_indices[j])) + { + mg_interface_matrices[cd.level].add(cd.local_dof_indices[i], + cd.local_dof_indices[j], + cd.cell_matrix(i, j)); + } + }; + + const unsigned int n_gauss_points = degree + 1; + + ScratchData scratch_data(mapping, + fe, + n_gauss_points, + update_values | update_gradients | + update_JxW_values | + update_quadrature_points); + + MeshWorker::mesh_loop(dof_handler.begin_mg(), + dof_handler.end_mg(), + cell_worker, + copier, + scratch_data, + CopyData(), + MeshWorker::assemble_own_cells); + } + + + + // @sect4{LaplaceProblem::solve} + + // This is the other function that is significantly different in support of + // the multigrid solver (or, in fact, the preconditioner for which we use + // the multigrid method). + // + // Let us start out by setting up two of the components of multilevel + // methods: transfer operators between levels, and a solver on the coarsest + // level. In finite element methods, the transfer operators are derived from + // the finite element function spaces involved and can often be computed in + // a generic way independent of the problem under consideration. In that + // case, we can use the MGTransferPrebuilt class that, given the constraints + // of the final linear system and the MGConstrainedDoFs object that knows + // about the boundary conditions on the each level and the degrees of + // freedom on interfaces between different refinement level can build the + // matrices for those transfer operations from a DoFHandler object with + // level degrees of freedom. + // + // The second part of the following lines deals with the coarse grid + // solver. Since our coarse grid is very coarse indeed, we decide for a + // direct solver (a Householder decomposition of the coarsest level matrix), + // even if its implementation is not particularly sophisticated. If our + // coarse mesh had many more cells than the five we have here, something + // better suited would obviously be necessary here. + template + void LaplaceProblem::solve() + { + MGTransferPrebuilt> 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); + + // The next component of a multilevel solver or preconditioner is that we + // need a smoother on each level. A common choice for this is to use the + // application of a relaxation method (such as the SOR, Jacobi or Richardson + // method) or a small number of iterations of a solver method (such as CG or + // GMRES). The mg::SmootherRelaxation and MGSmootherPrecondition classes + // provide support for these two kinds of smoothers. Here, we opt for the + // application of a single SOR iteration. To this end, we define an + // appropriate alias and then setup a smoother object. + // + // The last step is to initialize the smoother object with our level + // matrices and to set some smoothing parameters. The + // initialize() function can optionally take additional + // arguments that will be passed to the smoother object on each level. In + // the current case for the SOR smoother, this could, for example, include + // a relaxation parameter. However, we here leave these at their default + // values. The call to set_steps() indicates that we will use + // two pre- and two post-smoothing steps on each level; to use a variable + // number of smoother steps on different levels, more options can be set + // in the constructor call to the mg_smoother object. + // + // The last step results from the fact that we use the SOR method as a + // smoother - which is not symmetric - but we use the conjugate gradient + // iteration (which requires a symmetric preconditioner) below, we need to + // let the multilevel preconditioner make sure that we get a symmetric + // operator even for nonsymmetric smoothers: + using Smoother = PreconditionSOR>; + mg::SmootherRelaxation> mg_smoother; + mg_smoother.initialize(mg_matrices); + mg_smoother.set_steps(2); + mg_smoother.set_symmetric(true); + + // The next preparatory step is that we must wrap our level and interface + // matrices in an object having the required multiplication functions. We + // will create two objects for the interface objects going from coarse to + // fine and the other way around; the multigrid algorithm will later use + // the transpose operator for the latter operation, allowing us to + // initialize both up and down versions of the operator with the matrices + // we already built: + mg::Matrix> mg_matrix(mg_matrices); + mg::Matrix> mg_interface_up(mg_interface_matrices); + mg::Matrix> mg_interface_down(mg_interface_matrices); + + // Now, we are ready to set up the V-cycle operator and the multilevel + // preconditioner. + Multigrid> mg( + mg_matrix, coarse_grid_solver, mg_transfer, mg_smoother, mg_smoother); + mg.set_edge_matrices(mg_interface_down, mg_interface_up); + + PreconditionMG, MGTransferPrebuilt>> + preconditioner(dof_handler, mg, mg_transfer); + + // With all this together, we can finally get about solving the linear + // system in the usual way: + SolverControl solver_control(1000, 1e-12); + SolverCG<> solver(solver_control); + + solution = 0; + + solver.solve(system_matrix, solution, system_rhs, preconditioner); + std::cout << " Number of CG iterations: " << solver_control.last_step() + << "\n" + << std::endl; + constraints.distribute(solution); + } + + + + // @sect4{Postprocessing} + + // The following two functions postprocess a solution once it is + // computed. In particular, the first one refines the mesh at the beginning + // of each cycle while the second one outputs results at the end of each + // such cycle. The functions are almost unchanged from those in step-6. + template + void LaplaceProblem::refine_grid() + { + Vector estimated_error_per_cell(triangulation.n_active_cells()); + + KellyErrorEstimator::estimate( + dof_handler, + QGauss(degree + 2), + std::map *>(), + solution, + estimated_error_per_cell); + GridRefinement::refine_and_coarsen_fixed_number(triangulation, + estimated_error_per_cell, + 0.3, + 0.03); + triangulation.execute_coarsening_and_refinement(); + } + + + + template + void LaplaceProblem::output_results(const unsigned int cycle) const + { + DataOut data_out; + + data_out.attach_dof_handler(dof_handler); + data_out.add_data_vector(solution, "solution"); + data_out.build_patches(); + + std::ofstream output("solution-" + std::to_string(cycle) + ".vtk"); + data_out.write_vtk(output); + } + + + // @sect4{LaplaceProblem::run} + + // Like several of the functions above, this is almost exactly a copy of + // the corresponding function in step-6. The only difference is the call to + // assemble_multigrid that takes care of forming the matrices + // on every level that we need in the multigrid method. + template + void LaplaceProblem::run() + { + for (unsigned int cycle = 0; cycle < 8; ++cycle) + { + std::cout << "Cycle " << cycle << std::endl; + + if (cycle == 0) + { + GridGenerator::hyper_ball(triangulation); + triangulation.refine_global(2); + } + else + refine_grid(); + + std::cout << " Number of active cells: " + << triangulation.n_active_cells() << std::endl; + + setup_system(); + + assemble_system(); + assemble_multigrid(); + + solve(); + output_results(cycle); + } + } +} // namespace Step16 + + +// @sect3{The main() function} +// +// This is again the same function as in step-6: +int main() +{ + try + { + using namespace Step16; + + LaplaceProblem<2> laplace_problem(1); + laplace_problem.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; +} From 81c110c254b5fbfb9c40410220543641f1367e04 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Tue, 12 Feb 2019 10:20:02 -0700 Subject: [PATCH 118/507] make example empty --- examples/step-63/step-63.cc | 664 +----------------------------------- 1 file changed, 4 insertions(+), 660 deletions(-) diff --git a/examples/step-63/step-63.cc b/examples/step-63/step-63.cc index 86234e2ac7b0..d2b9a18715f6 100644 --- a/examples/step-63/step-63.cc +++ b/examples/step-63/step-63.cc @@ -1,6 +1,6 @@ /* --------------------------------------------------------------------- * - * Copyright (C) 2003 - 2018 by the deal.II authors + * Copyright (C) 2018 - 2019 by the deal.II authors * * This file is part of the deal.II library. * @@ -18,671 +18,15 @@ */ // @note: This is work in progress and will be an example for block smoothers -// in geometric multigrid. For now, this is just step-16. +// in geometric multigrid. -// @sect3{Include files} +#include -// Again, the first few include files are already known, so we won't comment -// on them: -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include - -// These, now, are the include necessary for the multilevel methods. The first -// one declares how to handle Dirichlet boundary conditions on each of the -// levels of the multigrid method. For the actual description of the degrees -// of freedom, we do not need any new include file because DoFHandler already -// has all necessary methods implemented. We will only need to distribute the -// DoFs for the levels further down. -// -// The rest of the include files deals with the mechanics of multigrid as a -// linear operator (solver or preconditioner). -#include -#include -#include -#include -#include -#include -#include - -// We will be using MeshWorker::mesh_loop to loop over the cells, so include it -// here: -#include - - -// This is C++: -#include -#include - -using namespace dealii; - -namespace Step16 -{ - // @sect3{The Scratch and Copy objects} - // - // We use MeshWorker::mesh_loop() to assemble our matrices. For this, we - // need a ScratchData object to store temporary data on each cell (this is - // just the FEValues object) and a CopyData object that will contain the - // output of each cell assembly. For more details about the usage of scratch - // and copy objects, see the WorkStream namespace. - template - struct ScratchData - { - ScratchData(const Mapping & mapping, - const FiniteElement &fe, - const unsigned int quadrature_degree, - const UpdateFlags update_flags) - : fe_values(mapping, fe, QGauss(quadrature_degree), update_flags) - {} - - ScratchData(const ScratchData &scratch_data) - : fe_values(scratch_data.fe_values.get_mapping(), - scratch_data.fe_values.get_fe(), - scratch_data.fe_values.get_quadrature(), - scratch_data.fe_values.get_update_flags()) - {} - - FEValues fe_values; - }; - - struct CopyData - { - unsigned int level; - FullMatrix cell_matrix; - Vector cell_rhs; - std::vector local_dof_indices; - - template - void reinit(const Iterator &cell, unsigned int dofs_per_cell) - { - cell_matrix.reinit(dofs_per_cell, dofs_per_cell); - cell_rhs.reinit(dofs_per_cell); - - local_dof_indices.resize(dofs_per_cell); - cell->get_active_or_mg_dof_indices(local_dof_indices); - level = cell->level(); - } - }; - - // @sect3{The LaplaceProblem class template} - - // This main class is similar to the same class in step-6. As far as - // member functions is concerned, the only additions are: - // - The assemble_multigrid function that assembles the matrices - // that correspond to the discrete operators on intermediate levels. - // - The cell_worker function that assembles our PDE on a single - // cell. - template - class LaplaceProblem - { - public: - LaplaceProblem(const unsigned int degree); - void run(); - - private: - template - void cell_worker(const Iterator & cell, - ScratchData &scratch_data, - CopyData & copy_data); - - void setup_system(); - void assemble_system(); - void assemble_multigrid(); - void solve(); - void refine_grid(); - void output_results(const unsigned int cycle) const; - - Triangulation triangulation; - FE_Q fe; - DoFHandler dof_handler; - - SparsityPattern sparsity_pattern; - SparseMatrix system_matrix; - - AffineConstraints constraints; - - Vector solution; - Vector system_rhs; - - const unsigned int degree; - - // The following members are the essential data structures for the multigrid - // method. The first four represent the sparsity patterns and the matrices - // on individual levels of the multilevel hierarchy, very much like the - // objects for the global mesh above. - // - // Then we have two new matrices only needed for multigrid methods with - // local smoothing on adaptive meshes. They convey data between the interior - // part of the refined region and the refinement edge, as outlined in detail - // in the @ref mg_paper "multigrid paper". - // - // The last object stores information about the boundary indices on each - // level and information about indices lying on a refinement edge between - // two different refinement levels. It thus serves a similar purpose as - // AffineConstraints, but on each level. - MGLevelObject mg_sparsity_patterns; - MGLevelObject mg_interface_sparsity_patterns; - - MGLevelObject> mg_matrices; - MGLevelObject> mg_interface_matrices; - MGConstrainedDoFs mg_constrained_dofs; - }; - - - // @sect3{The LaplaceProblem class implementation} - - // Just one short remark about the constructor of the Triangulation: - // by convention, all adaptively refined triangulations in deal.II never - // change by more than one level across a face between cells. For our - // multigrid algorithms, however, we need a slightly stricter guarantee, - // namely that the mesh also does not change by more than refinement level - // across vertices that might connect two cells. In other words, we must - // prevent the following situation: - // - // @image html limit_level_difference_at_vertices.png "" - // - // This is achieved by passing the - // Triangulation::limit_level_difference_at_vertices flag to the constructor - // of the triangulation class. - template - LaplaceProblem::LaplaceProblem(const unsigned int degree) - : triangulation(Triangulation::limit_level_difference_at_vertices) - , fe(degree) - , dof_handler(triangulation) - , degree(degree) - {} - - - - // @sect4{LaplaceProblem::setup_system} - - // In addition to just distributing the degrees of freedom in - // the DoFHandler, we do the same on each level. Then, we follow the - // same procedure as before to set up the system on the leaf mesh. - template - void LaplaceProblem::setup_system() - { - dof_handler.distribute_dofs(fe); - dof_handler.distribute_mg_dofs(); - - std::cout << " Number of degrees of freedom: " << dof_handler.n_dofs() - << " (by level: "; - for (unsigned int level = 0; level < triangulation.n_levels(); ++level) - std::cout << dof_handler.n_dofs(level) - << (level == triangulation.n_levels() - 1 ? ")" : ", "); - std::cout << std::endl; - - - solution.reinit(dof_handler.n_dofs()); - system_rhs.reinit(dof_handler.n_dofs()); - - constraints.clear(); - DoFTools::make_hanging_node_constraints(dof_handler, constraints); - - std::set dirichlet_boundary_ids = {0}; - Functions::ZeroFunction homogeneous_dirichlet_bc; - const std::map *> - dirichlet_boundary_functions = { - {types::boundary_id(0), &homogeneous_dirichlet_bc}}; - VectorTools::interpolate_boundary_values(dof_handler, - dirichlet_boundary_functions, - constraints); - constraints.close(); - - { - DynamicSparsityPattern dsp(dof_handler.n_dofs(), dof_handler.n_dofs()); - DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints); - sparsity_pattern.copy_from(dsp); - } - system_matrix.reinit(sparsity_pattern); - - // The multigrid constraints have to be initialized. They need to know - // where Dirichlet boundary conditions are prescribed. - mg_constrained_dofs.clear(); - mg_constrained_dofs.initialize(dof_handler); - mg_constrained_dofs.make_zero_boundary_constraints(dof_handler, - dirichlet_boundary_ids); - - - // Now for the things that concern the multigrid data structures. First, we - // resize the multilevel objects to hold matrices and sparsity patterns for - // every level. The coarse level is zero (this is mandatory right now but - // may change in a future revision). Note that these functions take a - // complete, inclusive range here (not a starting index and size), so the - // finest level is n_levels-1. We first have to resize the - // container holding the SparseMatrix classes, since they have to release - // their SparsityPattern before the can be destroyed upon resizing. - const unsigned int n_levels = triangulation.n_levels(); - - mg_interface_matrices.resize(0, n_levels - 1); - mg_matrices.resize(0, n_levels - 1); - mg_sparsity_patterns.resize(0, n_levels - 1); - mg_interface_sparsity_patterns.resize(0, n_levels - 1); - - // Now, we have to provide a matrix on each level. To this end, we first use - // the MGTools::make_sparsity_pattern function to generate a preliminary - // compressed sparsity pattern on each level (see the @ref Sparsity module - // for more information on this topic) and then copy it over to the one we - // really want. The next step is to initialize the interface matrices with - // the fitting sparsity pattern. - // - // It may be worth pointing out that the interface matrices only have - // entries for degrees of freedom that sit at or next to the interface - // between coarser and finer levels of the mesh. They are therefore even - // sparser than the matrices on the individual levels of our multigrid - // hierarchy. Therefore, we use a function specifically build for this - // purpose to generate it. - 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); - mg_interface_matrices[level].reinit( - mg_interface_sparsity_patterns[level]); - } - } - } - - - // @sect4{LaplaceProblem::cell_worker} - - // The cell_worker function is used to assemble the matrix and right-hand side - // on the given cell. This function is used for the active cells to generate - // the system_matrix and on each level to build the level matrices. - // - // Note that we also assemble a right-hand side when called from - // assemble_multigrid() even though it is not used. - template - template - void LaplaceProblem::cell_worker(const Iterator & cell, - ScratchData &scratch_data, - CopyData & copy_data) - { - FEValues &fe_values = scratch_data.fe_values; - fe_values.reinit(cell); - - const unsigned int dofs_per_cell = fe_values.get_fe().dofs_per_cell; - const unsigned int n_q_points = fe_values.get_quadrature().size(); - - copy_data.reinit(cell, dofs_per_cell); - - const std::vector &JxW = fe_values.get_JxW_values(); - - for (unsigned int q = 0; q < n_q_points; ++q) - { - const double coefficient = - (fe_values.get_quadrature_points()[q][0] < 0.0) ? 1.0 : 0.1; - //(cell->center().square() < 0.5 * 0.5) ? 10.0:1.0; - - 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) += - coefficient * - (fe_values.shape_grad(i, q) * fe_values.shape_grad(j, q)) * - JxW[q]; - } - copy_data.cell_rhs(i) += 1.0 * fe_values.shape_value(i, q) * JxW[q]; - } - } - } - - - - // @sect4{LaplaceProblem::assemble_system} - - // The following function assembles the linear system on the active cells of - // the mesh. For this, we pass two lambda functions to the mesh_loop() - // function. The cell_worker function redirects to the class member function - // of the same name, while the copier is specific to this function and copies - // local matrix and vector to the corresponding global ones using the - // constraints. - template - void LaplaceProblem::assemble_system() - { - MappingQ1 mapping; - - auto cell_worker = - [&](const typename DoFHandler::active_cell_iterator &cell, - ScratchData & scratch_data, - CopyData & copy_data) { - this->cell_worker(cell, scratch_data, copy_data); - }; - - auto copier = [&](const CopyData &cd) { - this->constraints.distribute_local_to_global(cd.cell_matrix, - cd.cell_rhs, - cd.local_dof_indices, - system_matrix, - system_rhs); - }; - - const unsigned int n_gauss_points = degree + 1; - - ScratchData scratch_data(mapping, - fe, - n_gauss_points, - update_values | update_gradients | - update_JxW_values | - update_quadrature_points); - - MeshWorker::mesh_loop(dof_handler.begin_active(), - dof_handler.end(), - cell_worker, - copier, - scratch_data, - CopyData(), - MeshWorker::assemble_own_cells); - } - - - // @sect4{LaplaceProblem::assemble_multigrid} - - // The next function is the one that builds the matrices - // that define the multigrid method on each level of the mesh. The integration - // core is the same as above, but the loop below will go over all existing - // cells instead of just the active ones, and the results must be entered into - // the correct level matrices. Fortunately, MeshWorker hides most of that from - // us, and thus the difference between this function and the previous lies - // only in the setup of the assembler and the different iterators in the loop. - // - // We generate an AffineConstraints<> object for each level containing the - // boundary and interface dofs as constrained entries. The corresponding - // object is then used to generate the level matrices. - template - void LaplaceProblem::assemble_multigrid() - { - MappingQ1 mapping; - const unsigned int n_levels = triangulation.n_levels(); - - std::vector> boundary_constraints(n_levels); - for (unsigned int level = 0; level < n_levels; ++level) - { - IndexSet dofset; - DoFTools::extract_locally_relevant_level_dofs(dof_handler, - level, - dofset); - boundary_constraints[level].reinit(dofset); - 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 = - [&](const typename DoFHandler::level_cell_iterator &cell, - ScratchData & scratch_data, - CopyData & copy_data) { - this->cell_worker(cell, scratch_data, copy_data); - }; - - auto copier = [&](const CopyData &cd) { - boundary_constraints[cd.level].distribute_local_to_global( - cd.cell_matrix, cd.local_dof_indices, mg_matrices[cd.level]); - - const unsigned int dofs_per_cell = cd.local_dof_indices.size(); - - // TODO EXPLAIN: - - for (unsigned int i = 0; i < dofs_per_cell; ++i) - for (unsigned int j = 0; j < dofs_per_cell; ++j) - if (mg_constrained_dofs.is_interface_matrix_entry( - cd.level, cd.local_dof_indices[i], cd.local_dof_indices[j])) - { - mg_interface_matrices[cd.level].add(cd.local_dof_indices[i], - cd.local_dof_indices[j], - cd.cell_matrix(i, j)); - } - }; - - const unsigned int n_gauss_points = degree + 1; - - ScratchData scratch_data(mapping, - fe, - n_gauss_points, - update_values | update_gradients | - update_JxW_values | - update_quadrature_points); - - MeshWorker::mesh_loop(dof_handler.begin_mg(), - dof_handler.end_mg(), - cell_worker, - copier, - scratch_data, - CopyData(), - MeshWorker::assemble_own_cells); - } - - - - // @sect4{LaplaceProblem::solve} - - // This is the other function that is significantly different in support of - // the multigrid solver (or, in fact, the preconditioner for which we use - // the multigrid method). - // - // Let us start out by setting up two of the components of multilevel - // methods: transfer operators between levels, and a solver on the coarsest - // level. In finite element methods, the transfer operators are derived from - // the finite element function spaces involved and can often be computed in - // a generic way independent of the problem under consideration. In that - // case, we can use the MGTransferPrebuilt class that, given the constraints - // of the final linear system and the MGConstrainedDoFs object that knows - // about the boundary conditions on the each level and the degrees of - // freedom on interfaces between different refinement level can build the - // matrices for those transfer operations from a DoFHandler object with - // level degrees of freedom. - // - // The second part of the following lines deals with the coarse grid - // solver. Since our coarse grid is very coarse indeed, we decide for a - // direct solver (a Householder decomposition of the coarsest level matrix), - // even if its implementation is not particularly sophisticated. If our - // coarse mesh had many more cells than the five we have here, something - // better suited would obviously be necessary here. - template - void LaplaceProblem::solve() - { - MGTransferPrebuilt> 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); - - // The next component of a multilevel solver or preconditioner is that we - // need a smoother on each level. A common choice for this is to use the - // application of a relaxation method (such as the SOR, Jacobi or Richardson - // method) or a small number of iterations of a solver method (such as CG or - // GMRES). The mg::SmootherRelaxation and MGSmootherPrecondition classes - // provide support for these two kinds of smoothers. Here, we opt for the - // application of a single SOR iteration. To this end, we define an - // appropriate alias and then setup a smoother object. - // - // The last step is to initialize the smoother object with our level - // matrices and to set some smoothing parameters. The - // initialize() function can optionally take additional - // arguments that will be passed to the smoother object on each level. In - // the current case for the SOR smoother, this could, for example, include - // a relaxation parameter. However, we here leave these at their default - // values. The call to set_steps() indicates that we will use - // two pre- and two post-smoothing steps on each level; to use a variable - // number of smoother steps on different levels, more options can be set - // in the constructor call to the mg_smoother object. - // - // The last step results from the fact that we use the SOR method as a - // smoother - which is not symmetric - but we use the conjugate gradient - // iteration (which requires a symmetric preconditioner) below, we need to - // let the multilevel preconditioner make sure that we get a symmetric - // operator even for nonsymmetric smoothers: - using Smoother = PreconditionSOR>; - mg::SmootherRelaxation> mg_smoother; - mg_smoother.initialize(mg_matrices); - mg_smoother.set_steps(2); - mg_smoother.set_symmetric(true); - - // The next preparatory step is that we must wrap our level and interface - // matrices in an object having the required multiplication functions. We - // will create two objects for the interface objects going from coarse to - // fine and the other way around; the multigrid algorithm will later use - // the transpose operator for the latter operation, allowing us to - // initialize both up and down versions of the operator with the matrices - // we already built: - mg::Matrix> mg_matrix(mg_matrices); - mg::Matrix> mg_interface_up(mg_interface_matrices); - mg::Matrix> mg_interface_down(mg_interface_matrices); - - // Now, we are ready to set up the V-cycle operator and the multilevel - // preconditioner. - Multigrid> mg( - mg_matrix, coarse_grid_solver, mg_transfer, mg_smoother, mg_smoother); - mg.set_edge_matrices(mg_interface_down, mg_interface_up); - - PreconditionMG, MGTransferPrebuilt>> - preconditioner(dof_handler, mg, mg_transfer); - - // With all this together, we can finally get about solving the linear - // system in the usual way: - SolverControl solver_control(1000, 1e-12); - SolverCG<> solver(solver_control); - - solution = 0; - - solver.solve(system_matrix, solution, system_rhs, preconditioner); - std::cout << " Number of CG iterations: " << solver_control.last_step() - << "\n" - << std::endl; - constraints.distribute(solution); - } - - - - // @sect4{Postprocessing} - - // The following two functions postprocess a solution once it is - // computed. In particular, the first one refines the mesh at the beginning - // of each cycle while the second one outputs results at the end of each - // such cycle. The functions are almost unchanged from those in step-6. - template - void LaplaceProblem::refine_grid() - { - Vector estimated_error_per_cell(triangulation.n_active_cells()); - - KellyErrorEstimator::estimate( - dof_handler, - QGauss(degree + 2), - std::map *>(), - solution, - estimated_error_per_cell); - GridRefinement::refine_and_coarsen_fixed_number(triangulation, - estimated_error_per_cell, - 0.3, - 0.03); - triangulation.execute_coarsening_and_refinement(); - } - - - - template - void LaplaceProblem::output_results(const unsigned int cycle) const - { - DataOut data_out; - - data_out.attach_dof_handler(dof_handler); - data_out.add_data_vector(solution, "solution"); - data_out.build_patches(); - - std::ofstream output("solution-" + std::to_string(cycle) + ".vtk"); - data_out.write_vtk(output); - } - - - // @sect4{LaplaceProblem::run} - - // Like several of the functions above, this is almost exactly a copy of - // the corresponding function in step-6. The only difference is the call to - // assemble_multigrid that takes care of forming the matrices - // on every level that we need in the multigrid method. - template - void LaplaceProblem::run() - { - for (unsigned int cycle = 0; cycle < 8; ++cycle) - { - std::cout << "Cycle " << cycle << std::endl; - - if (cycle == 0) - { - GridGenerator::hyper_ball(triangulation); - triangulation.refine_global(2); - } - else - refine_grid(); - - std::cout << " Number of active cells: " - << triangulation.n_active_cells() << std::endl; - - setup_system(); - - assemble_system(); - assemble_multigrid(); - - solve(); - output_results(cycle); - } - } -} // namespace Step16 - - -// @sect3{The main() function} -// -// This is again the same function as in step-6: int main() { try { - using namespace Step16; - - LaplaceProblem<2> laplace_problem(1); - laplace_problem.run(); + // do nothing. } catch (std::exception &exc) { From 583b5acc874e6e36b591801c508828f82c8d269b Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Sat, 9 Feb 2019 10:48:12 -0700 Subject: [PATCH 119/507] [CI]: expose tests in Jenkins --- Jenkinsfile | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 9e3e48848fc8..e6f70559f4e0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -76,7 +76,15 @@ 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')] + } + cleanup { + cleanWs() + } + } steps { @@ -97,7 +105,7 @@ pipeline $WORKSPACE/ time ninja -j $NP 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 ''' } } @@ -113,7 +121,15 @@ 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')] + } + cleanup { + cleanWs() + } + } steps { @@ -132,10 +148,11 @@ pipeline $WORKSPACE/ time ninja -j $NP 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 ''' } } + } } From 9d41443da1975f5c0ae8fe55c86558863b2e4fa5 Mon Sep 17 00:00:00 2001 From: Giovanni Alzetta Date: Wed, 13 Feb 2019 09:30:53 +0100 Subject: [PATCH 120/507] Adding cell_hint to GridTools::compute_point_locations documentation --- include/deal.II/grid/grid_tools.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/deal.II/grid/grid_tools.h b/include/deal.II/grid/grid_tools.h index 3a89f434b751..420ec05376d5 100644 --- a/include/deal.II/grid/grid_tools.h +++ b/include/deal.II/grid/grid_tools.h @@ -698,6 +698,8 @@ namespace GridTools * * @param[in] cache The triangulation's GridTools::Cache . * @param[in] points The point's vector. + * @param[in] cell_hint (optional) A cell iterator for a cell which likely + * contains the first point of @p points. * * @return A tuple containing the following information: * - Cells, is a vector of a vector cells of the all cells From 229e27b92360196e6371306d65e87f0db0ab5ba9 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Wed, 13 Feb 2019 08:31:48 -0700 Subject: [PATCH 121/507] add include --- examples/step-63/step-63.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/step-63/step-63.cc b/examples/step-63/step-63.cc index d2b9a18715f6..2534596dc665 100644 --- a/examples/step-63/step-63.cc +++ b/examples/step-63/step-63.cc @@ -20,8 +20,10 @@ // @note: This is work in progress and will be an example for block smoothers // in geometric multigrid. +#include #include + int main() { try From cd914279550bebc954c219c4e072e4e64246f2f7 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Wed, 13 Feb 2019 19:00:48 -0600 Subject: [PATCH 122/507] Documentation: add some pointers to step-20 --- doc/doxygen/headers/laoperators.h | 6 ++++++ include/deal.II/lac/linear_operator.h | 3 +++ include/deal.II/lac/packaged_operation.h | 3 +++ 3 files changed, 12 insertions(+) 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/include/deal.II/lac/linear_operator.h b/include/deal.II/lac/linear_operator.h index e066190781cd..ef84db6e253c 100644 --- a/include/deal.II/lac/linear_operator.h +++ b/include/deal.II/lac/linear_operator.h @@ -151,6 +151,9 @@ null_operator(const LinearOperator &); * for linear operators have been provided within the respective * TrilinosWrappers (and, in the future, PETScWrappers) namespaces. * + * @note The step-20 tutorial program has a detailed usage example of the + * LinearOperator class. + * * @author Luca Heltai, Matthias Maier, 2015; Jean-Paul Pelteret, 2016 * * @ingroup LAOperators diff --git a/include/deal.II/lac/packaged_operation.h b/include/deal.II/lac/packaged_operation.h index 8c73828e2ad1..f4da9786afef 100644 --- a/include/deal.II/lac/packaged_operation.h +++ b/include/deal.II/lac/packaged_operation.h @@ -93,6 +93,9 @@ class PackagedOperation; * y -= residual; * @endcode * + * @note The step-20 tutorial program has a detailed usage example of the + * LinearOperator class. + * * @author Matthias Maier, 2015 * * @ingroup LAOperators From c46ca30fe9b73ae1c4ac13010f8377705b6e285e Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Thu, 14 Feb 2019 02:31:17 +0000 Subject: [PATCH 123/507] Do not use cudaDeviceSynchronize in release mode --- .../deal.II/lac/vector_operations_internal.h | 26 +++++++++++++++++++ source/lac/cuda_sparse_matrix.cu | 10 +++++++ source/lac/cuda_vector.cu | 23 ++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/include/deal.II/lac/vector_operations_internal.h b/include/deal.II/lac/vector_operations_internal.h index c78df10c9433..5d98e3f23a6b 100644 --- a/include/deal.II/lac/vector_operations_internal.h +++ b/include/deal.II/lac/vector_operations_internal.h @@ -2026,10 +2026,12 @@ namespace internal ::dealii::LinearAlgebra::CUDAWrappers::kernel::set <<>>(data.values_dev.get(), s, size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2049,10 +2051,12 @@ namespace internal v_data.values_dev.get(), size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2072,10 +2076,12 @@ namespace internal v_data.values_dev.get(), size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2091,10 +2097,12 @@ namespace internal ::dealii::LinearAlgebra::CUDAWrappers::kernel::vec_add <<>>(data.values_dev.get(), a, size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2115,10 +2123,12 @@ namespace internal v_data.values_dev.get(), size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2144,10 +2154,12 @@ namespace internal w_data.values_dev.get(), size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2166,10 +2178,12 @@ namespace internal <<>>( x, data.values_dev.get(), 1., v_data.values_dev.get(), size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2189,10 +2203,12 @@ namespace internal <<>>( x, data.values_dev.get(), a, v_data.values_dev.get(), size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2220,10 +2236,12 @@ namespace internal w_data.values_dev.get(), size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2239,10 +2257,12 @@ namespace internal ::dealii::LinearAlgebra::CUDAWrappers::kernel::vec_scale <<>>(data.values_dev.get(), factor, size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2261,10 +2281,12 @@ namespace internal v_data.values_dev.get(), size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2285,10 +2307,12 @@ namespace internal v_data.values_dev.get(), size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static void @@ -2314,10 +2338,12 @@ namespace internal w_data.values_dev.get(), size); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } static Number diff --git a/source/lac/cuda_sparse_matrix.cu b/source/lac/cuda_sparse_matrix.cu index 6756e9d97ded..687e565d26ec 100644 --- a/source/lac/cuda_sparse_matrix.cu +++ b/source/lac/cuda_sparse_matrix.cu @@ -343,10 +343,12 @@ namespace CUDAWrappers internal::scale <<>>(val_dev.get(), factor, nnz); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif return *this; } @@ -363,10 +365,12 @@ namespace CUDAWrappers internal::scale <<>>(val_dev.get(), 1. / factor, nnz); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif return *this; } @@ -515,10 +519,13 @@ namespace CUDAWrappers column_index_dev.get(), row_ptr_dev.get(), column_sums.get_values()); + +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif return column_sums.linfty_norm(); } @@ -537,10 +544,13 @@ namespace CUDAWrappers column_index_dev.get(), row_ptr_dev.get(), row_sums.get_values()); + +# ifdef DEUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif return row_sums.linfty_norm(); } diff --git a/source/lac/cuda_vector.cu b/source/lac/cuda_vector.cu index 4f12a49740db..0787cb679c70 100644 --- a/source/lac/cuda_vector.cu +++ b/source/lac/cuda_vector.cu @@ -158,10 +158,13 @@ namespace LinearAlgebra kernel::vector_bin_op <<>>(val.get(), tmp, n_elements); + +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif // Delete the temporary vector Utilities::CUDA::free(tmp); @@ -197,10 +200,12 @@ namespace LinearAlgebra kernel::vec_scale <<>>(val.get(), factor, n_elements); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif return *this; } @@ -217,10 +222,12 @@ namespace LinearAlgebra kernel::vec_scale <<>>(val.get(), 1. / factor, n_elements); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif return *this; } @@ -246,10 +253,12 @@ namespace LinearAlgebra kernel::vector_bin_op <<>>(val.get(), down_V.val.get(), n_elements); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif return *this; } @@ -275,10 +284,12 @@ namespace LinearAlgebra kernel::vector_bin_op <<>>(val.get(), down_V.val.get(), n_elements); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif return *this; } @@ -336,10 +347,12 @@ namespace LinearAlgebra kernel::vec_add <<>>(val.get(), a, n_elements); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } @@ -364,10 +377,12 @@ namespace LinearAlgebra kernel::add_aV<<>>( val.get(), a, down_V.val.get(), n_elements); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } @@ -406,10 +421,12 @@ namespace LinearAlgebra kernel::add_aVbW<<>>( val.get(), a, down_V.val.get(), b, down_W.val.get(), n_elements); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } @@ -437,10 +454,12 @@ namespace LinearAlgebra kernel::sadd<<>>( s, val.get(), a, down_V.val.get(), n_elements); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } @@ -464,10 +483,12 @@ namespace LinearAlgebra kernel::scale<<>>( val.get(), down_scaling_factors.val.get(), n_elements); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } @@ -493,10 +514,12 @@ namespace LinearAlgebra kernel::equ<<>>( val.get(), a, down_V.val.get(), n_elements); +# ifdef DEBUG // Check that the kernel was launched correctly AssertCuda(cudaGetLastError()); // Check that there was no problem during the execution of the kernel AssertCuda(cudaDeviceSynchronize()); +# endif } From b2bac494a46b5322fa7d2507c937b1b200bf5491 Mon Sep 17 00:00:00 2001 From: Giovanni Alzetta Date: Wed, 9 Jan 2019 15:32:24 +0100 Subject: [PATCH 124/507] Added new function compute point locations try all --- include/deal.II/grid/grid_tools.h | 41 +++++ source/grid/grid_tools.cc | 120 ++++++++++++--- source/grid/grid_tools.inst.in | 13 ++ .../compute_point_locations_try_all_01.cc | 143 ++++++++++++++++++ .../compute_point_locations_try_all_01.output | 12 ++ 5 files changed, 311 insertions(+), 18 deletions(-) create mode 100644 tests/grid/compute_point_locations_try_all_01.cc create mode 100644 tests/grid/compute_point_locations_try_all_01.output diff --git a/include/deal.II/grid/grid_tools.h b/include/deal.II/grid/grid_tools.h index 3a89f434b751..809de1bccad4 100644 --- a/include/deal.II/grid/grid_tools.h +++ b/include/deal.II/grid/grid_tools.h @@ -720,6 +720,9 @@ namespace GridTools * they belong are the best case. Pre-sorting points, trying to minimize * distances between them, might make the function extremely faster. * + * @note If a point is not found inside the mesh, or is lying inside an + * artificial cell of a parallel::Triangulation, an exception is thrown. + * * @note The actual return type of this function, i.e., the type referenced * above as @p return_type, is * @code @@ -750,6 +753,44 @@ namespace GridTools &cell_hint = typename Triangulation::active_cell_iterator()); + /** + * This function is similar to GridTools::compute_point_locations(), + * but it tries to find and transform every point of @p points. + * + * @return A tuple containing four elements; the first three + * are documented in GridTools::compute_point_locations(). + * The last element of the @p return_type contains the + * indices of points which are not not found inside the mesh + * or lie on artificial cells. + * + * @code + * std::tuple< + * std::vector::active_cell_iterator>, std::vector>>, + * std::vector>, + * std::vector> + * @endcode + * + * For a more detailed documentation see + * GridTools::compute_point_locations(). + */ + template +# ifndef DOXYGEN + std::tuple< + std::vector::active_cell_iterator>, + std::vector>>, + std::vector>, + std::vector> +# else + return_type +# endif + compute_point_locations_try_all( + const Cache & cache, + const std::vector> &points, + const typename Triangulation::active_cell_iterator + &cell_hint = + typename Triangulation::active_cell_iterator()); + /** * Given a @p cache and a list of * @p local_points for each process, find the points lying on the locally diff --git a/source/grid/grid_tools.cc b/source/grid/grid_tools.cc index 201dfe03f9ee..bd97f63dc4b9 100644 --- a/source/grid/grid_tools.cc +++ b/source/grid/grid_tools.cc @@ -4193,14 +4193,50 @@ namespace GridTools const std::vector> &points, const typename Triangulation::active_cell_iterator &cell_hint) + { + const auto cqmp = compute_point_locations_try_all(cache, points, cell_hint); + // Splitting the tuple's components + auto &cells = std::get<0>(cqmp); + auto &qpoints = std::get<1>(cqmp); + auto &maps = std::get<2>(cqmp); + auto &missing_points = std::get<3>(cqmp); + // If a point was not found, throwing an error, as the old + // implementation of compute_point_locations would have done + AssertThrow(std::get<3>(cqmp).size() == 0, + ExcPointNotFound(points[missing_points[0]])); + + (void)missing_points; + + return {std::move(cells), std::move(qpoints), std::move(maps)}; + } + + + + template +#ifndef DOXYGEN + std::tuple< + std::vector::active_cell_iterator>, + std::vector>>, + std::vector>, + std::vector> +#else + return_type +#endif + compute_point_locations_try_all( + const Cache & cache, + const std::vector> &points, + const typename Triangulation::active_cell_iterator + &cell_hint) { // How many points are here? - const unsigned int np = points.size(); + const unsigned int np = points.size(); + std::vector points_outside; std::tuple< std::vector::active_cell_iterator>, std::vector>>, - std::vector>> + std::vector>, + std::vector> cell_qpoint_map; // Now the easy case. @@ -4211,18 +4247,53 @@ namespace GridTools std::pair::active_cell_iterator, Point> my_pair; + + bool found = false; + unsigned int points_checked = 0; if (cell_hint.state() == IteratorState::valid) - my_pair = - GridTools::find_active_cell_around_point(cache, points[0], cell_hint); - else - my_pair = GridTools::find_active_cell_around_point(cache, points[0]); + { + try + { + my_pair = GridTools::find_active_cell_around_point(cache, + points[0], + cell_hint); + found = true; + } + catch (const GridTools::ExcPointNotFound &) + { + points_outside.emplace_back(0); + } + ++points_checked; + } + - std::get<0>(cell_qpoint_map).emplace_back(my_pair.first); - std::get<1>(cell_qpoint_map).emplace_back(1, my_pair.second); - std::get<2>(cell_qpoint_map).emplace_back(1, 0); + while (!found && points_checked < np) + { + try + { + my_pair = + GridTools::find_active_cell_around_point(cache, + points[points_checked]); + found = true; + } + catch (const GridTools::ExcPointNotFound &) + { + points_outside.emplace_back(points_checked); + } + // Updating the position of the analyzed points + ++points_checked; + } + + // If the point has been found in a cell, adding it + if (found) + { + std::get<0>(cell_qpoint_map).emplace_back(my_pair.first); + std::get<1>(cell_qpoint_map).emplace_back(1, my_pair.second); + std::get<2>(cell_qpoint_map).emplace_back(1, points_checked - 1); + } // Now the second easy case. - if (np == 1) + if (np == points_outside.size()) return cell_qpoint_map; // Computing the cell center and diameter Point cell_center = std::get<0>(cell_qpoint_map)[0]->center(); @@ -4230,15 +4301,24 @@ namespace GridTools (0.5 + std::numeric_limits::epsilon()); // Cycle over all points left - for (unsigned int p = 1; p < np; ++p) + for (unsigned int p = points_checked; p < np; ++p) { // Checking if the point is close to the cell center, in which // case calling find active cell with a cell hint - if (cell_center.distance(points[p]) < cell_diameter) - my_pair = GridTools::find_active_cell_around_point( - cache, points[p], std::get<0>(cell_qpoint_map).back()); - else - my_pair = GridTools::find_active_cell_around_point(cache, points[p]); + try + { + if (cell_center.distance(points[p]) < cell_diameter) + my_pair = GridTools::find_active_cell_around_point( + cache, points[p], std::get<0>(cell_qpoint_map).back()); + else + my_pair = + GridTools::find_active_cell_around_point(cache, points[p]); + } + catch (const GridTools::ExcPointNotFound &) + { + points_outside.push_back(p); + continue; + } // Assuming the cell is probably the last cell added if (my_pair.first == std::get<0>(cell_qpoint_map).back()) @@ -4298,7 +4378,8 @@ namespace GridTools // The number of points in all // the cells must be the same as // the number of points we - // started off from. + // started off from, + // plus the points which were ignored for (unsigned int n = 0; n < c; ++n) { Assert(std::get<1>(cell_qpoint_map)[n].size() == @@ -4307,9 +4388,12 @@ namespace GridTools std::get<2>(cell_qpoint_map)[n].size())); qps += std::get<1>(cell_qpoint_map)[n].size(); } - Assert(qps == np, ExcDimensionMismatch(qps, np)); + + Assert(qps + points_outside.size() == np, + ExcDimensionMismatch(qps + points_outside.size(), np)); #endif + std::get<3>(cell_qpoint_map) = points_outside; return cell_qpoint_map; } diff --git a/source/grid/grid_tools.inst.in b/source/grid/grid_tools.inst.in index c8b0ce9120e1..23dd04b907b6 100644 --- a/source/grid/grid_tools.inst.in +++ b/source/grid/grid_tools.inst.in @@ -93,6 +93,19 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) deal_II_space_dimension>::active_cell_iterator &, const std::vector &); + template std::tuple::active_cell_iterator>, + std::vector>>, + std::vector>, + std::vector> + compute_point_locations_try_all( + const Cache &, + const std::vector> &, + const typename Triangulation< + deal_II_dimension, + deal_II_space_dimension>::active_cell_iterator &); + template std::tuple::active_cell_iterator>, diff --git a/tests/grid/compute_point_locations_try_all_01.cc b/tests/grid/compute_point_locations_try_all_01.cc new file mode 100644 index 000000000000..ddb72f2e3f77 --- /dev/null +++ b/tests/grid/compute_point_locations_try_all_01.cc @@ -0,0 +1,143 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Test GridTools::compute_point_locations_try_all +// Test for corner case: vector of points, some of which +// lie outside the mesh + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "../tests.h" + +using namespace dealii; + +template +void +test_compute_pt_loc(unsigned int n_points) +{ + deallog << "Testing for dim = " << dim << std::endl; + deallog << "Testing on: " << n_points << " points." << std::endl; + + // Creating a grid in the square [0,1]x[0,1] + Triangulation tria; + GridGenerator::hyper_cube(tria); + tria.refine_global(std::max(6 - dim, 2)); + + // Creating the finite elements needed: + FE_Q fe(1); + DoFHandler dof_handler(tria); + dof_handler.distribute_dofs(fe); + + // Creating the random points + std::vector> points; + + for (size_t i = 0; i < n_points; ++i) + { + points.push_back(random_point()); + // One every three points is + // shifted outside the mesh + if (points.size() % 3 == dim - 1) + { + points.back()[0] += 5.0; + } + } + + // Initializing the cache + GridTools::Cache cache(tria); + + auto cell_qpoint_map = + GridTools::compute_point_locations_try_all(cache, points); + const auto &cells = std::get<0>(cell_qpoint_map); + const auto &qpoints = std::get<1>(cell_qpoint_map); + const auto &maps = std::get<2>(cell_qpoint_map); + const auto &other_p = std::get<3>(cell_qpoint_map); + size_t n_cells = cells.size(); + + deallog << "Points found in " << n_cells << " cells" << std::endl; + + unsigned int checked_points = 0; + // testing if the transformation is correct: + for (unsigned int i = 0; i < n_cells; ++i) + { + const auto &cell = cells[i]; + const auto &quad = qpoints[i]; + const auto &local_map = maps[i]; + + // Given the std::get<1>(cell_qpoint_map) of the current cell, compute the + // real points + FEValues fev(fe, quad, update_quadrature_points); + fev.reinit(cell); + const auto &real_quad = fev.get_quadrature_points(); + + for (unsigned int q = 0; q < real_quad.size(); ++q) + { + // Check if points are the same as real points + if (real_quad[q].distance(points[local_map[q]]) > 1e-10) + deallog << "Error on cell : " << cell << " at local point " << i + << ", corresponding to real point " << points[local_map[q]] + << ", that got transformed to " << real_quad[q] + << " instead." << std::endl; + else + ++checked_points; + } + } + for (auto i : other_p) + if (i % 3 != dim - 2) + { + deallog << "Error: point index " << i << " was not found!" << std::endl; + } + + if (checked_points + other_p.size() == points.size()) + deallog << "All points where processed correctly" << std::endl; + else + { + deallog << "Error: some points where not processed correctly" + << std::endl; + deallog << "Points found inside the mesh: " << checked_points + << std::endl; + deallog << "Discarded points: " << points.size() - checked_points + << std::endl; + deallog << "Points outside the mesh: " << other_p.size() << std::endl; + deallog << "Total points processed: " << points.size() << std::endl; + } + deallog << "Test finished" << std::endl; +} + +int +main() +{ + initlog(); + + deallog << "Deal.II compute_pt_loc_try_all:" << std::endl; + test_compute_pt_loc<2>(101); + test_compute_pt_loc<3>(202); +} diff --git a/tests/grid/compute_point_locations_try_all_01.output b/tests/grid/compute_point_locations_try_all_01.output new file mode 100644 index 000000000000..1272686f8528 --- /dev/null +++ b/tests/grid/compute_point_locations_try_all_01.output @@ -0,0 +1,12 @@ + +DEAL::Deal.II compute_pt_loc_try_all: +DEAL::Testing for dim = 2 +DEAL::Testing on: 101 points. +DEAL::Points found in 58 cells +DEAL::All points where processed correctly +DEAL::Test finished +DEAL::Testing for dim = 3 +DEAL::Testing on: 202 points. +DEAL::Points found in 119 cells +DEAL::All points where processed correctly +DEAL::Test finished From 5cca395fd110d6d30112aca0f157133c92cc9dfd Mon Sep 17 00:00:00 2001 From: Sebastian Stark Date: Wed, 13 Feb 2019 13:33:09 +0200 Subject: [PATCH 125/507] Fix bug in distribute_local_to_global If a local matrix with all diagonal elements equal to zero is distributed to a global matrix, the l1 norm of the local matrix divided by the size of the local matrix is now added to those diagonal elements of the global matrix which correspond to a constrained dof. In case the entire local matrix is zero, 1 is added. Previously zero was added for both cases, possibly resulting in singular global matrices. Additionally, a test for the patched version of distribute_local_to_global has been added. Fixes #7658 --- doc/news/changes/minor/20190213SebastianStark | 3 + .../lac/affine_constraints.templates.h | 20 ++++- ...nstraint_matrix_distribute_local_global.cc | 78 +++++++++++++++++++ ...aint_matrix_distribute_local_global.output | 7 ++ 4 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 doc/news/changes/minor/20190213SebastianStark create mode 100644 tests/lac/constraint_matrix_distribute_local_global.cc create mode 100644 tests/lac/constraint_matrix_distribute_local_global.output 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/include/deal.II/lac/affine_constraints.templates.h b/include/deal.II/lac/affine_constraints.templates.h index dc0df47d7f5a..9eb936ec9f73 100644 --- a/include/deal.II/lac/affine_constraints.templates.h +++ b/include/deal.II/lac/affine_constraints.templates.h @@ -3325,9 +3325,13 @@ namespace internals } // to make sure that the global matrix remains invertible, we need to do - // something with the diagonal elements. add the absolute value of the local - // matrix, so the resulting entry will always be positive and furthermore be - // in the same order of magnitude as the other elements of the matrix + // something with the diagonal elements. Add the average of the + // absolute values of the local matrix diagonals, so the resulting entry + // will always be positive and furthermore be in the same order of magnitude + // as the other elements of the matrix. If all local matrix diagonals are + // zero, add the l1 norm of the local matrix divided by the matrix size + // to the diagonal of the global matrix. If the entire local matrix is zero, + // add 1 to the diagonal of the global matrix. // // note that this also captures the special case that a dof is both // constrained and fixed (this can happen for hanging nodes in 3d that also @@ -3355,6 +3359,16 @@ namespace internals average_diagonal += std::abs(local_matrix(i, i)); average_diagonal /= static_cast(local_matrix.m()); + // handle the case that all diagonal elements are zero + if (average_diagonal == static_cast(0.)) + { + average_diagonal = static_cast(local_matrix.l1_norm()) / + static_cast(local_matrix.m()); + // if the entire matrix is zero, use 1. for the diagonal + if (average_diagonal == static_cast(0.)) + average_diagonal = static_cast(1.); + } + for (size_type i = 0; i < global_rows.n_constraints(); i++) { const size_type local_row = global_rows.constraint_origin(i); diff --git a/tests/lac/constraint_matrix_distribute_local_global.cc b/tests/lac/constraint_matrix_distribute_local_global.cc new file mode 100644 index 000000000000..c76d1372cd68 --- /dev/null +++ b/tests/lac/constraint_matrix_distribute_local_global.cc @@ -0,0 +1,78 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2005 - 2016 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 +#include +#include + +#include + +#include + +#include "../tests.h" + +// Tests distribute_local_to_global for +// (1) the case that a local matrix +// with all diagonals equal to zero is +// distributed while a dof is +// constrained, and +// (2) the case that all entries of the local matrix +// are zero while a dof is constrained. + +using namespace dealii; + +int +main() +{ + initlog(); + + // set up constraint + AffineConstraints constraints; + constraints.add_line(0); + constraints.close(); + + // global matrix and vector + FullMatrix global_matrix(2); + Vector global_vector(2); + + // first test: add matrix with all diagonals zero + FullMatrix local_matrix(2); + local_matrix(1, 0) = local_matrix(0, 1) = 1.; + Vector local_vector(2); + constraints.distribute_local_to_global( + local_matrix, local_vector, {0, 1}, global_matrix, global_vector, true); + // output result + for (unsigned int m = 0; m < global_matrix.m(); ++m) + { + for (unsigned int n = 0; n < global_matrix.n(); ++n) + deallog << global_matrix(m, n) << " "; + deallog << std::endl; + } + deallog << std::endl; + + // second test: add matrix with all entries zero + global_matrix = 0.; + local_matrix = 0.; + constraints.distribute_local_to_global( + local_matrix, local_vector, {0, 1}, global_matrix, global_vector, true); + // output result + for (unsigned int m = 0; m < global_matrix.m(); ++m) + { + for (unsigned int n = 0; n < global_matrix.n(); ++n) + deallog << global_matrix(m, n) << " "; + deallog << std::endl; + } + deallog << std::endl; +} diff --git a/tests/lac/constraint_matrix_distribute_local_global.output b/tests/lac/constraint_matrix_distribute_local_global.output new file mode 100644 index 000000000000..6e129c4244cb --- /dev/null +++ b/tests/lac/constraint_matrix_distribute_local_global.output @@ -0,0 +1,7 @@ + +DEAL::0.500000 0.00000 +DEAL::0.00000 0.00000 +DEAL:: +DEAL::1.00000 0.00000 +DEAL::0.00000 0.00000 +DEAL:: From c7a3e6a787f0a1ddc8eb5ae5d43a77df2680eec8 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Tue, 12 Feb 2019 14:34:17 -0600 Subject: [PATCH 126/507] lac/linear_operator.h: Add rvalue-reference variant of inverse_operator --- include/deal.II/lac/linear_operator.h | 106 ++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/include/deal.II/lac/linear_operator.h b/include/deal.II/lac/linear_operator.h index ef84db6e253c..f0115ff2578d 100644 --- a/include/deal.II/lac/linear_operator.h +++ b/include/deal.II/lac/linear_operator.h @@ -41,6 +41,8 @@ namespace internal template class Vector; +class PreconditionIdentity; + template , typename Domain = Range, typename Payload = @@ -71,6 +73,10 @@ template < LinearOperator null_operator(const LinearOperator &); +template +LinearOperator +identity_operator(const LinearOperator &); + /** * A class to store the abstract concept of a linear operator. @@ -629,6 +635,7 @@ operator*(const LinearOperator & first_op, } } + /** * @relatesalso LinearOperator * @@ -725,6 +732,105 @@ inverse_operator(const LinearOperator &op, return return_op; } + +/** + * @relatesalso LinearOperator + * + * Variant of above function that takes a LinearOperator @p preconditioner + * as preconditioner argument. + * + * @ingroup LAOperators + */ +template +LinearOperator +inverse_operator(const LinearOperator &op, + Solver & solver, + const LinearOperator &preconditioner) +{ + LinearOperator return_op( + op.inverse_payload(solver, preconditioner)); + + return_op.reinit_range_vector = op.reinit_domain_vector; + return_op.reinit_domain_vector = op.reinit_range_vector; + + return_op.vmult = [op, &solver, preconditioner](Range &v, const Domain &u) { + op.reinit_range_vector(v, /*bool omit_zeroing_entries =*/false); + solver.solve(op, v, u, preconditioner); + }; + + return_op.vmult_add = [op, &solver, preconditioner](Range & v, + const Domain &u) { + GrowingVectorMemory vector_memory; + + typename VectorMemory::Pointer v2(vector_memory); + op.reinit_range_vector(*v2, /*bool omit_zeroing_entries =*/false); + solver.solve(op, *v2, u, preconditioner); + v += *v2; + }; + + return_op.Tvmult = [op, &solver, preconditioner](Range &v, const Domain &u) { + op.reinit_range_vector(v, /*bool omit_zeroing_entries =*/false); + solver.solve(transpose_operator(op), v, u, preconditioner); + }; + + return_op.Tvmult_add = [op, &solver, preconditioner](Range & v, + const Domain &u) { + GrowingVectorMemory vector_memory; + + typename VectorMemory::Pointer v2(vector_memory); + op.reinit_range_vector(*v2, /*bool omit_zeroing_entries =*/false); + solver.solve(transpose_operator(op), *v2, u, preconditioner); + v += *v2; + }; + + return return_op; +} + + +/** + * @relatesalso LinearOperator + * + * Variant of above function without a preconditioner argument. In this + * case the identity_operator() of the @p op argument is used as a + * preconditioner. This is equivalent to using PreconditionIdentity. + * + * @ingroup LAOperators + */ +template +LinearOperator +inverse_operator(const LinearOperator &op, + Solver & solver) +{ + return inverse_operator(op, solver, identity_operator(op)); +} + + +/** + * @relatesalso LinearOperator + * + * Special overload of above function that takes a PreconditionIdentity + * argument. + * + * @ingroup LAOperators + */ +template +LinearOperator +inverse_operator(const LinearOperator &op, + Solver & solver, + const PreconditionIdentity &) +{ + return inverse_operator(op, solver); +} + //@} From fadf55490d527d8c03b74bc3f11382f766b20369 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Wed, 13 Feb 2019 16:46:32 -0600 Subject: [PATCH 127/507] add a test --- tests/lac/linear_operator_01d.cc | 90 ++++++++++++++++++++++++++++ tests/lac/linear_operator_01d.output | 2 + 2 files changed, 92 insertions(+) create mode 100644 tests/lac/linear_operator_01d.cc create mode 100644 tests/lac/linear_operator_01d.output diff --git a/tests/lac/linear_operator_01d.cc b/tests/lac/linear_operator_01d.cc new file mode 100644 index 000000000000..b5482f5a9d44 --- /dev/null +++ b/tests/lac/linear_operator_01d.cc @@ -0,0 +1,90 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2015 - 2016 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. +// +// --------------------------------------------------------------------- + +// Verify that the inverse_operator function signature without a +// preconditioner argument and the one with PreconditionIdentity() as a +// temporary works correctly. + +#include +#include +#include +#include +#include +#include +#include + +#include "../tests.h" + +using namespace dealii; + +int +main() +{ + initlog(); + + Vector answer(2); + answer[0] = 0.25; + answer[1] = 0.25; + + SparsityPattern sparsity_pattern(2, 2, 1); + sparsity_pattern.add(0, 0); + sparsity_pattern.add(1, 1); + sparsity_pattern.compress(); + + SparseMatrix A(sparsity_pattern); + A.set(0, 0, 4.0); + A.set(1, 1, 4.0); + + Vector b(2); + b[0] = 1.0; + b[1] = 1.0; + + const auto lo_A = linear_operator(A); + + // As we all remember from numerical analysis class, CG will converge in + // at most two iterations + SolverControl solver_control_A(2, 1.0e-15); + + SolverCG> solver_A(solver_control_A); + + const auto lo_A_inv = inverse_operator(lo_A, solver_A); + const auto lo_A_inv_t = transpose_operator(lo_A_inv); + + deallog.depth_file(0); + + unsigned int n_mistakes{0}; + + Vector residual; // keep storage location to trigger bug. + + for (unsigned int j = 0; j < 1000; ++j) + { + // test Tvmult: + residual = lo_A_inv_t * b; + residual -= answer; + if (residual.l2_norm() > 1e-10) + ++n_mistakes; + + // test Tvmult_add: + residual = lo_A_inv_t * b - answer; + if (residual.l2_norm() > 1e-10) + ++n_mistakes; + } + + deallog.depth_file(3); + + deallog << "number of mistakes: " << n_mistakes << std::endl; + if (n_mistakes != 0) + deallog << "Ooops!" << std::endl; +} diff --git a/tests/lac/linear_operator_01d.output b/tests/lac/linear_operator_01d.output new file mode 100644 index 000000000000..9694fcba7f0e --- /dev/null +++ b/tests/lac/linear_operator_01d.output @@ -0,0 +1,2 @@ + +DEAL::number of mistakes: 0 From 49717f7bbe7e2299544ee11a45c90cbe387b3710 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Wed, 13 Feb 2019 16:50:21 -0600 Subject: [PATCH 128/507] add a changelog entry --- doc/news/changes/minor/20190213MatthiasMaier | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 doc/news/changes/minor/20190213MatthiasMaier diff --git a/doc/news/changes/minor/20190213MatthiasMaier b/doc/news/changes/minor/20190213MatthiasMaier new file mode 100644 index 000000000000..6d3a30db0f87 --- /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 2018/06/11) From 094a1d2acb10c2fc946e5e9728427c9790f30744 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Wed, 13 Feb 2019 16:51:16 -0600 Subject: [PATCH 129/507] examples/step-20: Simplify code by using a temporary --- examples/step-20/step-20.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/step-20/step-20.cc b/examples/step-20/step-20.cc index f1b12f6e185d..89ed11124b16 100644 --- a/examples/step-20/step-20.cc +++ b/examples/step-20/step-20.cc @@ -613,10 +613,9 @@ namespace Step20 // 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); - PreconditionIdentity preconditioner_aS; const auto preconditioner_S = - inverse_operator(op_aS, solver_aS, preconditioner_aS); + 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 From 2c2d43580f7cfc06e8551b88de783eeec70fb6df Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Thu, 14 Feb 2019 13:12:06 -0600 Subject: [PATCH 130/507] lac/linear_operator.h: Prevent users from creating LinearOperators with temoporaries --- include/deal.II/lac/linear_operator.h | 119 ++++++++++++++++++++++++++ tests/lac/linear_operator_18.cc | 55 ++++++++++++ tests/lac/linear_operator_18.output | 6 ++ 3 files changed, 180 insertions(+) create mode 100644 tests/lac/linear_operator_18.cc create mode 100644 tests/lac/linear_operator_18.output diff --git a/include/deal.II/lac/linear_operator.h b/include/deal.II/lac/linear_operator.h index f0115ff2578d..64dff9a09960 100644 --- a/include/deal.II/lac/linear_operator.h +++ b/include/deal.II/lac/linear_operator.h @@ -1473,6 +1473,125 @@ linear_operator(const LinearOperator &operator_exemplar, //@} +#ifndef DOXYGEN + +// +// Ensure that we never capture a reference to a temporary by accident. +// This ensures that instead of silently allowing a "stack use after free", +// we at least bail out with a runtime error message that is slightly more +// understandable. +// + +template < + typename Range = Vector, + typename Domain = Range, + typename Payload = internal::LinearOperatorImplementation::EmptyPayload, + typename OperatorExemplar, + typename Matrix, + typename = + typename std::enable_if::value>::type> +LinearOperator +linear_operator(const OperatorExemplar &, Matrix &&) +{ + Assert(false, + ExcMessage( + "You are trying to construct a linear operator from a temporary " + "matrix object.")); +} + +template < + typename Range = Vector, + typename Domain = Range, + typename Payload = internal::LinearOperatorImplementation::EmptyPayload, + typename OperatorExemplar, + typename Matrix, + typename = typename std::enable_if< + !std::is_lvalue_reference::value>::type> +LinearOperator +linear_operator(OperatorExemplar &&, const Matrix &) +{ + Assert(false, + ExcMessage( + "You are trying to construct a linear operator with a temporary " + "operator_exemplar object.")); +} + +template < + typename Range = Vector, + typename Domain = Range, + typename Payload = internal::LinearOperatorImplementation::EmptyPayload, + typename OperatorExemplar, + typename Matrix, + typename = + typename std::enable_if::value>::type, + typename = typename std::enable_if< + !std::is_lvalue_reference::value>::type> +LinearOperator +linear_operator(OperatorExemplar &&, Matrix &&) +{ + Assert(false, + ExcMessage( + "You are trying to construct a linear operator from a temporary " + "matrix object.")); +} + + +template < + typename Range = Vector, + typename Domain = Range, + typename Payload = internal::LinearOperatorImplementation::EmptyPayload, + typename Matrix, + typename = + typename std::enable_if::value>::type> +LinearOperator +linear_operator(const LinearOperator &, Matrix &&) +{ + Assert(false, + ExcMessage( + "You are trying to construct a linear operator from a temporary " + "matrix object.")); +} + +template < + typename Range = Vector, + typename Domain = Range, + typename Payload = internal::LinearOperatorImplementation::EmptyPayload, + typename Matrix, + typename = + typename std::enable_if::value>::type> +LinearOperator +linear_operator(Matrix &&) +{ + Assert(false, + ExcMessage( + "You are trying to construct a linear operator from a temporary " + "matrix object.")); +} + +template ::value>::type, + typename = typename std::enable_if< + !std::is_same::value>::type, + typename = typename std::enable_if< + !std::is_same>::value>::type> +LinearOperator +inverse_operator(const LinearOperator &, + Solver &, + Preconditioner &&) +{ + Assert(false, + ExcMessage( + "You are trying to construct an inverse operator with a temporary " + "preconditioner object.")); +} + +#endif // DOXYGEN DEAL_II_NAMESPACE_CLOSE diff --git a/tests/lac/linear_operator_18.cc b/tests/lac/linear_operator_18.cc new file mode 100644 index 000000000000..08fbfb180152 --- /dev/null +++ b/tests/lac/linear_operator_18.cc @@ -0,0 +1,55 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2015 - 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. +// +// --------------------------------------------------------------------- + +// Test that we cannot accidentally create a linear operator from a +// temporary object + +#include +#include +#include + +#include "../tests.h" + +#define CATCH(call) \ + try \ + { \ + call; \ + deallog << "Error: Something went wrong!" << std::endl; \ + } \ + catch (ExceptionBase & e) \ + { \ + deallog << e.get_exc_name() << std::endl; \ + } + +using namespace dealii; + +int +main() +{ + initlog(); + deal_II_exceptions::disable_abort_on_exception(); + + SparseMatrix A; + const auto op_A = linear_operator(A); + + CATCH(linear_operator(SparseMatrix())) + CATCH(linear_operator(SparseMatrix(), A)) + CATCH(linear_operator(A, SparseMatrix())) + CATCH(linear_operator(SparseMatrix(), SparseMatrix())) + + SolverControl solver_control; + SolverCG> solver(solver_control); + CATCH(inverse_operator(op_A, solver, SparseMatrix())) +} diff --git a/tests/lac/linear_operator_18.output b/tests/lac/linear_operator_18.output new file mode 100644 index 000000000000..8aad5753bce2 --- /dev/null +++ b/tests/lac/linear_operator_18.output @@ -0,0 +1,6 @@ + +DEAL::ExcMessage( "You are trying to construct a linear operator from a temporary " "matrix object.") +DEAL::ExcMessage( "You are trying to construct a linear operator with a temporary " "operator_exemplar object.") +DEAL::ExcMessage( "You are trying to construct a linear operator from a temporary " "matrix object.") +DEAL::ExcMessage( "You are trying to construct a linear operator from a temporary " "matrix object.") +DEAL::ExcMessage( "You are trying to construct an inverse operator with a temporary " "preconditioner object.") From 225cc0c87449c6c1baaa88e694c223560e353308 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 14 Feb 2019 22:50:50 +0100 Subject: [PATCH 131/507] Delete the disallowed functions instead --- include/deal.II/lac/linear_operator.h | 64 +++++++-------------------- tests/lac/linear_operator_18.cc | 55 ----------------------- tests/lac/linear_operator_18.output | 6 --- 3 files changed, 16 insertions(+), 109 deletions(-) delete mode 100644 tests/lac/linear_operator_18.cc delete mode 100644 tests/lac/linear_operator_18.output diff --git a/include/deal.II/lac/linear_operator.h b/include/deal.II/lac/linear_operator.h index 64dff9a09960..b8e118fe112c 100644 --- a/include/deal.II/lac/linear_operator.h +++ b/include/deal.II/lac/linear_operator.h @@ -1477,9 +1477,7 @@ linear_operator(const LinearOperator &operator_exemplar, // // Ensure that we never capture a reference to a temporary by accident. -// This ensures that instead of silently allowing a "stack use after free", -// we at least bail out with a runtime error message that is slightly more -// understandable. +// to avoid "stack use after free". // template < @@ -1491,13 +1489,7 @@ template < typename = typename std::enable_if::value>::type> LinearOperator -linear_operator(const OperatorExemplar &, Matrix &&) -{ - Assert(false, - ExcMessage( - "You are trying to construct a linear operator from a temporary " - "matrix object.")); -} +linear_operator(const OperatorExemplar &, Matrix &&) = delete; template < typename Range = Vector, @@ -1506,15 +1498,12 @@ template < typename OperatorExemplar, typename Matrix, typename = typename std::enable_if< - !std::is_lvalue_reference::value>::type> + !std::is_lvalue_reference::value>::type, + typename = typename std::enable_if< + !std::is_same>::value>::type> LinearOperator -linear_operator(OperatorExemplar &&, const Matrix &) -{ - Assert(false, - ExcMessage( - "You are trying to construct a linear operator with a temporary " - "operator_exemplar object.")); -} +linear_operator(OperatorExemplar &&, const Matrix &) = delete; template < typename Range = Vector, @@ -1525,16 +1514,12 @@ template < typename = typename std::enable_if::value>::type, typename = typename std::enable_if< - !std::is_lvalue_reference::value>::type> + !std::is_lvalue_reference::value>::type, + typename = typename std::enable_if< + !std::is_same>::value>::type> LinearOperator -linear_operator(OperatorExemplar &&, Matrix &&) -{ - Assert(false, - ExcMessage( - "You are trying to construct a linear operator from a temporary " - "matrix object.")); -} - +linear_operator(OperatorExemplar &&, Matrix &&) = delete; template < typename Range = Vector, @@ -1544,13 +1529,8 @@ template < typename = typename std::enable_if::value>::type> LinearOperator -linear_operator(const LinearOperator &, Matrix &&) -{ - Assert(false, - ExcMessage( - "You are trying to construct a linear operator from a temporary " - "matrix object.")); -} +linear_operator(const LinearOperator &, + Matrix &&) = delete; template < typename Range = Vector, @@ -1560,13 +1540,7 @@ template < typename = typename std::enable_if::value>::type> LinearOperator -linear_operator(Matrix &&) -{ - Assert(false, - ExcMessage( - "You are trying to construct a linear operator from a temporary " - "matrix object.")); -} +linear_operator(Matrix &&) = delete; template inverse_operator(const LinearOperator &, Solver &, - Preconditioner &&) -{ - Assert(false, - ExcMessage( - "You are trying to construct an inverse operator with a temporary " - "preconditioner object.")); -} + Preconditioner &&) = delete; #endif // DOXYGEN diff --git a/tests/lac/linear_operator_18.cc b/tests/lac/linear_operator_18.cc deleted file mode 100644 index 08fbfb180152..000000000000 --- a/tests/lac/linear_operator_18.cc +++ /dev/null @@ -1,55 +0,0 @@ -// --------------------------------------------------------------------- -// -// Copyright (C) 2015 - 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. -// -// --------------------------------------------------------------------- - -// Test that we cannot accidentally create a linear operator from a -// temporary object - -#include -#include -#include - -#include "../tests.h" - -#define CATCH(call) \ - try \ - { \ - call; \ - deallog << "Error: Something went wrong!" << std::endl; \ - } \ - catch (ExceptionBase & e) \ - { \ - deallog << e.get_exc_name() << std::endl; \ - } - -using namespace dealii; - -int -main() -{ - initlog(); - deal_II_exceptions::disable_abort_on_exception(); - - SparseMatrix A; - const auto op_A = linear_operator(A); - - CATCH(linear_operator(SparseMatrix())) - CATCH(linear_operator(SparseMatrix(), A)) - CATCH(linear_operator(A, SparseMatrix())) - CATCH(linear_operator(SparseMatrix(), SparseMatrix())) - - SolverControl solver_control; - SolverCG> solver(solver_control); - CATCH(inverse_operator(op_A, solver, SparseMatrix())) -} diff --git a/tests/lac/linear_operator_18.output b/tests/lac/linear_operator_18.output deleted file mode 100644 index 8aad5753bce2..000000000000 --- a/tests/lac/linear_operator_18.output +++ /dev/null @@ -1,6 +0,0 @@ - -DEAL::ExcMessage( "You are trying to construct a linear operator from a temporary " "matrix object.") -DEAL::ExcMessage( "You are trying to construct a linear operator with a temporary " "operator_exemplar object.") -DEAL::ExcMessage( "You are trying to construct a linear operator from a temporary " "matrix object.") -DEAL::ExcMessage( "You are trying to construct a linear operator from a temporary " "matrix object.") -DEAL::ExcMessage( "You are trying to construct an inverse operator with a temporary " "preconditioner object.") From cfdd06c2bd8388581be15e2f8e825a7bb44341d9 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 14 Feb 2019 00:40:26 +0100 Subject: [PATCH 132/507] Fix return value --- include/deal.II/grid/grid_tools.h | 9 +++++---- source/grid/grid_tools.cc | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/deal.II/grid/grid_tools.h b/include/deal.II/grid/grid_tools.h index 809de1bccad4..d8e9050b414e 100644 --- a/include/deal.II/grid/grid_tools.h +++ b/include/deal.II/grid/grid_tools.h @@ -765,10 +765,11 @@ namespace GridTools * * @code * std::tuple< - * std::vector::active_cell_iterator>, std::vector>>, - * std::vector>, - * std::vector> + * std::vector< + * typename Triangulation::active_cell_iterator>, + * std::vector>>, + * std::vector>, + * std::vector > * @endcode * * For a more detailed documentation see diff --git a/source/grid/grid_tools.cc b/source/grid/grid_tools.cc index bd97f63dc4b9..58d12d3a94fc 100644 --- a/source/grid/grid_tools.cc +++ b/source/grid/grid_tools.cc @@ -4207,7 +4207,9 @@ namespace GridTools (void)missing_points; - return {std::move(cells), std::move(qpoints), std::move(maps)}; + return std::make_tuple(std::move(cells), + std::move(qpoints), + std::move(maps)); } From bc7358286f2f2614713ea2735d53cd01b0259639 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Fri, 15 Feb 2019 18:00:02 +0100 Subject: [PATCH 133/507] allow zero padding in plate_with_a_hole --- include/deal.II/grid/grid_generator.h | 3 +- source/grid/grid_generator.cc | 129 +++++---- .../grid_generator_plate_with_a_hole_4.cc | 121 ++++++++ .../grid_generator_plate_with_a_hole_4.output | 261 ++++++++++++++++++ 4 files changed, 451 insertions(+), 63 deletions(-) create mode 100644 tests/grid/grid_generator_plate_with_a_hole_4.cc create mode 100644 tests/grid/grid_generator_plate_with_a_hole_4.output diff --git a/include/deal.II/grid/grid_generator.h b/include/deal.II/grid/grid_generator.h index 318646b14c96..caa95daf80dc 100644 --- a/include/deal.II/grid/grid_generator.h +++ b/include/deal.II/grid/grid_generator.h @@ -327,8 +327,7 @@ namespace GridGenerator * All cells in this region will have a FlatManifold attached to them. * The final width of the plate will be padding_left + 2*outer_radius + * padding_right, while its length is padding_top + - * 2*outer_radius + padding_bottom. Three out of four paddings are - * allowed to be zero. + * 2*outer_radius + padding_bottom. * * Here is the non-symmetric grid (after one global refinement, colored * according to manifold id) in 2D and 3D, respectively: diff --git a/source/grid/grid_generator.cc b/source/grid/grid_generator.cc index 08eb9c701fb2..e774a7368ae2 100644 --- a/source/grid/grid_generator.cc +++ b/source/grid/grid_generator.cc @@ -1966,8 +1966,9 @@ namespace GridGenerator const unsigned int /*n_slices*/, const bool colorize) { - Assert((pad_bottom > 0 || pad_top > 0 || pad_left > 0 || pad_right > 0), - ExcMessage("At least one padding parameter has to be non-zero.")); + const bool with_padding = + pad_bottom > 0 || pad_top > 0 || pad_left > 0 || pad_right > 0; + Assert(pad_bottom >= 0., ExcMessage("Negative bottom padding.")); Assert(pad_top >= 0., ExcMessage("Negative top padding.")); Assert(pad_left >= 0., ExcMessage("Negative left padding.")); @@ -1984,7 +1985,8 @@ namespace GridGenerator }; // start by setting up the cylinder triangulation - Triangulation<2> cylinder_tria; + Triangulation<2> cylinder_tria_maybe; + Triangulation<2> &cylinder_tria = with_padding ? cylinder_tria_maybe : tria; GridGenerator::hyper_cube_with_cylindrical_hole(cylinder_tria, inner_radius, outer_radius, @@ -1996,65 +1998,70 @@ namespace GridGenerator for (const auto &cell : cylinder_tria.active_cell_iterators()) cell->set_manifold_id(tfi_manifold_id); - // hyper_cube_with_cylindrical_hole will have 2 cells along - // each face, so he element size is outer_radius - - auto add_sizes = [](std::vector &step_sizes, - const double padding, - const double h) -> void { - // use std::round instead of std::ceil to improve aspect ratio - // in case padding is only slightly larger than h. - const auto rounded = static_cast(std::round(padding / h)); - // in case padding is much smaller than h, make sure we - // have at least 1 element - const unsigned int num = (padding > 0. && rounded == 0) ? 1 : rounded; - for (unsigned int i = 0; i < num; ++i) - step_sizes.push_back(padding / num); - }; - - std::vector> step_sizes(2); - // x-coord - // left: - add_sizes(step_sizes[0], pad_left, outer_radius); - // center - step_sizes[0].push_back(outer_radius); - step_sizes[0].push_back(outer_radius); - // right - add_sizes(step_sizes[0], pad_right, outer_radius); - // y-coord - // bottom - add_sizes(step_sizes[1], pad_bottom, outer_radius); - // center - step_sizes[1].push_back(outer_radius); - step_sizes[1].push_back(outer_radius); - // top - add_sizes(step_sizes[1], pad_top, outer_radius); - - // now create bulk - Triangulation<2> bulk_tria; - const Point<2> bl(-outer_radius - pad_left, -outer_radius - pad_bottom); - const Point<2> tr(outer_radius + pad_right, outer_radius + pad_top); - GridGenerator::subdivided_hyper_rectangle( - bulk_tria, step_sizes, bl, tr, colorize); - - // now remove cells reserved from the cylindrical hole - std::set::active_cell_iterator> cells_to_remove; - for (const auto &cell : bulk_tria.active_cell_iterators()) - if (internal::point_in_2d_box(cell->center(), center, outer_radius)) - cells_to_remove.insert(cell); - - Triangulation<2> tria_without_cylinder; - GridGenerator::create_triangulation_with_removed_cells( - bulk_tria, cells_to_remove, tria_without_cylinder); - - const double tolerance = std::min(min_line_length(tria_without_cylinder), - min_line_length(cylinder_tria)) / - 2.0; + const Point<2> bl(-outer_radius - pad_left, -outer_radius - pad_bottom); + const Point<2> tr(outer_radius + pad_right, outer_radius + pad_top); + if (with_padding) + { + // hyper_cube_with_cylindrical_hole will have 2 cells along + // each face, so he element size is outer_radius + + auto add_sizes = [](std::vector &step_sizes, + const double padding, + const double h) -> void { + // use std::round instead of std::ceil to improve aspect ratio + // in case padding is only slightly larger than h. + const auto rounded = + static_cast(std::round(padding / h)); + // in case padding is much smaller than h, make sure we + // have at least 1 element + const unsigned int num = (padding > 0. && rounded == 0) ? 1 : rounded; + for (unsigned int i = 0; i < num; ++i) + step_sizes.push_back(padding / num); + }; - GridGenerator::merge_triangulations(tria_without_cylinder, - cylinder_tria, - tria, - tolerance); + std::vector> step_sizes(2); + // x-coord + // left: + add_sizes(step_sizes[0], pad_left, outer_radius); + // center + step_sizes[0].push_back(outer_radius); + step_sizes[0].push_back(outer_radius); + // right + add_sizes(step_sizes[0], pad_right, outer_radius); + // y-coord + // bottom + add_sizes(step_sizes[1], pad_bottom, outer_radius); + // center + step_sizes[1].push_back(outer_radius); + step_sizes[1].push_back(outer_radius); + // top + add_sizes(step_sizes[1], pad_top, outer_radius); + + // now create bulk + Triangulation<2> bulk_tria; + GridGenerator::subdivided_hyper_rectangle( + bulk_tria, step_sizes, bl, tr, colorize); + + // now remove cells reserved from the cylindrical hole + std::set::active_cell_iterator> cells_to_remove; + for (const auto &cell : bulk_tria.active_cell_iterators()) + if (internal::point_in_2d_box(cell->center(), center, outer_radius)) + cells_to_remove.insert(cell); + + Triangulation<2> tria_without_cylinder; + GridGenerator::create_triangulation_with_removed_cells( + bulk_tria, cells_to_remove, tria_without_cylinder); + + const double tolerance = + std::min(min_line_length(tria_without_cylinder), + min_line_length(cylinder_tria)) / + 2.0; + + GridGenerator::merge_triangulations(tria_without_cylinder, + cylinder_tria, + tria, + tolerance); + } // now set manifold ids: for (const auto &cell : tria.active_cell_iterators()) diff --git a/tests/grid/grid_generator_plate_with_a_hole_4.cc b/tests/grid/grid_generator_plate_with_a_hole_4.cc new file mode 100644 index 000000000000..7631d240d393 --- /dev/null +++ b/tests/grid/grid_generator_plate_with_a_hole_4.cc @@ -0,0 +1,121 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + + +// Test GridGenerator::plate_with_a_hole() with zero padding + +#include + +#include + +#include +#include + +#include + +#include "../tests.h" + +template +void +test() +{ + Triangulation triangulation; + GridGenerator::plate_with_a_hole( + triangulation, 0.4, 1., 0, 0, 0, 0, Point(), 0, 1, 1., 2, true); + + triangulation.refine_global(1); + + using Tuple = std::tuple, types::boundary_id, types::manifold_id>; + std::vector boundary_faces; + + for (const auto &cell : triangulation.active_cell_iterators()) + for (unsigned int face_n = 0; face_n < GeometryInfo::faces_per_cell; + ++face_n) + if (cell->face(face_n)->at_boundary()) + boundary_faces.push_back( + std::make_tuple(cell->face(face_n)->center(), + cell->face(face_n)->boundary_id(), + cell->face(face_n)->manifold_id())); + + // see dof_tools.cc internal::ComparisonHelper + std::sort(begin(boundary_faces), + end(boundary_faces), + [](const Tuple &t1, const Tuple &t2) { + const auto &b1 = std::get<1>(t1); + const auto &b2 = std::get<1>(t2); + if (b1 != b2) + return b1 < b2; + + const auto &p1 = std::get<0>(t1); + const auto &p2 = std::get<0>(t2); + + for (unsigned int d = 0; d < dim; ++d) + if (std::abs(p1[d] - p2[d]) > 1e-8) + return p1[d] < p2[d]; + + return std::get<2>(t1) < std::get<2>(t2); + }); + + for (const auto el : boundary_faces) + deallog << "center: " << std::get<0>(el) + << " boundary id: " << std::get<1>(el) + << " manifold id: " << std::get<2>(el) << std::endl; + + deallog << std::endl << std::endl; + Vector manifold_id(triangulation.n_active_cells()); + unsigned int index = 0; + for (const auto &cell : triangulation.active_cell_iterators()) + { + deallog << "center: " << cell->center() + << " manifold id: " << cell->manifold_id() << std::endl; + manifold_id[index] = cell->manifold_id(); + index++; + } + + // write in vtk for visual inspection + if (false) + { + DoFHandler dof_handler(triangulation); + FE_Q fe(1); + dof_handler.distribute_dofs(fe); + + DataOut data_out; + + data_out.attach_dof_handler(dof_handler); + data_out.add_data_vector(manifold_id, "manifold_id"); + data_out.build_patches(); + + const std::string filename = + "output_" + Utilities::int_to_string(dim) + ".vtu"; + std::ofstream output(filename.c_str()); + data_out.write_vtu(output); + } +} + + +int +main() +{ + initlog(); + + deallog.push("2d"); + test<2>(); + deallog.pop(); + + deallog.push("3d"); + test<3>(); + deallog.pop(); +} diff --git a/tests/grid/grid_generator_plate_with_a_hole_4.output b/tests/grid/grid_generator_plate_with_a_hole_4.output new file mode 100644 index 000000000000..8f7500c6a4da --- /dev/null +++ b/tests/grid/grid_generator_plate_with_a_hole_4.output @@ -0,0 +1,261 @@ + +DEAL:2d::center: -1.00000 -0.750000 boundary id: 0 manifold id: 1 +DEAL:2d::center: -1.00000 -0.250000 boundary id: 0 manifold id: 1 +DEAL:2d::center: -1.00000 0.250000 boundary id: 0 manifold id: 1 +DEAL:2d::center: -1.00000 0.750000 boundary id: 0 manifold id: 1 +DEAL:2d::center: 1.00000 -0.750000 boundary id: 1 manifold id: 1 +DEAL:2d::center: 1.00000 -0.250000 boundary id: 1 manifold id: 1 +DEAL:2d::center: 1.00000 0.250000 boundary id: 1 manifold id: 1 +DEAL:2d::center: 1.00000 0.750000 boundary id: 1 manifold id: 1 +DEAL:2d::center: -0.750000 -1.00000 boundary id: 2 manifold id: 1 +DEAL:2d::center: -0.250000 -1.00000 boundary id: 2 manifold id: 1 +DEAL:2d::center: 0.250000 -1.00000 boundary id: 2 manifold id: 1 +DEAL:2d::center: 0.750000 -1.00000 boundary id: 2 manifold id: 1 +DEAL:2d::center: -0.750000 1.00000 boundary id: 3 manifold id: 1 +DEAL:2d::center: -0.250000 1.00000 boundary id: 3 manifold id: 1 +DEAL:2d::center: 0.250000 1.00000 boundary id: 3 manifold id: 1 +DEAL:2d::center: 0.750000 1.00000 boundary id: 3 manifold id: 1 +DEAL:2d::center: -0.384776 -0.0765367 boundary id: 4 manifold id: 0 +DEAL:2d::center: -0.384776 0.0765367 boundary id: 4 manifold id: 0 +DEAL:2d::center: -0.326197 -0.217958 boundary id: 4 manifold id: 0 +DEAL:2d::center: -0.326197 0.217958 boundary id: 4 manifold id: 0 +DEAL:2d::center: -0.217958 -0.326197 boundary id: 4 manifold id: 0 +DEAL:2d::center: -0.217958 0.326197 boundary id: 4 manifold id: 0 +DEAL:2d::center: -0.0765367 -0.384776 boundary id: 4 manifold id: 0 +DEAL:2d::center: -0.0765367 0.384776 boundary id: 4 manifold id: 0 +DEAL:2d::center: 0.0765367 -0.384776 boundary id: 4 manifold id: 0 +DEAL:2d::center: 0.0765367 0.384776 boundary id: 4 manifold id: 0 +DEAL:2d::center: 0.217958 -0.326197 boundary id: 4 manifold id: 0 +DEAL:2d::center: 0.217958 0.326197 boundary id: 4 manifold id: 0 +DEAL:2d::center: 0.326197 -0.217958 boundary id: 4 manifold id: 0 +DEAL:2d::center: 0.326197 0.217958 boundary id: 4 manifold id: 0 +DEAL:2d::center: 0.384776 -0.0765367 boundary id: 4 manifold id: 0 +DEAL:2d::center: 0.384776 0.0765367 boundary id: 4 manifold id: 0 +DEAL:2d:: +DEAL:2d:: +DEAL:2d::center: 0.846194 0.206634 manifold id: 1 +DEAL:2d::center: 0.831549 0.616990 manifold id: 1 +DEAL:2d::center: 0.538582 0.119903 manifold id: 1 +DEAL:2d::center: 0.494648 0.350969 manifold id: 1 +DEAL:2d::center: 0.616990 0.831549 manifold id: 1 +DEAL:2d::center: 0.206634 0.846194 manifold id: 1 +DEAL:2d::center: 0.350969 0.494648 manifold id: 1 +DEAL:2d::center: 0.119903 0.538582 manifold id: 1 +DEAL:2d::center: -0.206634 0.846194 manifold id: 1 +DEAL:2d::center: -0.616990 0.831549 manifold id: 1 +DEAL:2d::center: -0.119903 0.538582 manifold id: 1 +DEAL:2d::center: -0.350969 0.494648 manifold id: 1 +DEAL:2d::center: -0.831549 0.616990 manifold id: 1 +DEAL:2d::center: -0.846194 0.206634 manifold id: 1 +DEAL:2d::center: -0.494648 0.350969 manifold id: 1 +DEAL:2d::center: -0.538582 0.119903 manifold id: 1 +DEAL:2d::center: -0.846194 -0.206634 manifold id: 1 +DEAL:2d::center: -0.831549 -0.616990 manifold id: 1 +DEAL:2d::center: -0.538582 -0.119903 manifold id: 1 +DEAL:2d::center: -0.494648 -0.350969 manifold id: 1 +DEAL:2d::center: -0.616990 -0.831549 manifold id: 1 +DEAL:2d::center: -0.206634 -0.846194 manifold id: 1 +DEAL:2d::center: -0.350969 -0.494648 manifold id: 1 +DEAL:2d::center: -0.119903 -0.538582 manifold id: 1 +DEAL:2d::center: 0.206634 -0.846194 manifold id: 1 +DEAL:2d::center: 0.616990 -0.831549 manifold id: 1 +DEAL:2d::center: 0.119903 -0.538582 manifold id: 1 +DEAL:2d::center: 0.350969 -0.494648 manifold id: 1 +DEAL:2d::center: 0.831549 -0.616990 manifold id: 1 +DEAL:2d::center: 0.846194 -0.206634 manifold id: 1 +DEAL:2d::center: 0.494648 -0.350969 manifold id: 1 +DEAL:2d::center: 0.538582 -0.119903 manifold id: 1 +DEAL:3d::center: -1.00000 -0.750000 -0.250000 boundary id: 0 manifold id: 1 +DEAL:3d::center: -1.00000 -0.750000 0.250000 boundary id: 0 manifold id: 1 +DEAL:3d::center: -1.00000 -0.250000 -0.250000 boundary id: 0 manifold id: 1 +DEAL:3d::center: -1.00000 -0.250000 0.250000 boundary id: 0 manifold id: 1 +DEAL:3d::center: -1.00000 0.250000 -0.250000 boundary id: 0 manifold id: 1 +DEAL:3d::center: -1.00000 0.250000 0.250000 boundary id: 0 manifold id: 1 +DEAL:3d::center: -1.00000 0.750000 -0.250000 boundary id: 0 manifold id: 1 +DEAL:3d::center: -1.00000 0.750000 0.250000 boundary id: 0 manifold id: 1 +DEAL:3d::center: 1.00000 -0.750000 -0.250000 boundary id: 1 manifold id: 1 +DEAL:3d::center: 1.00000 -0.750000 0.250000 boundary id: 1 manifold id: 1 +DEAL:3d::center: 1.00000 -0.250000 -0.250000 boundary id: 1 manifold id: 1 +DEAL:3d::center: 1.00000 -0.250000 0.250000 boundary id: 1 manifold id: 1 +DEAL:3d::center: 1.00000 0.250000 -0.250000 boundary id: 1 manifold id: 1 +DEAL:3d::center: 1.00000 0.250000 0.250000 boundary id: 1 manifold id: 1 +DEAL:3d::center: 1.00000 0.750000 -0.250000 boundary id: 1 manifold id: 1 +DEAL:3d::center: 1.00000 0.750000 0.250000 boundary id: 1 manifold id: 1 +DEAL:3d::center: -0.750000 -1.00000 -0.250000 boundary id: 2 manifold id: 1 +DEAL:3d::center: -0.750000 -1.00000 0.250000 boundary id: 2 manifold id: 1 +DEAL:3d::center: -0.250000 -1.00000 -0.250000 boundary id: 2 manifold id: 1 +DEAL:3d::center: -0.250000 -1.00000 0.250000 boundary id: 2 manifold id: 1 +DEAL:3d::center: 0.250000 -1.00000 -0.250000 boundary id: 2 manifold id: 1 +DEAL:3d::center: 0.250000 -1.00000 0.250000 boundary id: 2 manifold id: 1 +DEAL:3d::center: 0.750000 -1.00000 -0.250000 boundary id: 2 manifold id: 1 +DEAL:3d::center: 0.750000 -1.00000 0.250000 boundary id: 2 manifold id: 1 +DEAL:3d::center: -0.750000 1.00000 -0.250000 boundary id: 3 manifold id: 1 +DEAL:3d::center: -0.750000 1.00000 0.250000 boundary id: 3 manifold id: 1 +DEAL:3d::center: -0.250000 1.00000 -0.250000 boundary id: 3 manifold id: 1 +DEAL:3d::center: -0.250000 1.00000 0.250000 boundary id: 3 manifold id: 1 +DEAL:3d::center: 0.250000 1.00000 -0.250000 boundary id: 3 manifold id: 1 +DEAL:3d::center: 0.250000 1.00000 0.250000 boundary id: 3 manifold id: 1 +DEAL:3d::center: 0.750000 1.00000 -0.250000 boundary id: 3 manifold id: 1 +DEAL:3d::center: 0.750000 1.00000 0.250000 boundary id: 3 manifold id: 1 +DEAL:3d::center: -0.384776 -0.0765367 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.384776 -0.0765367 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.384776 0.0765367 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.384776 0.0765367 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.326197 -0.217958 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.326197 -0.217958 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.326197 0.217958 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.326197 0.217958 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.217958 -0.326197 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.217958 -0.326197 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.217958 0.326197 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.217958 0.326197 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.0765367 -0.384776 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.0765367 -0.384776 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.0765367 0.384776 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.0765367 0.384776 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.0765367 -0.384776 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.0765367 -0.384776 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.0765367 0.384776 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.0765367 0.384776 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.217958 -0.326197 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.217958 -0.326197 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.217958 0.326197 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.217958 0.326197 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.326197 -0.217958 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.326197 -0.217958 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.326197 0.217958 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.326197 0.217958 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.384776 -0.0765367 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.384776 -0.0765367 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.384776 0.0765367 -0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: 0.384776 0.0765367 0.250000 boundary id: 4 manifold id: 0 +DEAL:3d::center: -0.846194 -0.206634 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.846194 0.206634 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.831549 -0.616990 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.831549 0.616990 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.616990 -0.831549 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.616990 0.831549 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.538582 -0.119903 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.538582 0.119903 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.494648 -0.350969 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.494648 0.350969 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.350969 -0.494648 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.350969 0.494648 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.206634 -0.846194 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.206634 0.846194 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.119903 -0.538582 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.119903 0.538582 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.119903 -0.538582 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.119903 0.538582 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.206634 -0.846194 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.206634 0.846194 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.350969 -0.494648 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.350969 0.494648 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.494648 -0.350969 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.494648 0.350969 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.538582 -0.119903 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.538582 0.119903 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.616990 -0.831549 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.616990 0.831549 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.831549 -0.616990 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.831549 0.616990 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.846194 -0.206634 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: 0.846194 0.206634 -0.500000 boundary id: 5 manifold id: 1 +DEAL:3d::center: -0.846194 -0.206634 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.846194 0.206634 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.831549 -0.616990 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.831549 0.616990 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.616990 -0.831549 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.616990 0.831549 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.538582 -0.119903 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.538582 0.119903 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.494648 -0.350969 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.494648 0.350969 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.350969 -0.494648 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.350969 0.494648 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.206634 -0.846194 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.206634 0.846194 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.119903 -0.538582 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: -0.119903 0.538582 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.119903 -0.538582 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.119903 0.538582 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.206634 -0.846194 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.206634 0.846194 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.350969 -0.494648 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.350969 0.494648 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.494648 -0.350969 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.494648 0.350969 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.538582 -0.119903 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.538582 0.119903 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.616990 -0.831549 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.616990 0.831549 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.831549 -0.616990 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.831549 0.616990 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.846194 -0.206634 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d::center: 0.846194 0.206634 0.500000 boundary id: 6 manifold id: 1 +DEAL:3d:: +DEAL:3d:: +DEAL:3d::center: 0.846194 0.206634 -0.250000 manifold id: 1 +DEAL:3d::center: 0.831549 0.616990 -0.250000 manifold id: 1 +DEAL:3d::center: 0.538582 0.119903 -0.250000 manifold id: 1 +DEAL:3d::center: 0.494648 0.350969 -0.250000 manifold id: 1 +DEAL:3d::center: 0.846194 0.206634 0.250000 manifold id: 1 +DEAL:3d::center: 0.831549 0.616990 0.250000 manifold id: 1 +DEAL:3d::center: 0.538582 0.119903 0.250000 manifold id: 1 +DEAL:3d::center: 0.494648 0.350969 0.250000 manifold id: 1 +DEAL:3d::center: 0.616990 0.831549 -0.250000 manifold id: 1 +DEAL:3d::center: 0.206634 0.846194 -0.250000 manifold id: 1 +DEAL:3d::center: 0.350969 0.494648 -0.250000 manifold id: 1 +DEAL:3d::center: 0.119903 0.538582 -0.250000 manifold id: 1 +DEAL:3d::center: 0.616990 0.831549 0.250000 manifold id: 1 +DEAL:3d::center: 0.206634 0.846194 0.250000 manifold id: 1 +DEAL:3d::center: 0.350969 0.494648 0.250000 manifold id: 1 +DEAL:3d::center: 0.119903 0.538582 0.250000 manifold id: 1 +DEAL:3d::center: -0.206634 0.846194 -0.250000 manifold id: 1 +DEAL:3d::center: -0.616990 0.831549 -0.250000 manifold id: 1 +DEAL:3d::center: -0.119903 0.538582 -0.250000 manifold id: 1 +DEAL:3d::center: -0.350969 0.494648 -0.250000 manifold id: 1 +DEAL:3d::center: -0.206634 0.846194 0.250000 manifold id: 1 +DEAL:3d::center: -0.616990 0.831549 0.250000 manifold id: 1 +DEAL:3d::center: -0.119903 0.538582 0.250000 manifold id: 1 +DEAL:3d::center: -0.350969 0.494648 0.250000 manifold id: 1 +DEAL:3d::center: -0.831549 0.616990 -0.250000 manifold id: 1 +DEAL:3d::center: -0.846194 0.206634 -0.250000 manifold id: 1 +DEAL:3d::center: -0.494648 0.350969 -0.250000 manifold id: 1 +DEAL:3d::center: -0.538582 0.119903 -0.250000 manifold id: 1 +DEAL:3d::center: -0.831549 0.616990 0.250000 manifold id: 1 +DEAL:3d::center: -0.846194 0.206634 0.250000 manifold id: 1 +DEAL:3d::center: -0.494648 0.350969 0.250000 manifold id: 1 +DEAL:3d::center: -0.538582 0.119903 0.250000 manifold id: 1 +DEAL:3d::center: -0.846194 -0.206634 -0.250000 manifold id: 1 +DEAL:3d::center: -0.831549 -0.616990 -0.250000 manifold id: 1 +DEAL:3d::center: -0.538582 -0.119903 -0.250000 manifold id: 1 +DEAL:3d::center: -0.494648 -0.350969 -0.250000 manifold id: 1 +DEAL:3d::center: -0.846194 -0.206634 0.250000 manifold id: 1 +DEAL:3d::center: -0.831549 -0.616990 0.250000 manifold id: 1 +DEAL:3d::center: -0.538582 -0.119903 0.250000 manifold id: 1 +DEAL:3d::center: -0.494648 -0.350969 0.250000 manifold id: 1 +DEAL:3d::center: -0.616990 -0.831549 -0.250000 manifold id: 1 +DEAL:3d::center: -0.206634 -0.846194 -0.250000 manifold id: 1 +DEAL:3d::center: -0.350969 -0.494648 -0.250000 manifold id: 1 +DEAL:3d::center: -0.119903 -0.538582 -0.250000 manifold id: 1 +DEAL:3d::center: -0.616990 -0.831549 0.250000 manifold id: 1 +DEAL:3d::center: -0.206634 -0.846194 0.250000 manifold id: 1 +DEAL:3d::center: -0.350969 -0.494648 0.250000 manifold id: 1 +DEAL:3d::center: -0.119903 -0.538582 0.250000 manifold id: 1 +DEAL:3d::center: 0.206634 -0.846194 -0.250000 manifold id: 1 +DEAL:3d::center: 0.616990 -0.831549 -0.250000 manifold id: 1 +DEAL:3d::center: 0.119903 -0.538582 -0.250000 manifold id: 1 +DEAL:3d::center: 0.350969 -0.494648 -0.250000 manifold id: 1 +DEAL:3d::center: 0.206634 -0.846194 0.250000 manifold id: 1 +DEAL:3d::center: 0.616990 -0.831549 0.250000 manifold id: 1 +DEAL:3d::center: 0.119903 -0.538582 0.250000 manifold id: 1 +DEAL:3d::center: 0.350969 -0.494648 0.250000 manifold id: 1 +DEAL:3d::center: 0.831549 -0.616990 -0.250000 manifold id: 1 +DEAL:3d::center: 0.846194 -0.206634 -0.250000 manifold id: 1 +DEAL:3d::center: 0.494648 -0.350969 -0.250000 manifold id: 1 +DEAL:3d::center: 0.538582 -0.119903 -0.250000 manifold id: 1 +DEAL:3d::center: 0.831549 -0.616990 0.250000 manifold id: 1 +DEAL:3d::center: 0.846194 -0.206634 0.250000 manifold id: 1 +DEAL:3d::center: 0.494648 -0.350969 0.250000 manifold id: 1 +DEAL:3d::center: 0.538582 -0.119903 0.250000 manifold id: 1 From 9296119dcb0888f4a9bed2f3e72b08a3fec3edca Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Fri, 15 Feb 2019 09:42:02 -0700 Subject: [PATCH 134/507] [CI]: mark main status in github as failed --- Jenkinsfile | 52 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index e6f70559f4e0..c2b78f390a13 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -40,6 +40,12 @@ 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: @@ -76,15 +82,21 @@ pipeline image 'tjhei/candi:v9.0.1-r4' } } + post { - always { - sh "cp /home/dealii/build/Testing/*/*.xml $WORKSPACE/serial.xml || true" - xunit tools: [CTest(pattern: '*.xml')] - } - cleanup { - cleanWs() - } - } + always { + sh "cp /home/dealii/build/Testing/*/*.xml $WORKSPACE/serial.xml || true" + xunit tools: [CTest(pattern: '*.xml')] + } + + cleanup { + cleanWs() + } + + failure { + githubNotify context: 'CI', description: 'serial build failed', status: 'FAILURE' + } + } steps { @@ -93,7 +105,7 @@ pipeline sh "echo \"building on node ${env.NODE_NAME}\"" sh '''#!/bin/bash export NP=`grep -c ^processor /proc/cpuinfo` - export TEST_TIME_LIMIT=1200 + export TEST_TIME_LIMIT=1200 echo $NP mkdir -p /home/dealii/build cd /home/dealii/build @@ -121,15 +133,21 @@ pipeline image 'tjhei/candi:v9.0.1-r4' } } + post { - always { - sh "cp /home/dealii/build/Testing/*/*.xml $WORKSPACE/mpi.xml || true" - xunit tools: [CTest(pattern: '*.xml')] - } - cleanup { - cleanWs() - } - } + always { + sh "cp /home/dealii/build/Testing/*/*.xml $WORKSPACE/mpi.xml || true" + xunit tools: [CTest(pattern: '*.xml')] + } + + cleanup { + cleanWs() + } + + failure { + githubNotify context: 'CI', description: 'mpi build failed', status: 'FAILURE' + } + } steps { From 2489cfc0e7f32f863709f4c63ea32b9570f0e5f7 Mon Sep 17 00:00:00 2001 From: Logan Harbour Date: Tue, 19 Feb 2019 12:20:08 -0600 Subject: [PATCH 135/507] Fix doxygen docstring for DoFInfo indices --- include/deal.II/meshworker/dof_info.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/deal.II/meshworker/dof_info.h b/include/deal.II/meshworker/dof_info.h index 34a54fe076ae..1b3bf0825a27 100644 --- a/include/deal.II/meshworker/dof_info.h +++ b/include/deal.II/meshworker/dof_info.h @@ -96,7 +96,7 @@ namespace MeshWorker */ unsigned int sub_number; - /* + /** * The DoF indices of the * current cell */ From f81049e0e89c85b1ba1b19f1b1de6e6a4a88ecb5 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 19 Feb 2019 19:21:50 +0100 Subject: [PATCH 136/507] Remove redundant switch in MatrixFree::TaskInfo --- source/matrix_free/task_info.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/source/matrix_free/task_info.cc b/source/matrix_free/task_info.cc index 1fd323d2cfa6..d60db786c86b 100644 --- a/source/matrix_free/task_info.cc +++ b/source/matrix_free/task_info.cc @@ -363,10 +363,7 @@ namespace internal worker[j]->set_ref_count(2); blocked_worker[j - 1]->dummy = new (worker[j]->allocate_child()) tbb::empty_task; - if (j > 1) - tbb::task::spawn(*blocked_worker[j - 1]); - else - tbb::task::spawn(*blocked_worker[j - 1]); + tbb::task::spawn(*blocked_worker[j - 1]); } else { From a1ba1042970bfbb815774dc4866bb3e6c6a5abff Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 19 Feb 2019 19:26:55 +0100 Subject: [PATCH 137/507] Provide step-61 with the usual exception catching harness --- examples/step-61/step-61.cc | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/examples/step-61/step-61.cc b/examples/step-61/step-61.cc index 13866adf300f..d62b125a7b8c 100644 --- a/examples/step-61/step-61.cc +++ b/examples/step-61/step-61.cc @@ -912,9 +912,36 @@ void WGDarcyEquation::run() // This is the main function. We can change the dimension here to run in 3d. int main() { - deallog.depth_console(2); - WGDarcyEquation<2> WGDarcyEquationTest; - WGDarcyEquationTest.run(); + try + { + deallog.depth_console(2); + WGDarcyEquation<2> WGDarcyEquationTest; + WGDarcyEquationTest.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; + } + catch (...) + { + std::cerr << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + throw; + } return 0; } From 531bd4307253266c0d3772c4eab6e0c76b4053fa Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 19 Feb 2019 18:58:32 +0100 Subject: [PATCH 138/507] More HDF5 checks --- source/base/hdf5.cc | 73 ++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/source/base/hdf5.cc b/source/base/hdf5.cc index b8c958679012..9e061c766432 100644 --- a/source/base/hdf5.cc +++ b/source/base/hdf5.cc @@ -68,8 +68,10 @@ namespace HDF5 else if (std::is_same>::value) { t_type = std::shared_ptr(new hid_t, [](hid_t *pointer) { - // Relase the HDF5 resource - H5Tclose(*pointer); + // Release the HDF5 resource + const herr_t ret = H5Tclose(*pointer); + Assert(ret >= 0, ExcInternalError()); + (void)ret; delete pointer; }); *t_type = H5Tcreate(H5T_COMPOUND, sizeof(std::complex)); @@ -77,15 +79,20 @@ namespace HDF5 // format used for the std::complex type be binary-compatible with // the C99 type, i.e. an array T[2] with consecutive real [0] and // imaginary [1] parts. - H5Tinsert(*t_type, "r", 0, H5T_NATIVE_FLOAT); - H5Tinsert(*t_type, "i", sizeof(float), H5T_NATIVE_FLOAT); + herr_t ret = H5Tinsert(*t_type, "r", 0, H5T_NATIVE_FLOAT); + Assert(ret >= 0, ExcInternalError()); + ret = H5Tinsert(*t_type, "i", sizeof(float), H5T_NATIVE_FLOAT); + Assert(ret >= 0, ExcInternalError()); + (void)ret; return t_type; } else if (std::is_same>::value) { t_type = std::shared_ptr(new hid_t, [](hid_t *pointer) { - // Relase the HDF5 resource - H5Tclose(*pointer); + // Release the HDF5 resource + const herr_t ret = H5Tclose(*pointer); + Assert(ret >= 0, ExcInternalError()); + (void)ret; delete pointer; }); *t_type = H5Tcreate(H5T_COMPOUND, sizeof(std::complex)); @@ -93,8 +100,11 @@ namespace HDF5 // format used for the std::complex type be binary-compatible with // the C99 type, i.e. an array T[2] with consecutive real [0] and // imaginary [1] parts. - H5Tinsert(*t_type, "r", 0, H5T_NATIVE_DOUBLE); - H5Tinsert(*t_type, "i", sizeof(double), H5T_NATIVE_DOUBLE); + herr_t ret = H5Tinsert(*t_type, "r", 0, H5T_NATIVE_DOUBLE); + Assert(ret >= 0, ExcInternalError()); + ret = H5Tinsert(*t_type, "i", sizeof(double), H5T_NATIVE_DOUBLE); + Assert(ret >= 0, ExcInternalError()); + (void)ret; return t_type; } @@ -434,7 +444,7 @@ namespace HDF5 // https://support.hdfgroup.org/ftp/HDF5/examples/misc-examples/vlstratt.c // // In the case of a variable length string the user does not have to reserve - // memory for string_out. The call HAread will reserve the memory and the + // memory for string_out. H5Aread will reserve the memory and the // user has to free the memory. // // Todo: @@ -466,8 +476,11 @@ namespace HDF5 // The memory of the variable length string has to be freed. // H5Dvlen_reclaim could be also used free(string_out); - H5Tclose(type); - H5Aclose(attr); + ret = H5Tclose(type); + Assert(ret >= 0, ExcInternalError()); + + ret = H5Aclose(attr); + Assert(ret >= 0, ExcInternalError()); (void)ret; return string_value; @@ -588,13 +601,17 @@ namespace HDF5 , global_no_collective_cause(H5D_MPIO_SET_INDEPENDENT) { hdf5_reference = std::shared_ptr(new hid_t, [](hid_t *pointer) { - // Relase the HDF5 resource - H5Dclose(*pointer); + // Release the HDF5 resource + const herr_t ret = H5Dclose(*pointer); + Assert(ret >= 0, ExcInternalError()); + (void)ret; delete pointer; }); dataspace = std::shared_ptr(new hid_t, [](hid_t *pointer) { - // Relase the HDF5 resource - H5Sclose(*pointer); + // Release the HDF5 resource + const herr_t ret = H5Sclose(*pointer); + Assert(ret >= 0, ExcInternalError()); + (void)ret; delete pointer; }); @@ -639,13 +656,17 @@ namespace HDF5 , global_no_collective_cause(H5D_MPIO_SET_INDEPENDENT) { hdf5_reference = std::shared_ptr(new hid_t, [](hid_t *pointer) { - // Relase the HDF5 resource - H5Dclose(*pointer); + // Release the HDF5 resource + const herr_t ret = H5Dclose(*pointer); + Assert(ret >= 0, ExcInternalError()); + (void)ret; delete pointer; }); dataspace = std::shared_ptr(new hid_t, [](hid_t *pointer) { - // Relase the HDF5 resource - H5Sclose(*pointer); + // Release the HDF5 resource + const herr_t ret = H5Sclose(*pointer); + Assert(ret >= 0, ExcInternalError()); + (void)ret; delete pointer; }); @@ -1273,8 +1294,10 @@ namespace HDF5 : HDF5Object(name, mpi) { hdf5_reference = std::shared_ptr(new hid_t, [](hid_t *pointer) { - // Relase the HDF5 resource - H5Gclose(*pointer); + // Release the HDF5 resource + const herr_t ret = H5Gclose(*pointer); + Assert(ret >= 0, ExcInternalError()); + (void)ret; delete pointer; }); switch (mode) @@ -1374,8 +1397,10 @@ namespace HDF5 : Group(name, mpi) { hdf5_reference = std::shared_ptr(new hid_t, [](hid_t *pointer) { - // Relase the HDF5 resource - H5Fclose(*pointer); + // Release the HDF5 resource + const herr_t err = H5Fclose(*pointer); + Assert(err >= 0, ExcInternalError()); + (void)err; delete pointer; }); @@ -1419,7 +1444,7 @@ namespace HDF5 if (mpi) { - // Relase the HDF5 resource + // Release the HDF5 resource ret = H5Pclose(plist); Assert(ret >= 0, ExcMessage("Error at H5Pclose")); } From 44cd2cedb50036b8e19fd5cd4fd85413b02cd2e7 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 19 Feb 2019 21:00:48 +0100 Subject: [PATCH 139/507] Use AssertNothrow in custom deleters --- source/base/hdf5.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/base/hdf5.cc b/source/base/hdf5.cc index 9e061c766432..d32555839966 100644 --- a/source/base/hdf5.cc +++ b/source/base/hdf5.cc @@ -70,7 +70,7 @@ namespace HDF5 t_type = std::shared_ptr(new hid_t, [](hid_t *pointer) { // Release the HDF5 resource const herr_t ret = H5Tclose(*pointer); - Assert(ret >= 0, ExcInternalError()); + AssertNothrow(ret >= 0, ExcInternalError()); (void)ret; delete pointer; }); @@ -91,7 +91,7 @@ namespace HDF5 t_type = std::shared_ptr(new hid_t, [](hid_t *pointer) { // Release the HDF5 resource const herr_t ret = H5Tclose(*pointer); - Assert(ret >= 0, ExcInternalError()); + AssertNothrow(ret >= 0, ExcInternalError()); (void)ret; delete pointer; }); @@ -603,14 +603,14 @@ namespace HDF5 hdf5_reference = std::shared_ptr(new hid_t, [](hid_t *pointer) { // Release the HDF5 resource const herr_t ret = H5Dclose(*pointer); - Assert(ret >= 0, ExcInternalError()); + AssertNothrow(ret >= 0, ExcInternalError()); (void)ret; delete pointer; }); dataspace = std::shared_ptr(new hid_t, [](hid_t *pointer) { // Release the HDF5 resource const herr_t ret = H5Sclose(*pointer); - Assert(ret >= 0, ExcInternalError()); + AssertNothrow(ret >= 0, ExcInternalError()); (void)ret; delete pointer; }); @@ -658,14 +658,14 @@ namespace HDF5 hdf5_reference = std::shared_ptr(new hid_t, [](hid_t *pointer) { // Release the HDF5 resource const herr_t ret = H5Dclose(*pointer); - Assert(ret >= 0, ExcInternalError()); + AssertNothrow(ret >= 0, ExcInternalError()); (void)ret; delete pointer; }); dataspace = std::shared_ptr(new hid_t, [](hid_t *pointer) { // Release the HDF5 resource const herr_t ret = H5Sclose(*pointer); - Assert(ret >= 0, ExcInternalError()); + AssertNothrow(ret >= 0, ExcInternalError()); (void)ret; delete pointer; }); @@ -1296,7 +1296,7 @@ namespace HDF5 hdf5_reference = std::shared_ptr(new hid_t, [](hid_t *pointer) { // Release the HDF5 resource const herr_t ret = H5Gclose(*pointer); - Assert(ret >= 0, ExcInternalError()); + AssertNothrow(ret >= 0, ExcInternalError()); (void)ret; delete pointer; }); @@ -1399,7 +1399,7 @@ namespace HDF5 hdf5_reference = std::shared_ptr(new hid_t, [](hid_t *pointer) { // Release the HDF5 resource const herr_t err = H5Fclose(*pointer); - Assert(err >= 0, ExcInternalError()); + AssertNothrow(err >= 0, ExcInternalError()); (void)err; delete pointer; }); From f0ddc3b56bdbc002c2176ac347bf9463ec779766 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Tue, 19 Feb 2019 16:04:29 -0700 Subject: [PATCH 140/507] Update the indentation of a documentation snippet. --- include/deal.II/grid/grid_tools.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/deal.II/grid/grid_tools.h b/include/deal.II/grid/grid_tools.h index d8e9050b414e..6eb080fe7233 100644 --- a/include/deal.II/grid/grid_tools.h +++ b/include/deal.II/grid/grid_tools.h @@ -761,15 +761,16 @@ namespace GridTools * are documented in GridTools::compute_point_locations(). * The last element of the @p return_type contains the * indices of points which are not not found inside the mesh - * or lie on artificial cells. - * + * or lie on artificial cells. The @p return_type equals the + * following tuple type: * @code * std::tuple< * std::vector< * typename Triangulation::active_cell_iterator>, - * std::vector>>, - * std::vector>, - * std::vector > + * std::vector>>, + * std::vector>, + * std::vector + * > * @endcode * * For a more detailed documentation see From 87179579f0aa07beeb41b9a7fb942c600eee9b32 Mon Sep 17 00:00:00 2001 From: tcclevenger Date: Tue, 19 Feb 2019 16:48:34 -0700 Subject: [PATCH 141/507] add random renumbering --- .../changes/minor/20190219ConradClevenger | 4 + include/deal.II/dofs/dof_renumbering.h | 21 ++++ source/dofs/dof_renumbering.cc | 49 ++++++++ source/dofs/dof_renumbering.inst.in | 10 ++ tests/dofs/dof_renumbering_09.cc | 108 ++++++++++++++++++ tests/dofs/dof_renumbering_09.output | 68 +++++++++++ 6 files changed, 260 insertions(+) create mode 100644 doc/news/changes/minor/20190219ConradClevenger create mode 100644 tests/dofs/dof_renumbering_09.cc create mode 100644 tests/dofs/dof_renumbering_09.output 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/include/deal.II/dofs/dof_renumbering.h b/include/deal.II/dofs/dof_renumbering.h index d94420c66e78..445fedd07883 100644 --- a/include/deal.II/dofs/dof_renumbering.h +++ b/include/deal.II/dofs/dof_renumbering.h @@ -1133,6 +1133,16 @@ namespace DoFRenumbering void random(DoFHandlerType &dof_handler); + /** + * Renumber the degrees of freedom in a random way. It does the same thing as + * the above function, only that it does this for one single level of a + * multilevel discretization. The non-multigrid part of the DoFHandler + * is not touched. + */ + template + void + random(DoFHandlerType &dof_handler, const unsigned int level); + /** * Compute the renumbering vector needed by the random() function. See * there for more information on the computed random renumbering. @@ -1145,6 +1155,17 @@ namespace DoFRenumbering compute_random(std::vector &new_dof_indices, const DoFHandlerType & dof_handler); + /** + * Compute the renumbering vector needed by the random() function. Same + * as the above function but for a single level of a multilevel + * discretization. + */ + template + void + compute_random(std::vector &new_dof_indices, + const DoFHandlerType & dof_handler, + const unsigned int level); + /** * @} */ diff --git a/source/dofs/dof_renumbering.cc b/source/dofs/dof_renumbering.cc index bd96818aca41..adc401e0f70d 100644 --- a/source/dofs/dof_renumbering.cc +++ b/source/dofs/dof_renumbering.cc @@ -2129,6 +2129,24 @@ namespace DoFRenumbering + template + void + random(DoFHandlerType &dof_handler, const unsigned int level) + { + Assert(dof_handler.n_dofs(level) != numbers::invalid_dof_index, + ExcDoFHandlerNotInitialized()); + + std::vector renumbering( + dof_handler.locally_owned_mg_dofs(level).n_elements(), + numbers::invalid_dof_index); + + compute_random(renumbering, dof_handler, level); + + dof_handler.renumber_dofs(level, renumbering); + } + + + template void compute_random(std::vector &new_indices, @@ -2159,6 +2177,37 @@ namespace DoFRenumbering + template + void + compute_random(std::vector &new_indices, + const DoFHandlerType & dof_handler, + const unsigned int level) + { + const types::global_dof_index n_dofs = dof_handler.n_dofs(level); + Assert(new_indices.size() == n_dofs, + ExcDimensionMismatch(new_indices.size(), n_dofs)); + + for (unsigned int i = 0; i < n_dofs; ++i) + new_indices[i] = i; + + // shuffle the elements; the following is essentially std::shuffle (which + // is new in C++11) but with a boost URNG + ::boost::mt19937 random_number_generator; + for (unsigned int i = 1; i < n_dofs; ++i) + { + // get a random number between 0 and i (inclusive) + const unsigned int j = + ::boost::random::uniform_int_distribution<>(0, i)( + random_number_generator); + + // if possible, swap the elements + if (i != j) + std::swap(new_indices[i], new_indices[j]); + } + } + + + template void subdomain_wise(DoFHandlerType &dof_handler) diff --git a/source/dofs/dof_renumbering.inst.in b/source/dofs/dof_renumbering.inst.in index f7667f4b8316..7ff6480386ef 100644 --- a/source/dofs/dof_renumbering.inst.in +++ b/source/dofs/dof_renumbering.inst.in @@ -293,6 +293,16 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) std::vector &, const DoFHandler &); + template void + random>(DoFHandler &, + const unsigned int); + + template void + compute_random>( + std::vector &, + const DoFHandler &, + const unsigned int); + template void sort_selected_dofs_back>( DoFHandler &, diff --git a/tests/dofs/dof_renumbering_09.cc b/tests/dofs/dof_renumbering_09.cc new file mode 100644 index 000000000000..7d3e0dcc3b0c --- /dev/null +++ b/tests/dofs/dof_renumbering_09.cc @@ -0,0 +1,108 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2000 - 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. +// +// --------------------------------------------------------------------- + + + +// tests DoFRenumbering::random function for levels + + + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "../tests.h" + + + +template +void +print_dofs(const DoFHandler &dof, unsigned int level) +{ + std::vector v(dof.get_fe().dofs_per_cell); + for (typename DoFHandler::cell_iterator cell = dof.begin(level); + cell != dof.end(level); + ++cell) + { + deallog << "Cell " << cell << " -- "; + cell->get_mg_dof_indices(v); + for (unsigned int i = 0; i < v.size(); ++i) + deallog << v[i] << ' '; + deallog << std::endl; + } +} + + +template +void +test() +{ + Triangulation tr(Triangulation::limit_level_difference_at_vertices); + GridGenerator::hyper_cube(tr); + tr.refine_global((dim == 1 ? 2 : 1)); + + DoFHandler dof_handler(tr); + + FE_Q fe(1); + dof_handler.distribute_dofs(fe); + dof_handler.distribute_mg_dofs(fe); + + + // Print dofs before reordering + deallog << "Before reorder: " << std::endl; + for (unsigned int level = 0; level < tr.n_levels(); ++level) + { + deallog << "Level " << level << std::endl; + print_dofs(dof_handler, level); + } + + for (unsigned int level = 0; level < tr.n_levels(); ++level) + DoFRenumbering::random(dof_handler, level); + + // Print dofs after reordering + deallog << "After reorder: " << std::endl; + for (unsigned int level = 0; level < tr.n_levels(); ++level) + { + deallog << "Level " << level << std::endl; + print_dofs(dof_handler, level); + } +} + + +int +main() +{ + initlog(); + + deallog << "1D" << std::endl; + test<1>(); + deallog << std::endl << "2D" << std::endl; + test<2>(); + deallog << std::endl << "3D" << std::endl; + test<3>(); +} diff --git a/tests/dofs/dof_renumbering_09.output b/tests/dofs/dof_renumbering_09.output new file mode 100644 index 000000000000..a82919a5f96f --- /dev/null +++ b/tests/dofs/dof_renumbering_09.output @@ -0,0 +1,68 @@ + +DEAL::1D +DEAL::Before reorder: +DEAL::Level 0 +DEAL::Cell 0.0 -- 0 1 +DEAL::Level 1 +DEAL::Cell 1.0 -- 0 1 +DEAL::Cell 1.1 -- 1 2 +DEAL::Level 2 +DEAL::Cell 2.0 -- 0 1 +DEAL::Cell 2.1 -- 1 2 +DEAL::Cell 2.2 -- 2 3 +DEAL::Cell 2.3 -- 3 4 +DEAL::After reorder: +DEAL::Level 0 +DEAL::Cell 0.0 -- 0 1 +DEAL::Level 1 +DEAL::Cell 1.0 -- 2 1 +DEAL::Cell 1.1 -- 1 0 +DEAL::Level 2 +DEAL::Cell 2.0 -- 2 1 +DEAL::Cell 2.1 -- 1 0 +DEAL::Cell 2.2 -- 0 3 +DEAL::Cell 2.3 -- 3 4 +DEAL:: +DEAL::2D +DEAL::Before reorder: +DEAL::Level 0 +DEAL::Cell 0.0 -- 0 1 2 3 +DEAL::Level 1 +DEAL::Cell 1.0 -- 0 1 2 3 +DEAL::Cell 1.1 -- 1 4 3 5 +DEAL::Cell 1.2 -- 2 3 6 7 +DEAL::Cell 1.3 -- 3 5 7 8 +DEAL::After reorder: +DEAL::Level 0 +DEAL::Cell 0.0 -- 2 1 0 3 +DEAL::Level 1 +DEAL::Cell 1.0 -- 5 8 0 3 +DEAL::Cell 1.1 -- 8 4 3 2 +DEAL::Cell 1.2 -- 0 3 6 7 +DEAL::Cell 1.3 -- 3 2 7 1 +DEAL:: +DEAL::3D +DEAL::Before reorder: +DEAL::Level 0 +DEAL::Cell 0.0 -- 0 1 2 3 4 5 6 7 +DEAL::Level 1 +DEAL::Cell 1.0 -- 0 1 2 3 4 5 6 7 +DEAL::Cell 1.1 -- 1 8 3 9 5 10 7 11 +DEAL::Cell 1.2 -- 2 3 12 13 6 7 14 15 +DEAL::Cell 1.3 -- 3 9 13 16 7 11 15 17 +DEAL::Cell 1.4 -- 4 5 6 7 18 19 20 21 +DEAL::Cell 1.5 -- 5 10 7 11 19 22 21 23 +DEAL::Cell 1.6 -- 6 7 14 15 20 21 24 25 +DEAL::Cell 1.7 -- 7 11 15 17 21 23 25 26 +DEAL::After reorder: +DEAL::Level 0 +DEAL::Cell 0.0 -- 5 1 0 3 4 2 6 7 +DEAL::Level 1 +DEAL::Cell 1.0 -- 5 11 26 21 4 2 9 12 +DEAL::Cell 1.1 -- 11 15 21 6 2 3 12 8 +DEAL::Cell 1.2 -- 26 21 7 10 9 12 0 1 +DEAL::Cell 1.3 -- 21 6 10 22 12 8 1 17 +DEAL::Cell 1.4 -- 4 2 9 12 18 19 20 13 +DEAL::Cell 1.5 -- 2 3 12 8 19 16 13 23 +DEAL::Cell 1.6 -- 9 12 0 1 20 13 25 24 +DEAL::Cell 1.7 -- 12 8 1 17 13 23 24 14 From 23412344473e67a86effd12b85ec8f63d20a5e70 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Tue, 19 Feb 2019 18:12:28 -0700 Subject: [PATCH 142/507] Edits to the intro and results sections of step-61. --- examples/step-61/doc/intro.dox | 101 ++++++++++++++++++++++--------- examples/step-61/doc/results.dox | 85 ++++++++++++++++++-------- 2 files changed, 134 insertions(+), 52 deletions(-) diff --git a/examples/step-61/doc/intro.dox b/examples/step-61/doc/intro.dox index f5ca096683c0..5cc7c2120e3c 100644 --- a/examples/step-61/doc/intro.dox +++ b/examples/step-61/doc/intro.dox @@ -11,9 +11,11 @@ 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 large number of degrees of freedom (because, for +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, in general, every degree of freedom +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. @@ -25,13 +27,15 @@ 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 shape functions for these cell degrees of freedom are -discontinuous and only "live" on exactly one cell. +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 exactly one formulates -the problem that connects all of these different shape functions. The HDG does -things by reformulating second order problems in terms of a system of first +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 @@ -48,19 +52,21 @@ 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 +to approximate scalar unknowns, and discrete weak gradients to approximate classical gradients. -It was 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., 2013, 103-115. +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 expected convergence rates can +It results in a SPD linear system, and optimal convergence rates can be obtained with mesh refinement. -

WGFEM applied to the Poisson equation

+

The equation to solve

This program solves the Poisson equation using the weak Galerkin finite element method: @f{eqnarray*} @@ -74,38 +80,77 @@ using the weak Galerkin finite element method: 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. +$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)\sin(\pi y \right)$ on the unit square domain, -with homogenous Dirichelet boundary conditions and identity matrix $\mathbf{K}$. -Then we will calculate $L_2$ errors of pressure, velocity and flux. +is $p = \sin \left( \pi x\right)\sin\left(\pi y \right)$ on the unit square domain, +with homogenous Dirichelet boundary conditions and $\mathbf{K}$ the identity matrix. +Then we will calculate $L_2$ errors of pressure, velocity, and flux.

Weak Galerkin scheme

-Via integration by parts, the weak Galerkin scheme for the Poisson equation is +The Poisson equation above has a solution $p$ that needs to satisfy the weak +formulation of the problem, @f{equation*} -\mathcal{A}_h\left(p_h,q \right) = \mathcal{F} \left(q \right), +\mathcal{A}\left(p,q \right) = \mathcal{F} \left(q \right), @f} -where +for all test functions $q$, where @f{equation*} -\mathcal{A}_h\left(p_h,q\right) - := \sum_{T \in \mathcal{T}_h} - \int_T \mathbf{K} \nabla_{w,d} p_h \cdot \nabla_{w,d} q \mathrm{d}x, +\mathcal{A}\left(p,q\right) + := \int_\Omega \mathbf{K} \nabla p \cdot \nabla q \;\mathrm{d}x, @f} and @f{equation*} \mathcal{F}\left(q\right) - := \sum_{T \in \mathcal{T}_h} \int_T f \, q^\circ \mathrm{d}x - - \sum_{\gamma \in \Gamma_h^N} \int_\gamma u_N q^\partial \mathrm{d}x, + := \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_{T \in \mathcal{T}_h} + \int_T \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_{T \in \mathcal{T}_h} \int_T f \, q_h^\circ \;\mathrm{d}x + - \sum_{\gamma \in \Gamma_h^N} \int_\gamma u_N q_h^\partial \;\mathrm{d}x, @f} -$q^\circ$ is the shape function of the polynomial space in the interior, -$q^\partial$ is the shape function of the polynomial space on faces, $ \nabla_{w,d} $ means the discrete weak gradient used to approximate the classical gradient. +The key point is that here, we have replaced the gradient $\nabla p_h$ by the +discrete weak gradient + $ \nabla_{w,d} p_h $ that is defined for our peculiarly defined approximation $p_h$. We use FE_DGQ as the interior polynomial space, FE_FaceQ as the face polynomial space, and Raviart-Thomas elements for the velocity $\mathbf{u} = -{\mathbf{K}} \nabla_{w,d} p$. diff --git a/examples/step-61/doc/results.dox b/examples/step-61/doc/results.dox index b71c57abb177..6d21bb519c00 100644 --- a/examples/step-61/doc/results.dox +++ b/examples/step-61/doc/results.dox @@ -24,14 +24,27 @@ Since the mesh is a rectangular mesh and numbers of refinement are even, we have We run the code with finer meshes and get the following convergence rates of pressure, velocity and flux. -@code -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 -@endcode + + + + + + + + + + + + + + + + + + + +
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. @@ -52,14 +65,26 @@ to divide each cell interior into 4 subcells. These are the convergence rates of pressure, velocity and flux on $\mbox{WG}(Q_1,Q_1;RT_{[1]})$ -@code -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 -@endcode + + + + + + + + + + + + + + + + + + + +
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.

Test results on $WG(Q_2,Q_2;RT_{[2]})$

@@ -77,12 +102,24 @@ These are interior pressures and face pressures implemented on $WG(Q_2,Q_2;RT_{[ This is the convergence table of $L_2$ errors of pressure, velocity and flux on $\mbox{WG}(Q_2,Q_2;RT_{[2]})$ -@code -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 -@endcode + + + + + + + + + + + + + + + + + + + +
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
The convergence rates of $\mbox{WG}(Q_2,Q_2;RT_{[2]})$ are around 3. From 8dd953d299423f8f0dc292d57378b9d5a9734440 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 20 Feb 2019 11:36:56 +0100 Subject: [PATCH 143/507] Escape preprocessor commands for doxygen --- include/deal.II/base/exceptions.h | 54 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) 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 From 2db0688995602a45ae67d742e3585968735b4280 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 20 Feb 2019 11:38:19 +0100 Subject: [PATCH 144/507] Improve QR documentation --- include/deal.II/lac/qr.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/deal.II/lac/qr.h b/include/deal.II/lac/qr.h index 1898d6fb1438..7625f7935799 100644 --- a/include/deal.II/lac/qr.h +++ b/include/deal.II/lac/qr.h @@ -127,8 +127,8 @@ class BaseQR * Connect a slot to retrieve a notification when the Givens rotations * are performed. * - * The function takes @p i'th and @p j'th indices of the plane of rotation - * and a triplet of numbers @p csr (cosine, sine and radius, see + * The function takes two indices, @p i and @p j, describing the plane of + * rotation, and a triplet of numbers @p csr (cosine, sine and radius, see * Utilities::LinearAlgebra::givens_rotation()) which represents the rotation * matrix. */ @@ -169,7 +169,7 @@ class BaseQR /** * Signal used to retrieve a notification - * when Givens rotations are performed in plane @p i and @p j. + * when Givens rotations are performed in the `(i,j)`-plane. */ boost::signals2::signal virtual ~QR() = default; /** - * @copyfrom BaseQR::append_column + * @copydoc BaseQR::append_column * * @note Currently this function always returns true. */ @@ -310,7 +310,7 @@ class QR : public BaseQR private: /** - * Apply givens rotation in plane @p i @p k to @p Q and @p R so that + * Apply givens rotation in the `(i,j)`-plane to @p Q and @p R so that * R(k,k) is zeroed. * * See Chapter 5.1.9 of Golub 2013, Matrix computations. @@ -396,7 +396,7 @@ class ImplicitQR : public BaseQR * Connect a slot to implement a custom check of linear dependency * during addition of a column. * - * Here, @p u is the last column of the to-be R matrix , @p rho + * Here, @p u is the last column of the to-be R matrix, @p rho * is its diagonal and @p col_norm_sqr is the square of the $l2$ norm of the column. * The function should return true if the new column is * linearly independent. @@ -409,7 +409,7 @@ class ImplicitQR : public BaseQR private: /** - * Apply givens rotation in plane @i @p k to zero out $R(k,k)$. + * Apply givens rotation in the `(i,k)`-plane to zero out $R(k,k)$. */ void apply_givens_rotation(const unsigned int i, const unsigned int k); @@ -417,7 +417,7 @@ class ImplicitQR : public BaseQR /** * Signal used to decide if the new column is linear dependent. * - * Here, @p u is the last column of the to-be R matrix , @p rho + * Here, @p u is the last column of the to-be R matrix, @p rho * is its diagonal and @p col_norm_sqr is the square of the $l2$ norm of the column. * The function should return true if the new column is * linearly independent. From 366c7497712e5269ffc533e94da7ef6ee15541a3 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 20 Feb 2019 11:38:53 +0100 Subject: [PATCH 145/507] Fix doxygen problem in VectorTools::create_point_source_vector --- include/deal.II/numerics/vector_tools.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/deal.II/numerics/vector_tools.h b/include/deal.II/numerics/vector_tools.h index ec060968c17b..37b43f49ed51 100644 --- a/include/deal.II/numerics/vector_tools.h +++ b/include/deal.II/numerics/vector_tools.h @@ -2184,7 +2184,7 @@ namespace VectorTools * function for the problem you are solving. This is because the * Green's function $G(x,p)$ is defined by * @f{align*}{ - * L G(x,p) &= \delta(x-p)$ + * L G(x,p) &= \delta(x-p) * @f} * where $L$ is the differential operator of your problem. The discrete * version then requires computing the right hand side vector From ba314705d507e7d318bf544c969c3799f03be5b2 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 27 Aug 2018 17:14:38 +0200 Subject: [PATCH 146/507] Implement TpetraWrappers::Vector --- cmake/config/template-arguments.in | 5 + cmake/configure/configure_2_trilinos.cmake | 3 +- doc/external-libs/trilinos.html | 2 + include/deal.II/base/index_set.h | 5 + include/deal.II/base/utilities.h | 3 + include/deal.II/dofs/dof_accessor.templates.h | 27 + .../fe/fe_tools_extrapolate.templates.h | 15 + .../fe/fe_tools_interpolate.templates.h | 16 + include/deal.II/lac/read_write_vector.h | 39 +- .../deal.II/lac/read_write_vector.templates.h | 121 +++- include/deal.II/lac/trilinos_sparse_matrix.h | 1 + .../trilinos_tpetra_communication_pattern.h | 106 +++ include/deal.II/lac/trilinos_tpetra_vector.h | 406 +++++++++++ include/deal.II/lac/vector_element_access.h | 70 +- include/deal.II/multigrid/mg_transfer.h | 32 + .../deal.II/numerics/vector_tools.templates.h | 1 + source/base/index_set.cc | 66 ++ source/base/time_stepping.cc | 1 + source/base/utilities.cc | 14 + source/dofs/dof_accessor_get.cc | 1 + source/dofs/dof_accessor_set.cc | 1 + source/fe/fe_values.cc | 1 + source/fe/mapping_fe_field.cc | 1 + source/lac/CMakeLists.txt | 2 + source/lac/solver.cc | 1 + source/lac/trilinos_sparse_matrix.cc | 50 ++ .../trilinos_tpetra_communication_pattern.cc | 104 +++ source/lac/trilinos_tpetra_vector.cc | 632 ++++++++++++++++++ source/lac/vector_memory.cc | 1 + source/multigrid/mg_base.cc | 1 + source/numerics/data_out_dof_data_codim.cc | 1 + source/numerics/derivative_approximation.cc | 1 + tests/trilinos/tpetra_vector_01.cc | 225 +++++++ .../trilinos/tpetra_vector_01.mpirun=2.output | 2 + tests/trilinos/tpetra_vector_02.cc | 216 ++++++ .../trilinos/tpetra_vector_02.mpirun=2.output | 2 + tests/trilinos/tpetra_vector_03.cc | 101 +++ .../trilinos/tpetra_vector_03.mpirun=2.output | 70 ++ .../trilinos/tpetra_vector_03.mpirun=4.output | 146 ++++ 39 files changed, 2488 insertions(+), 4 deletions(-) create mode 100644 include/deal.II/lac/trilinos_tpetra_communication_pattern.h create mode 100644 include/deal.II/lac/trilinos_tpetra_vector.h create mode 100644 source/lac/trilinos_tpetra_communication_pattern.cc create mode 100644 source/lac/trilinos_tpetra_vector.cc create mode 100644 tests/trilinos/tpetra_vector_01.cc create mode 100644 tests/trilinos/tpetra_vector_01.mpirun=2.output create mode 100644 tests/trilinos/tpetra_vector_02.cc create mode 100644 tests/trilinos/tpetra_vector_02.mpirun=2.output create mode 100644 tests/trilinos/tpetra_vector_03.cc create mode 100644 tests/trilinos/tpetra_vector_03.mpirun=2.output create mode 100644 tests/trilinos/tpetra_vector_03.mpirun=4.output diff --git a/cmake/config/template-arguments.in b/cmake/config/template-arguments.in index 551fdd08d3cc..17a9f2ba9477 100644 --- a/cmake/config/template-arguments.in +++ b/cmake/config/template-arguments.in @@ -95,6 +95,7 @@ VECTOR_TYPES := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR@; @DEAL_II_EXPAND_TRILINOS_MPI_BLOCKVECTOR@; @@ -120,6 +121,7 @@ REAL_VECTOR_TYPES := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR_REAL@; @DEAL_II_EXPAND_TRILINOS_MPI_BLOCKVECTOR@; @@ -138,6 +140,7 @@ REAL_NONBLOCK_VECTORS := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR_REAL@; } @@ -145,6 +148,7 @@ 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@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR@; @DEAL_II_EXPAND_PETSC_MPI_BLOCKVECTOR@ } @@ -163,6 +167,7 @@ VECTORS_WITH_MATRIX := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR@; } diff --git a/cmake/configure/configure_2_trilinos.cmake b/cmake/configure/configure_2_trilinos.cmake index c53f105c0995..abe66905d82c 100644 --- a/cmake/configure/configure_2_trilinos.cmake +++ b/cmake/configure/configure_2_trilinos.cmake @@ -42,7 +42,7 @@ MACRO(FEATURE_TRILINOS_FIND_EXTERNAL var) ) FOREACH(_module - Amesos Epetra Ifpack AztecOO Teuchos ML MueLu + Amesos Epetra Ifpack AztecOO Teuchos Tpetra ML MueLu ) ITEM_MATCHES(_module_found ${_module} ${Trilinos_PACKAGE_LIST}) IF(_module_found) @@ -227,6 +227,7 @@ 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") + SET(DEAL_II_EXPAND_TPETRA_VECTOR "LinearAlgebra::TpetraWrappers::Vector") ENDIF() IF(${DEAL_II_TRILINOS_WITH_SACADO}) # Note: Only CMake 3.0 and greater support line continuation with the "\" character diff --git a/doc/external-libs/trilinos.html b/doc/external-libs/trilinos.html index 9579c9a62a0a..d950f55b11c0 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,
  • Zoltan (optional). @@ -92,6 +93,7 @@
    Installing Trilinos
    -DTrilinos_ENABLE_MueLu=ON \ -DTrilinos_ENABLE_ML=ON \ -DTrilinos_ENABLE_ROL=ON \ + -DTrilinos_ENABLE_Tpetra=ON \ -DTrilinos_ENABLE_Zoltan=ON \ -DTrilinos_VERBOSE_CONFIGURE=OFF \ -DTPL_ENABLE_MPI=ON \ diff --git a/include/deal.II/base/index_set.h b/include/deal.II/base/index_set.h index fec38b883f22..2e21fab64498 100644 --- a/include/deal.II/base/index_set.h +++ b/include/deal.II/base/index_set.h @@ -31,6 +31,7 @@ #ifdef DEAL_II_WITH_TRILINOS # include +# include #endif #if defined(DEAL_II_WITH_MPI) || defined(DEAL_II_WITH_PETSC) @@ -446,6 +447,10 @@ class IndexSet Epetra_Map make_trilinos_map(const MPI_Comm &communicator = MPI_COMM_WORLD, const bool overlapping = false) const; + + Tpetra::Map<> + make_tpetra_map(const MPI_Comm &communicator = MPI_COMM_WORLD, + const bool overlapping = false) const; #endif diff --git a/include/deal.II/base/utilities.h b/include/deal.II/base/utilities.h index f49c3021321b..71d05faf24ea 100644 --- a/include/deal.II/base/utilities.h +++ b/include/deal.II/base/utilities.h @@ -888,6 +888,9 @@ namespace Utilities const Epetra_Comm & comm_self(); + const Teuchos::RCP> & + tpetra_comm_self(); + /** * Given a communicator, duplicate it. If the given communicator is * serial, that means to just return a copy of itself. On the other hand, diff --git a/include/deal.II/dofs/dof_accessor.templates.h b/include/deal.II/dofs/dof_accessor.templates.h index a7c898c9537f..73b77c07a57d 100644 --- a/include/deal.II/dofs/dof_accessor.templates.h +++ b/include/deal.II/dofs/dof_accessor.templates.h @@ -1534,6 +1534,33 @@ namespace internal + template + static void + extract_subvector_to(const LinearAlgebra::TpetraWrappers::Vector &values, + const types::global_dof_index *cache_begin, + const types::global_dof_index *cache_end, + ForwardIterator local_values_begin) + { + std::vector sorted_indices_pos = + sort_indices(cache_begin, cache_end); + const unsigned int cache_size = cache_end - cache_begin; + std::vector cache_indices(cache_size); + for (unsigned int i = 0; i < cache_size; ++i) + cache_indices[i] = *(cache_begin + sorted_indices_pos[i]); + + IndexSet index_set(cache_indices.back() + 1); + index_set.add_indices(cache_indices.begin(), cache_indices.end()); + index_set.compress(); + LinearAlgebra::ReadWriteVector read_write_vector(index_set); + read_write_vector.import(values, VectorOperation::insert); + + // Copy the elements from read_write_vector and reorder them. + for (unsigned int i = 0; i < cache_size; ++i, ++local_values_begin) + *local_values_begin = read_write_vector[sorted_indices_pos[i]]; + } + + + template static void extract_subvector_to(const LinearAlgebra::EpetraWrappers::Vector &values, diff --git a/include/deal.II/fe/fe_tools_extrapolate.templates.h b/include/deal.II/fe/fe_tools_extrapolate.templates.h index f2acc692d7ae..850a4c6216ca 100644 --- a/include/deal.II/fe/fe_tools_extrapolate.templates.h +++ b/include/deal.II/fe/fe_tools_extrapolate.templates.h @@ -1581,6 +1581,21 @@ namespace FETools # ifdef DEAL_II_WITH_MPI + template + void + reinit_distributed(const DoFHandler & dh, + LinearAlgebra::TpetraWrappers::Vector &vector) + { + const parallel::distributed::Triangulation *parallel_tria = + dynamic_cast< + const parallel::distributed::Triangulation *>( + &dh.get_triangulation()); + Assert(parallel_tria != nullptr, ExcNotImplemented()); + + const IndexSet &locally_owned_dofs = dh.locally_owned_dofs(); + vector.reinit(locally_owned_dofs, parallel_tria->get_communicator()); + } + template void reinit_distributed(const DoFHandler & dh, diff --git a/include/deal.II/fe/fe_tools_interpolate.templates.h b/include/deal.II/fe/fe_tools_interpolate.templates.h index 82460f14bb24..e2e9b417fe02 100644 --- a/include/deal.II/fe/fe_tools_interpolate.templates.h +++ b/include/deal.II/fe/fe_tools_interpolate.templates.h @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -511,6 +512,21 @@ namespace FETools { AssertThrow(false, ExcNotImplemented()); } + + template + void + back_interpolate( + const DoFHandler &, + const AffineConstraints< + typename LinearAlgebra::TpetraWrappers::Vector::value_type> &, + const LinearAlgebra::TpetraWrappers::Vector &, + const DoFHandler &, + const AffineConstraints< + typename LinearAlgebra::TpetraWrappers::Vector::value_type> &, + LinearAlgebra::TpetraWrappers::Vector &) + { + AssertThrow(false, ExcNotImplemented()); + } #endif diff --git a/include/deal.II/lac/read_write_vector.h b/include/deal.II/lac/read_write_vector.h index 9e67f981787d..70d89ade7a1c 100644 --- a/include/deal.II/lac/read_write_vector.h +++ b/include/deal.II/lac/read_write_vector.h @@ -35,6 +35,7 @@ #ifdef DEAL_II_WITH_TRILINOS # include # include +# include # include @@ -334,6 +335,21 @@ namespace LinearAlgebra std::shared_ptr()); # ifdef DEAL_II_WITH_MPI + /** + * Imports all the elements present in the vector's IndexSet from the input + * vector @p tpetra_vec. VectorOperation::values @p operation is used to + * decide if the elements in @p V should be added to the current vector or + * replace the current elements. The last parameter can be used if the same + * communication pattern is used multiple times. This can be used to improve + * performance. + */ + void + import(const TpetraWrappers::Vector &tpetra_vec, + VectorOperation::values operation, + const std::shared_ptr + &communication_pattern = + std::shared_ptr()); + /** * Imports all the elements present in the vector's IndexSet from the input * vector @p epetra_vec. VectorOperation::values @p operation is used to @@ -593,6 +609,19 @@ namespace LinearAlgebra protected: #ifdef DEAL_II_WITH_TRILINOS + /** + * Import all the elements present in the vector's IndexSet from the input + * vector @p tpetra_vector. This is an helper function and it should not be + * used directly. + */ + void + import(const Tpetra::Vector<> &tpetra_vector, + const IndexSet & locally_owned_elements, + VectorOperation::values operation, + const MPI_Comm & mpi_comm, + const std::shared_ptr + &communication_pattern); + /** * Import all the elements present in the vector's IndexSet from the input * vector @p multivector. This is an helper function and it should not be @@ -627,7 +656,15 @@ namespace LinearAlgebra #if defined(DEAL_II_WITH_TRILINOS) && defined(DEAL_II_WITH_MPI) /** - * Return a EpetraWrappers::Communication pattern and store it for future + * Return a TpetraWrappers::CommunicationPattern and store it for future + * use. + */ + TpetraWrappers::CommunicationPattern + create_tpetra_comm_pattern(const IndexSet &source_index_set, + const MPI_Comm &mpi_comm); + + /** + * Return a EpetraWrappers::CommunicationPattern and store it for future * use. */ EpetraWrappers::CommunicationPattern diff --git a/include/deal.II/lac/read_write_vector.templates.h b/include/deal.II/lac/read_write_vector.templates.h index 9a8022648168..b4437cfd3fbf 100644 --- a/include/deal.II/lac/read_write_vector.templates.h +++ b/include/deal.II/lac/read_write_vector.templates.h @@ -34,7 +34,6 @@ #ifdef DEAL_II_WITH_TRILINOS # include -# include # include # include @@ -507,6 +506,93 @@ namespace LinearAlgebra #if defined(DEAL_II_WITH_TRILINOS) && defined(DEAL_II_WITH_MPI) + template + void + ReadWriteVector::import( + const Tpetra::Vector<> &vector, + const IndexSet & source_elements, + VectorOperation::values operation, + const MPI_Comm & mpi_comm, + const std::shared_ptr + &communication_pattern) + { + std::shared_ptr + tpetra_comm_pattern; + + // If no communication pattern is given, create one. Otherwise, use the one + // given. + if (communication_pattern == nullptr) + { + // The first time import is called, we create a communication pattern. + // Check if the communication pattern already exists and if it can be + // reused. + if ((source_elements.size() == source_stored_elements.size()) && + (source_elements == source_stored_elements)) + { + tpetra_comm_pattern = std::dynamic_pointer_cast< + const TpetraWrappers::CommunicationPattern>(comm_pattern); + if (tpetra_comm_pattern == nullptr) + tpetra_comm_pattern = + std::make_shared( + create_tpetra_comm_pattern(source_elements, mpi_comm)); + } + else + tpetra_comm_pattern = + std::make_shared( + create_tpetra_comm_pattern(source_elements, mpi_comm)); + } + else + { + tpetra_comm_pattern = + std::dynamic_pointer_cast( + communication_pattern); + AssertThrow(tpetra_comm_pattern != nullptr, + ExcMessage( + std::string("The communication pattern is not of type ") + + "LinearAlgebra::TpetraWrappers::CommunicationPattern.")); + } + + Tpetra::Export<> tpetra_export(tpetra_comm_pattern->get_tpetra_export()); + + Tpetra::Vector<> target_vector(tpetra_export.getSourceMap()); + target_vector.doImport(vector, tpetra_export, Tpetra::REPLACE); + + const auto *new_values = target_vector.getData().get(); + const auto size = target_vector.getLocalLength(); + + using size_type = std::decay::type; + + Assert(size == 0 || values != nullptr, ExcInternalError("Export failed.")); + AssertDimension(size, stored_elements.n_elements()); + + if (operation == VectorOperation::insert) + { + for (size_type i = 0; i < size; ++i) + values[i] = new_values[i]; + } + else if (operation == VectorOperation::add) + { + for (size_type i = 0; i < size; ++i) + values[i] += new_values[i]; + } + else if (operation == VectorOperation::min) + { + for (size_type i = 0; i < size; ++i) + if (std::real(new_values[i]) - std::real(values[i]) < 0.0) + values[i] = new_values[i]; + } + else if (operation == VectorOperation::max) + { + for (size_type i = 0; i < size; ++i) + if (std::real(new_values[i]) - std::real(values[i]) > 0.0) + values[i] = new_values[i]; + } + else + AssertThrow(false, ExcNotImplemented()); + } + + + template void ReadWriteVector::import( @@ -652,6 +738,23 @@ namespace LinearAlgebra + template + void + ReadWriteVector::import( + const LinearAlgebra::TpetraWrappers::Vector &trilinos_vec, + VectorOperation::values operation, + const std::shared_ptr + &communication_pattern) + { + import(trilinos_vec.trilinos_vector(), + trilinos_vec.locally_owned_elements(), + operation, + trilinos_vec.get_mpi_communicator(), + communication_pattern); + } + + + template void ReadWriteVector::import( @@ -793,6 +896,22 @@ namespace LinearAlgebra #if defined(DEAL_II_WITH_TRILINOS) && defined(DEAL_II_WITH_MPI) + template + TpetraWrappers::CommunicationPattern + ReadWriteVector::create_tpetra_comm_pattern( + const IndexSet &source_index_set, + const MPI_Comm &mpi_comm) + { + source_stored_elements = source_index_set; + TpetraWrappers::CommunicationPattern epetra_comm_pattern( + source_stored_elements, stored_elements, mpi_comm); + comm_pattern = std::make_shared( + source_stored_elements, stored_elements, mpi_comm); + + return epetra_comm_pattern; + } + + template EpetraWrappers::CommunicationPattern ReadWriteVector::create_epetra_comm_pattern( diff --git a/include/deal.II/lac/trilinos_sparse_matrix.h b/include/deal.II/lac/trilinos_sparse_matrix.h index 25478951f673..006dc3171219 100644 --- a/include/deal.II/lac/trilinos_sparse_matrix.h +++ b/include/deal.II/lac/trilinos_sparse_matrix.h @@ -27,6 +27,7 @@ # include # include # include +# include # include # include # include diff --git a/include/deal.II/lac/trilinos_tpetra_communication_pattern.h b/include/deal.II/lac/trilinos_tpetra_communication_pattern.h new file mode 100644 index 000000000000..8dc7cf787472 --- /dev/null +++ b/include/deal.II/lac/trilinos_tpetra_communication_pattern.h @@ -0,0 +1,106 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2015 - 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_trilinos_tpetra_communication_pattern_h +#define dealii_trilinos_tpetra_communication_pattern_h + + +#include + +#ifdef DEAL_II_WITH_TRILINOS + +# ifdef DEAL_II_WITH_MPI + +# include + +# include + +# include + +DEAL_II_NAMESPACE_OPEN + +namespace LinearAlgebra +{ + namespace TpetraWrappers + { + /** + * This class implements a wrapper to Tpetra::Import and Tpetra::Export. + */ + class CommunicationPattern : public CommunicationPatternBase + { + public: + /** + * Reinitialize the communication pattern. The first argument @p + * vector_space_vector_index_set is the index set associated to a + * VectorSpaceVector object. The second argument @p + * read_write_vector_index_set is the index set associated to a + * ReadWriteVector object. + */ + CommunicationPattern(const IndexSet &vector_space_vector_index_set, + const IndexSet &read_write_vector_index_set, + const MPI_Comm &communicator); + + /** + * Reinitialize the object. + */ + virtual void + reinit(const IndexSet &vector_space_vector_index_set, + const IndexSet &read_write_vector_index_set, + const MPI_Comm &communicator) override; + + /** + * Return the underlying MPI communicator. + */ + virtual const MPI_Comm & + get_mpi_communicator() const override; + + /** + * Return the underlying Tpetra::Import object. + */ + const Tpetra::Import<> & + get_tpetra_import() const; + + /** + * Return the underlying Tpetra::Export object. + */ + const Tpetra::Export<> & + get_tpetra_export() const; + + private: + /** + * Shared pointer to the MPI communicator used. + */ + std::shared_ptr comm; + + /** + * Shared pointer to the Tpetra::Import object used. + */ + std::unique_ptr> tpetra_import; + + /** + * Shared pointer to the Tpetra::Export object used. + */ + std::unique_ptr> tpetra_export; + }; + } // end of namespace TpetraWrappers +} // end of namespace LinearAlgebra + +DEAL_II_NAMESPACE_CLOSE + +# endif + +#endif + +#endif diff --git a/include/deal.II/lac/trilinos_tpetra_vector.h b/include/deal.II/lac/trilinos_tpetra_vector.h new file mode 100644 index 000000000000..df0b0c99c581 --- /dev/null +++ b/include/deal.II/lac/trilinos_tpetra_vector.h @@ -0,0 +1,406 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2015 - 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_trilinos_tpetra_vector_h +#define dealii_trilinos_tpetra_vector_h + + +#include + +#if defined(DEAL_II_WITH_TRILINOS) && defined(DEAL_II_WITH_MPI) + +# include +# include + +# include +# include +# include +# include + +# include +# include +# include +# include +# include +# include + +# include + +DEAL_II_NAMESPACE_OPEN + +namespace LinearAlgebra +{ + // Forward declaration + template + class ReadWriteVector; + + namespace TpetraWrappers + { + /** + * This class implements a wrapper to the Trilinos distributed vector + * class Tpetra::Vector. This class is derived from the + * LinearAlgebra::VectorSpaceVector class. Note however that Tpetra only + * works with Number = double. + * + * @ingroup TrilinosWrappers + * @ingroup Vectors + * @author Daniel Arndt, 2018 + */ + class Vector : public VectorSpaceVector, public Subscriptor + { + public: + /** + * Constructor. Create a vector of dimension zero. + */ + Vector(); + + /** + * Copy constructor. Sets the dimension and the partitioning to that of + * the given vector and copies all elements. + */ + Vector(const Vector &V); + + /** + * This constructor takes an IndexSet that defines how to distribute the + * individual components among the MPI processors. Since it also + * includes information about the size of the vector, this is all we + * need to generate a %parallel vector. + */ + explicit Vector(const IndexSet ¶llel_partitioner, + const MPI_Comm &communicator); + + /** + * Reinit functionality. This function destroys the old vector content + * and generates a new one based on the input partitioning. The flag + * omit_zeroing_entries determines whether the vector should be + * filled with zero (false) or left untouched (true). + */ + void + reinit(const IndexSet ¶llel_partitioner, + const MPI_Comm &communicator, + const bool omit_zeroing_entries = false); + + /** + * Change the dimension to that of the vector V. The elements of V are not + * copied. + */ + virtual void + reinit(const VectorSpaceVector &V, + const bool omit_zeroing_entries = false) override; + + /** + * Copy function. This function takes a Vector and copies all the + * elements. The Vector will have the same parallel distribution as @p + * V. + */ + Vector & + operator=(const Vector &V); + + /** + * Sets all elements of the vector to the scalar @p s. This operation is + * only allowed if @p s is equal to zero. + */ + virtual Vector & + operator=(const double s) override; + + /** + * Imports all the elements present in the vector's IndexSet from the + * input + * vector @p V. VectorOperation::values @p operation is used to decide if + * the elements in @p V should be added to the current vector or replace the + * current elements. The last parameter can be used if the same + * communication pattern is used multiple times. This can be used to + * improve performance. + */ + virtual void + import( + const ReadWriteVector & V, + VectorOperation::values operation, + std::shared_ptr communication_pattern = + std::shared_ptr()) override; + + /** + * Multiply the entire vector by a fixed factor. + */ + virtual Vector & + operator*=(const double factor) override; + + /** + * Divide the entire vector by a fixed factor. + */ + virtual Vector & + operator/=(const double factor) override; + + /** + * Add the vector @p V to the present one. + */ + virtual Vector & + operator+=(const VectorSpaceVector &V) override; + + /** + * Subtract the vector @p V from the present one. + */ + virtual Vector & + operator-=(const VectorSpaceVector &V) override; + + /** + * Return the scalar product of two vectors. The vectors need to have the + * same layout. + */ + virtual double + operator*(const VectorSpaceVector &V) const override; + + /** + * Add @p a to all components. Note that @p is a scalar not a vector. + */ + virtual void + add(const double a) override; + + /** + * Simple addition of a multiple of a vector, i.e. *this += + * a*V. The vectors need to have the same layout. + */ + virtual void + add(const double a, const VectorSpaceVector &V) override; + + /** + * Multiple addition of multiple of a vector, i.e. *this> += + * a*V+b*W. The vectors need to have the same layout. + */ + virtual void + add(const double a, + const VectorSpaceVector &V, + const double b, + const VectorSpaceVector &W) override; + + /** + * Scaling and simple addition of a multiple of a vector, i.e. *this + * = s*(*this)+a*V. + */ + virtual void + sadd(const double s, + const double a, + const VectorSpaceVector &V) override; + + /** + * Scale each element of this vector by the corresponding element in the + * argument. This function is mostly meant to simulate multiplication + * (and immediate re-assignment) by a diagonal scaling matrix. The + * vectors need to have the same layout. + */ + virtual void + scale(const VectorSpaceVector &scaling_factors) override; + + /** + * Assignment *this = a*V. + */ + virtual void + equ(const double a, const VectorSpaceVector &V) override; + + /** + * Return whether the vector contains only elements with value zero. + */ + virtual bool + all_zero() const override; + + /** + * Return the mean value of the element of this vector. + */ + virtual double + mean_value() const override; + + /** + * Return the l1 norm of the vector (i.e., the sum of the + * absolute values of all entries among all processors). + */ + virtual double + l1_norm() const override; + + /** + * Return the l2 norm of the vector (i.e., the square root of + * the sum of the square of all entries among all processors). + */ + virtual double + l2_norm() const override; + + /** + * Return the maximum norm of the vector (i.e., the maximum absolute value + * among all entries and among all processors). + */ + virtual double + linfty_norm() const override; + + /** + * Performs a combined operation of a vector addition and a subsequent + * inner product, returning the value of the inner product. In other + * words, the result of this function is the same as if the user called + * @code + * this->add(a, V); + * return_value = *this * W; + * @endcode + * + * The reason this function exists is that this operation involves less + * memory transfer than calling the two functions separately. This + * method only needs to load three vectors, @p this, @p V, @p W, whereas + * calling separate methods means to load the calling vector @p this + * twice. Since most vector operations are memory transfer limited, this + * reduces the time by 25\% (or 50\% if @p W equals @p this). + * + * The vectors need to have the same layout. + * + * For complex-valued vectors, the scalar product in the second step is + * implemented as + * $\left=\sum_i v_i \bar{w_i}$. + */ + virtual double + add_and_dot(const double a, + const VectorSpaceVector &V, + const VectorSpaceVector &W) override; + /** + * This function always returns false and is present only for backward + * compatibility. + */ + bool + has_ghost_elements() const; + + /** + * Return the global size of the vector, equal to the sum of the number of + * locally owned indices among all processors. + */ + virtual size_type + size() const override; + + /** + * Return the MPI communicator object in use with this object. + */ + MPI_Comm + get_mpi_communicator() const; + + /** + * Return an index set that describes which elements of this vector are + * owned by the current processor. As a consequence, the index sets + * returned on different processors if this is a distributed vector will + * form disjoint sets that add up to the complete index set. Obviously, if + * a vector is created on only one processor, then the result would + * satisfy + * @code + * vec.locally_owned_elements() == complete_index_set(vec.size()) + * @endcode + */ + virtual ::dealii::IndexSet + locally_owned_elements() const override; + + /** + * Return a const reference to the underlying Trilinos + * Tpetra::Vector class. + */ + const Tpetra::Vector<> & + trilinos_vector() const; + + /** + * Return a (modifyable) reference to the underlying Trilinos + * Tpetra::Vector class. + */ + Tpetra::Vector<> & + trilinos_vector(); + + /** + * Prints the vector to the output stream @p out. + */ + virtual void + print(std::ostream & out, + const unsigned int precision = 3, + const bool scientific = true, + const bool across = true) const override; + + /** + * Return the memory consumption of this class in bytes. + */ + virtual std::size_t + memory_consumption() const override; + + /** + * The vectors have different partitioning, i.e. they have use different + * IndexSet. + */ + DeclException0(ExcDifferentParallelPartitioning); + + /** + * Attempt to perform an operation between two incompatible vector types. + * + * @ingroup Exceptions + */ + DeclException0(ExcVectorTypeNotCompatible); + + /** + * Exception thrown by an error in Trilinos. + * + * @ingroup Exceptions + */ + DeclException1(ExcTrilinosError, + int, + << "An error with error number " << arg1 + << " occurred while calling a Trilinos function"); + + private: + /** + * Create the CommunicationPattern for the communication between the + * IndexSet @p source_index_set and the current vector based + * on the communicator @p mpi_comm. + */ + void + create_tpetra_comm_pattern(const IndexSet &source_index_set, + const MPI_Comm &mpi_comm); + + /** + * Pointer to the actual Tpetra vector object. + */ + std::unique_ptr> vector; + + /** + * IndexSet of the elements of the last imported vector. + */ + ::dealii::IndexSet source_stored_elements; + + /** + * CommunicationPattern for the communication between the + * source_stored_elements IndexSet and the current vector. + */ + std::shared_ptr + tpetra_comm_pattern; + }; + + + inline bool + Vector::has_ghost_elements() const + { + return false; + } + } // namespace TpetraWrappers +} // namespace LinearAlgebra + + +/** + * Declare dealii::LinearAlgebra::TpetraWrappers::Vector as distributed vector. + */ +template <> +struct is_serial_vector : std::false_type +{}; + +DEAL_II_NAMESPACE_CLOSE + +#endif + +#endif diff --git a/include/deal.II/lac/vector_element_access.h b/include/deal.II/lac/vector_element_access.h index 791f6894c375..b16826058885 100644 --- a/include/deal.II/lac/vector_element_access.h +++ b/include/deal.II/lac/vector_element_access.h @@ -18,6 +18,7 @@ #include +#include DEAL_II_NAMESPACE_OPEN @@ -108,7 +109,6 @@ namespace internal vector[0][trilinos_i] = value; } - template <> inline double ElementAccess::get( @@ -122,6 +122,74 @@ namespace internal return vector[0][trilinos_i]; } + + + + template <> + inline void + ElementAccess::add( + const double value, + const types::global_dof_index i, + LinearAlgebra::TpetraWrappers::Vector &V) + { + // Extract local indices in the vector. + Tpetra::Vector<> vector = V.trilinos_vector(); + TrilinosWrappers::types::int_type trilinos_i = + vector.getMap()->getLocalElement( + static_cast(i)); + + vector.sync(); + auto vector_2d = vector.getLocalView(); + auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); + // We're going to modify the data on host. + vector.modify(); + vector_1d(trilinos_i) += value; + vector.sync::device_type::memory_space>(); + } + + + + template <> + inline void + ElementAccess::set( + const double value, + const types::global_dof_index i, + LinearAlgebra::TpetraWrappers::Vector &V) + { + // Extract local indices in the vector. + Tpetra::Vector<> vector = V.trilinos_vector(); + TrilinosWrappers::types::int_type trilinos_i = + vector.getMap()->getLocalElement( + static_cast(i)); + + vector.sync(); + auto vector_2d = vector.getLocalView(); + auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); + // We're going to modify the data on host. + vector.modify(); + vector_1d(trilinos_i) = value; + vector.sync::device_type::memory_space>(); + } + + + template <> + inline double + ElementAccess::get( + const LinearAlgebra::TpetraWrappers::Vector &V, + const types::global_dof_index i) + { + // Extract local indices in the vector. + Tpetra::Vector<> vector = V.trilinos_vector(); + TrilinosWrappers::types::int_type trilinos_i = + vector.getMap()->getLocalElement( + static_cast(i)); + + vector.sync(); + auto vector_2d = vector.getLocalView(); + auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); + // We're going to modify the data on host. + return vector_1d(trilinos_i); + } #endif } // namespace internal diff --git a/include/deal.II/multigrid/mg_transfer.h b/include/deal.II/multigrid/mg_transfer.h index a88bf028846b..e4b4f3db2ac9 100644 --- a/include/deal.II/multigrid/mg_transfer.h +++ b/include/deal.II/multigrid/mg_transfer.h @@ -132,6 +132,38 @@ namespace internal }; # ifdef DEAL_II_WITH_MPI + template <> + struct MatrixSelector + { + using Sparsity = ::dealii::TrilinosWrappers::SparsityPattern; + using Matrix = ::dealii::TrilinosWrappers::SparseMatrix; + + static const bool requires_distributed_sparsity_pattern = false; + + template + static void + reinit(Matrix &matrix, + Sparsity &, + int level, + const SparsityPatternType &sp, + DoFHandlerType & dh) + { + const parallel::Triangulation + *dist_tria = dynamic_cast< + const parallel::Triangulation *>( + &(dh.get_triangulation())); + MPI_Comm communicator = + dist_tria != nullptr ? dist_tria->get_communicator() : MPI_COMM_SELF; + matrix.reinit(dh.locally_owned_mg_dofs(level + 1), + dh.locally_owned_mg_dofs(level), + sp, + communicator, + true); + } + }; + template <> struct MatrixSelector { diff --git a/include/deal.II/numerics/vector_tools.templates.h b/include/deal.II/numerics/vector_tools.templates.h index 30e5fa5f1fe5..aebdafb33768 100644 --- a/include/deal.II/numerics/vector_tools.templates.h +++ b/include/deal.II/numerics/vector_tools.templates.h @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include diff --git a/source/base/index_set.cc b/source/base/index_set.cc index 3e7f0914cf35..6fe2920ffe39 100644 --- a/source/base/index_set.cc +++ b/source/base/index_set.cc @@ -520,6 +520,72 @@ IndexSet::fill_index_vector(std::vector &indices) const #ifdef DEAL_II_WITH_TRILINOS +Tpetra::Map<> +IndexSet::make_tpetra_map(const MPI_Comm &communicator, + const bool overlapping) const +{ + compress(); + (void)communicator; + +# ifdef DEBUG + if (!overlapping) + { + const size_type n_global_elements = + Utilities::MPI::sum(n_elements(), communicator); + Assert(n_global_elements == size(), + ExcMessage("You are trying to create an Tpetra::Map object " + "that partitions elements of an index set " + "between processors. However, the union of the " + "index sets on different processors does not " + "contain all indices exactly once: the sum of " + "the number of entries the various processors " + "want to store locally is " + + Utilities::to_string(n_global_elements) + + " whereas the total size of the object to be " + "allocated is " + + Utilities::to_string(size()) + + ". In other words, there are " + "either indices that are not spoken for " + "by any processor, or there are indices that are " + "claimed by multiple processors.")); + } +# endif + + // Find out if the IndexSet is ascending and 1:1. This corresponds to a + // linear Tpetra::Map. Overlapping IndexSets are never 1:1. + const bool linear = + overlapping ? false : is_ascending_and_one_to_one(communicator); + if (linear) + return Tpetra::Map<>(size(), + n_elements(), + 0, +# ifdef DEAL_II_WITH_MPI + Teuchos::rcp(new Teuchos::MpiComm(communicator)) +# else + Teuchos::rcp(new Teuchos::Comm()) +# endif + ); + else + { + std::vector indices; + fill_index_vector(indices); + std::vector int_indices(indices.size()); + std::copy(indices.begin(), indices.end(), int_indices.begin()); + return Tpetra::Map<>(size(), + (n_elements() > 0 ? int_indices.data() : nullptr), + n_elements(), + 0, +# ifdef DEAL_II_WITH_MPI + Teuchos::rcp(new Teuchos::MpiComm(communicator)) +# else + Teuchos::rcp(new Teuchos::Comm()) +# endif + ); + } +} + + + Epetra_Map IndexSet::make_trilinos_map(const MPI_Comm &communicator, const bool overlapping) const diff --git a/source/base/time_stepping.cc b/source/base/time_stepping.cc index 9bb02320eb63..3e4d6bed678b 100644 --- a/source/base/time_stepping.cc +++ b/source/base/time_stepping.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/source/base/utilities.cc b/source/base/utilities.cc index 27b798cc124b..ff4d0d957322 100644 --- a/source/base/utilities.cc +++ b/source/base/utilities.cc @@ -979,6 +979,20 @@ namespace Utilities + const Teuchos::RCP> & + tpetra_comm_self() + { +# ifdef DEAL_II_WITH_MPI + static auto communicator = Teuchos::RCP>( + new Teuchos::MpiComm(MPI_COMM_SELF)); +# else + static auto communicator = + Teuchos::RCP>(new Teuchos::Comm()); +# endif + + return communicator; + } + const Epetra_Comm & comm_self() { diff --git a/source/dofs/dof_accessor_get.cc b/source/dofs/dof_accessor_get.cc index 4f1bdc2b0316..53b47d2238ad 100644 --- a/source/dofs/dof_accessor_get.cc +++ b/source/dofs/dof_accessor_get.cc @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/source/dofs/dof_accessor_set.cc b/source/dofs/dof_accessor_set.cc index 556dcd48c8f7..a116ab0858e9 100644 --- a/source/dofs/dof_accessor_set.cc +++ b/source/dofs/dof_accessor_set.cc @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/source/fe/fe_values.cc b/source/fe/fe_values.cc index 920f57a61ae0..b2c44908a6b8 100644 --- a/source/fe/fe_values.cc +++ b/source/fe/fe_values.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include diff --git a/source/fe/mapping_fe_field.cc b/source/fe/mapping_fe_field.cc index 5289c9d1e7ce..1659ccfb3a65 100644 --- a/source/fe/mapping_fe_field.cc +++ b/source/fe/mapping_fe_field.cc @@ -44,6 +44,7 @@ #include #include #include +#include #include #include diff --git a/source/lac/CMakeLists.txt b/source/lac/CMakeLists.txt index a6ce60360fe8..973837219e1b 100644 --- a/source/lac/CMakeLists.txt +++ b/source/lac/CMakeLists.txt @@ -132,6 +132,8 @@ IF(DEAL_II_WITH_TRILINOS) trilinos_solver.cc trilinos_sparse_matrix.cc trilinos_sparsity_pattern.cc + trilinos_tpetra_communication_pattern.cc + trilinos_tpetra_vector.cc trilinos_vector.cc ) diff --git a/source/lac/solver.cc b/source/lac/solver.cc index 6d432ae184b8..7bf9e30c3e86 100644 --- a/source/lac/solver.cc +++ b/source/lac/solver.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/source/lac/trilinos_sparse_matrix.cc b/source/lac/trilinos_sparse_matrix.cc index 291929c5c359..350006da3cca 100644 --- a/source/lac/trilinos_sparse_matrix.cc +++ b/source/lac/trilinos_sparse_matrix.cc @@ -103,6 +103,36 @@ namespace TrilinosWrappers { return V.trilinos_vector()[0] + V.trilinos_vector().MyLength(); } + + template <> + double * + begin(LinearAlgebra::TpetraWrappers::Vector &V) + { + return V.trilinos_vector().getDataNonConst().get(); + } + + template <> + const double * + begin(const LinearAlgebra::TpetraWrappers::Vector &V) + { + return V.trilinos_vector().getData().get(); + } + + template <> + double * + end(LinearAlgebra::TpetraWrappers::Vector &V) + { + return V.trilinos_vector().getDataNonConst().get() + + V.trilinos_vector().getLocalLength(); + } + + template <> + const double * + end(const LinearAlgebra::TpetraWrappers::Vector &V) + { + return V.trilinos_vector().getData().get() + + V.trilinos_vector().getLocalLength(); + } # endif } // namespace internal @@ -3454,6 +3484,11 @@ namespace TrilinosWrappers dealii::LinearAlgebra::distributed::Vector &, const dealii::LinearAlgebra::distributed::Vector &) const; # ifdef DEAL_II_WITH_MPI + template void + SparseMatrix::vmult( + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + template void SparseMatrix::vmult( dealii::LinearAlgebra::EpetraWrappers::Vector &, @@ -3469,6 +3504,11 @@ namespace TrilinosWrappers dealii::LinearAlgebra::distributed::Vector &, const dealii::LinearAlgebra::distributed::Vector &) const; # ifdef DEAL_II_WITH_MPI + template void + SparseMatrix::Tvmult( + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + template void SparseMatrix::Tvmult( dealii::LinearAlgebra::EpetraWrappers::Vector &, @@ -3484,6 +3524,11 @@ namespace TrilinosWrappers dealii::LinearAlgebra::distributed::Vector &, const dealii::LinearAlgebra::distributed::Vector &) const; # ifdef DEAL_II_WITH_MPI + template void + SparseMatrix::vmult_add( + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + template void SparseMatrix::vmult_add( dealii::LinearAlgebra::EpetraWrappers::Vector &, @@ -3499,6 +3544,11 @@ namespace TrilinosWrappers dealii::LinearAlgebra::distributed::Vector &, const dealii::LinearAlgebra::distributed::Vector &) const; # ifdef DEAL_II_WITH_MPI + template void + SparseMatrix::Tvmult_add( + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + template void SparseMatrix::Tvmult_add( dealii::LinearAlgebra::EpetraWrappers::Vector &, diff --git a/source/lac/trilinos_tpetra_communication_pattern.cc b/source/lac/trilinos_tpetra_communication_pattern.cc new file mode 100644 index 000000000000..e78dfda3d3d1 --- /dev/null +++ b/source/lac/trilinos_tpetra_communication_pattern.cc @@ -0,0 +1,104 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2015 - 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. +// +// --------------------------------------------------------------------- + +#include + +#include + +#ifdef DEAL_II_WITH_TRILINOS + +# ifdef DEAL_II_WITH_MPI + +# include + +# include + +# include + +DEAL_II_NAMESPACE_OPEN + +namespace LinearAlgebra +{ + namespace TpetraWrappers + { + CommunicationPattern::CommunicationPattern( + const IndexSet &vector_space_vector_index_set, + const IndexSet &read_write_vector_index_set, + const MPI_Comm &communicator) + { + // virtual functions called in constructors and destructors never use the + // override in a derived class + // for clarity be explicit on which function is called + CommunicationPattern::reinit(vector_space_vector_index_set, + read_write_vector_index_set, + communicator); + } + + + + void + CommunicationPattern::reinit(const IndexSet &vector_space_vector_index_set, + const IndexSet &read_write_vector_index_set, + const MPI_Comm &communicator) + { + comm = std::make_shared(communicator); + + auto vector_space_vector_map = Teuchos::rcp(new Tpetra::Map<>( + vector_space_vector_index_set.make_tpetra_map(*comm, false))); + auto read_write_vector_map = Teuchos::rcp(new Tpetra::Map<>( + read_write_vector_index_set.make_tpetra_map(*comm, true))); + + // Target map is read_write_vector_map + // Source map is vector_space_vector_map. This map must have uniquely + // owned GID. + tpetra_import = + std_cxx14::make_unique>(read_write_vector_map, + vector_space_vector_map); + tpetra_export = + std_cxx14::make_unique>(read_write_vector_map, + vector_space_vector_map); + } + + + + const MPI_Comm & + CommunicationPattern::get_mpi_communicator() const + { + return *comm; + } + + + + const Tpetra::Import<> & + CommunicationPattern::get_tpetra_import() const + { + return *tpetra_import; + } + + + + const Tpetra::Export<> & + CommunicationPattern::get_tpetra_export() const + { + return *tpetra_export; + } + } // namespace TpetraWrappers +} // namespace LinearAlgebra + +DEAL_II_NAMESPACE_CLOSE + +# endif + +#endif diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc new file mode 100644 index 000000000000..0a52aa1972e6 --- /dev/null +++ b/source/lac/trilinos_tpetra_vector.cc @@ -0,0 +1,632 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2015 - 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. +// +// --------------------------------------------------------------------- + +#include + +#include + +#ifdef DEAL_II_WITH_TRILINOS + +# ifdef DEAL_II_WITH_MPI + +# include + +# include + +# include + +# include +# include +# include + +# include + + +DEAL_II_NAMESPACE_OPEN + +namespace LinearAlgebra +{ + namespace TpetraWrappers + { + Vector::Vector() + : vector(new Tpetra::Vector<>(Teuchos::RCP>( + new Tpetra::Map<>(0, 0, Utilities::Trilinos::tpetra_comm_self())))) + {} + + + + Vector::Vector(const Vector &V) + : Subscriptor() + , vector(new Tpetra::Vector<>(V.trilinos_vector(), Teuchos::Copy)) + {} + + + + Vector::Vector(const IndexSet ¶llel_partitioner, + const MPI_Comm &communicator) + : vector(new Tpetra::Vector<>(Teuchos::rcp(new Tpetra::Map<>( + parallel_partitioner.make_tpetra_map(communicator, false))))) + {} + + + + void + Vector::reinit(const IndexSet ¶llel_partitioner, + const MPI_Comm &communicator, + const bool omit_zeroing_entries) + { + Tpetra::Map<> input_map = + parallel_partitioner.make_tpetra_map(communicator, false); + if (vector->getMap()->isSameAs(input_map) == false) + vector = std_cxx14::make_unique>( + Teuchos::rcp(new Tpetra::Map<>(input_map))); + else if (omit_zeroing_entries == false) + { + vector->putScalar(0.); + } + } + + + + void + Vector::reinit(const VectorSpaceVector &V, + const bool omit_zeroing_entries) + { + // Check that casting will work. + Assert(dynamic_cast(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast(V); + + reinit(down_V.locally_owned_elements(), + down_V.get_mpi_communicator(), + omit_zeroing_entries); + } + + + + Vector & + Vector::operator=(const Vector &V) + { + // Distinguish three cases: + // - First case: both vectors have the same layout. + // - Second case: both vectors have the same size but different layout. + // - Third case: the vectors have different size. + if (vector->getMap()->isSameAs(*(V.trilinos_vector().getMap()))) + *vector = V.trilinos_vector(); + else + { + if (size() == V.size()) + { + Tpetra::Import<> data_exchange(vector->getMap(), + V.trilinos_vector().getMap()); + + vector->doImport(V.trilinos_vector(), + data_exchange, + Tpetra::REPLACE); + } + else + vector = + std_cxx14::make_unique>(V.trilinos_vector()); + } + + return *this; + } + + + + Vector & + Vector::operator=(const double s) + { + Assert(s == 0., ExcMessage("Only 0 can be assigned to a vector.")); + + vector->putScalar(s); + + return *this; + } + + + + void + Vector::import( + const ReadWriteVector & V, + VectorOperation::values operation, + std::shared_ptr communication_pattern) + { + // If no communication pattern is given, create one. Otherwsie, use the + // one given. + if (communication_pattern == nullptr) + { + // The first time import is called, a communication pattern is + // created. Check if the communication pattern already exists and if + // it can be reused. + if ((source_stored_elements.size() != + V.get_stored_elements().size()) || + (source_stored_elements != V.get_stored_elements())) + { + const Teuchos::MpiComm *mpi_comm = + dynamic_cast *>( + vector->getMap()->getComm().get()); + Assert(mpi_comm != nullptr, ExcInternalError()); + create_tpetra_comm_pattern(V.get_stored_elements(), + *(mpi_comm->getRawMpiComm())()); + } + } + else + { + tpetra_comm_pattern = std::dynamic_pointer_cast< + const TpetraWrappers::CommunicationPattern>(communication_pattern); + AssertThrow( + tpetra_comm_pattern != nullptr, + ExcMessage( + std::string("The communication pattern is not of type ") + + "LinearAlgebra::TpetraWrappers::CommunicationPattern.")); + } + + Tpetra::Export<> tpetra_export(tpetra_comm_pattern->get_tpetra_export()); + Tpetra::Vector<> source_vector(tpetra_export.getSourceMap()); + + source_vector.sync(); + auto x_2d = source_vector.getLocalView(); + auto x_1d = Kokkos::subview(x_2d, Kokkos::ALL(), 0); + source_vector.modify(); + const size_t localLength = source_vector.getLocalLength(); + auto values_it = V.begin(); + for (size_t k = 0; k < localLength; ++k) + x_1d(k) = *values_it++; + source_vector.sync::device_type::memory_space>(); + if (operation == VectorOperation::insert) + vector->doExport(source_vector, tpetra_export, Tpetra::REPLACE); + else if (operation == VectorOperation::add) + vector->doExport(source_vector, tpetra_export, Tpetra::ADD); + else + AssertThrow(false, ExcNotImplemented()); + } + + + + Vector & + Vector::operator*=(const double factor) + { + AssertIsFinite(factor); + vector->scale(factor); + + return *this; + } + + + + Vector & + Vector::operator/=(const double factor) + { + AssertIsFinite(factor); + Assert(factor != 0., ExcZero()); + *this *= 1. / factor; + + return *this; + } + + + + Vector & + Vector::operator+=(const VectorSpaceVector &V) + { + // Check that casting will work. + Assert(dynamic_cast(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast(V); + // If the maps are the same we can Update right away. + if (vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap()))) + { + vector->update(1., down_V.trilinos_vector(), 1.); + } + else + { + Assert(this->size() == down_V.size(), + ExcDimensionMismatch(this->size(), down_V.size())); + + // TODO: The code doesn't work as expected so we use a workaround. + /*Tpetra::Export<> data_exchange(vector->getMap(), + down_V.trilinos_vector().getMap()); + vector->doExport(down_V.trilinos_vector(), + data_exchange, + Tpetra::ADD);*/ + + Tpetra::Vector<> dummy(vector->getMap(), false); + Tpetra::Import<> data_exchange(dummy.getMap(), + down_V.trilinos_vector().getMap()); + + dummy.doExport(down_V.trilinos_vector(), + data_exchange, + Tpetra::REPLACE); + + vector->update(1.0, dummy, 1.0); + } + + return *this; + } + + + + Vector & + Vector::operator-=(const VectorSpaceVector &V) + { + this->add(-1., V); + + return *this; + } + + + + double Vector::operator*(const VectorSpaceVector &V) const + { + // Check that casting will work. + Assert(dynamic_cast(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast(V); + Assert(this->size() == down_V.size(), + ExcDimensionMismatch(this->size(), down_V.size())); + Assert(vector->getMap()->isSameAs(*down_V.trilinos_vector().getMap()), + ExcDifferentParallelPartitioning()); + + return vector->dot(down_V.trilinos_vector()); + } + + + + void + Vector::add(const double a) + { + AssertIsFinite(a); + + vector->sync(); + auto vector_2d = vector->getLocalView(); + auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); + vector->modify(); + const size_t localLength = vector->getLocalLength(); + for (size_t k = 0; k < localLength; ++k) + { + vector_1d(k) += a; + } + vector->sync::device_type::memory_space>(); + } + + + + void + Vector::add(const double a, const VectorSpaceVector &V) + { + // Check that casting will work. + Assert(dynamic_cast(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast(V); + AssertIsFinite(a); + Assert(vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap())), + ExcDifferentParallelPartitioning()); + + vector->update(a, down_V.trilinos_vector(), 1.); + } + + + + void + Vector::add(const double a, + const VectorSpaceVector &V, + const double b, + const VectorSpaceVector &W) + { + // Check that casting will work. + Assert(dynamic_cast(&V) != nullptr, + ExcVectorTypeNotCompatible()); + // Check that casting will work. + Assert(dynamic_cast(&W) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast(V); + // Downcast W. If fails, throws an exception. + const Vector &down_W = dynamic_cast(W); + Assert(vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap())), + ExcDifferentParallelPartitioning()); + Assert(vector->getMap()->isSameAs(*(down_W.trilinos_vector().getMap())), + ExcDifferentParallelPartitioning()); + AssertIsFinite(a); + AssertIsFinite(b); + + vector->update( + a, down_V.trilinos_vector(), b, down_W.trilinos_vector(), 1.); + } + + + + void + Vector::sadd(const double s, + const double a, + const VectorSpaceVector &V) + { + // Check that casting will work. + Assert(dynamic_cast(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + *this *= s; + // Downcast V. It fails, throws an exception. + const Vector &down_V = dynamic_cast(V); + Vector tmp(down_V); + tmp *= a; + *this += tmp; + } + + + + void + Vector::scale(const VectorSpaceVector &scaling_factors) + { + // Check that casting will work. + Assert(dynamic_cast(&scaling_factors) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast scaling_factors. If fails, throws an exception. + const Vector &down_scaling_factors = + dynamic_cast(scaling_factors); + Assert(vector->getMap()->isSameAs( + *(down_scaling_factors.trilinos_vector().getMap())), + ExcDifferentParallelPartitioning()); + + vector->elementWiseMultiply(1., + *down_scaling_factors.vector, + *vector, + 0.); + } + + + + void + Vector::equ(const double a, const VectorSpaceVector &V) + { + // Check that casting will work. + Assert(dynamic_cast(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast(V); + // If we don't have the same map, copy. + if (vector->getMap()->isSameAs(*down_V.trilinos_vector().getMap()) == + false) + this->sadd(0., a, V); + else + { + // Otherwise, just update + vector->update(a, down_V.trilinos_vector(), 0.); + } + } + + + + bool + Vector::all_zero() const + { + // get a representation of the vector and + // loop over all the elements + double * start_ptr = vector->getDataNonConst().get(); + const double *ptr = start_ptr, + *eptr = start_ptr + vector->getLocalLength(); + unsigned int flag = 0; + while (ptr != eptr) + { + if (*ptr != 0) + { + flag = 1; + break; + } + ++ptr; + } + + // Check that the vector is zero on _all_ processors. + const Teuchos::MpiComm *mpi_comm = + dynamic_cast *>( + vector->getMap()->getComm().get()); + Assert(mpi_comm != nullptr, ExcInternalError()); + unsigned int num_nonzero = + Utilities::MPI::sum(flag, *(mpi_comm->getRawMpiComm())()); + + return num_nonzero == 0; + } + + + + double + Vector::mean_value() const + { + return vector->meanValue(); + } + + + + double + Vector::l1_norm() const + { + return vector->norm1(); + } + + + + double + Vector::l2_norm() const + { + return vector->norm2(); + } + + + + double + Vector::linfty_norm() const + { + return vector->normInf(); + } + + + + double + Vector::add_and_dot(const double a, + const VectorSpaceVector &V, + const VectorSpaceVector &W) + { + this->add(a, V); + + return *this * W; + } + + + + Vector::size_type + Vector::size() const + { + return vector->getGlobalLength(); + } + + + + MPI_Comm + Vector::get_mpi_communicator() const + { + const auto tpetra_comm = dynamic_cast *>( + vector->getMap()->getComm().get()); + Assert(tpetra_comm != nullptr, ExcInternalError()); + return *(tpetra_comm->getRawMpiComm())(); + } + + + + ::dealii::IndexSet + Vector::locally_owned_elements() const + { + IndexSet is(size()); + + // easy case: local range is contiguous + if (vector->getMap()->isContiguous()) + { +# ifndef DEAL_II_WITH_64BIT_INDICES + is.add_range(vector->getMap()->getMinGlobalIndex(), + vector->getMap()->getMaxGlobalIndex() + 1); +# else + is.add_range(vector->getMap()->getMinGlobalIndex(), + vector->getMap()->getMaxGlobalIndex() + 1); +# endif + } + else if (vector->getLocalLength() > 0) + { + const size_type n_indices = vector->getLocalLength(); + auto vector_indices = vector->getMap()->getMyGlobalIndices(); + is.add_indices((unsigned int *)&vector_indices[0], + (unsigned int *)&vector_indices[0] + n_indices); + } + is.compress(); + + return is; + } + + + + const Tpetra::Vector<> & + Vector::trilinos_vector() const + { + return *vector; + } + + + + Tpetra::Vector<> & + Vector::trilinos_vector() + { + return *vector; + } + + + + void + Vector::print(std::ostream & out, + const unsigned int precision, + const bool scientific, + const bool across) const + { + AssertThrow(out, ExcIO()); + boost::io::ios_flags_saver restore_flags(out); + + // Get a representation of the vector and loop over all + // the elements + const auto val = vector->get1dView(); + + out.precision(precision); + if (scientific) + out.setf(std::ios::scientific, std::ios::floatfield); + else + out.setf(std::ios::fixed, std::ios::floatfield); + + vector->sync(); + auto vector_2d = vector->getLocalView(); + auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); + const size_t local_length = vector->getLocalLength(); + + if (across) + for (unsigned int i = 0; i < local_length; ++i) + out << i << "->" << vector->getMap()->getGlobalElement(i) << ": " + << vector_1d(i) << std::endl; + // out << val[i] << ' '; + else + for (unsigned int i = 0; i < local_length; ++i) + out << val[i] << std::endl; + out << std::endl; + + // restore the representation + // of the vector + AssertThrow(out, ExcIO()); + } + + + + std::size_t + Vector::memory_consumption() const + { + return sizeof(*this) + + vector->getLocalLength() * + (sizeof(double) + sizeof(TrilinosWrappers::types::int_type)); + } + + + + void + Vector::create_tpetra_comm_pattern(const IndexSet &source_index_set, + const MPI_Comm &mpi_comm) + { + source_stored_elements = source_index_set; + tpetra_comm_pattern = + std::make_shared( + locally_owned_elements(), source_index_set, mpi_comm); + } + } // namespace TpetraWrappers +} // namespace LinearAlgebra + +DEAL_II_NAMESPACE_CLOSE + +# endif + +#endif diff --git a/source/lac/vector_memory.cc b/source/lac/vector_memory.cc index f15f32800e75..3fa5affd9bd9 100644 --- a/source/lac/vector_memory.cc +++ b/source/lac/vector_memory.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/source/multigrid/mg_base.cc b/source/multigrid/mg_base.cc index 8744c6cf4049..a32b68a09688 100644 --- a/source/multigrid/mg_base.cc +++ b/source/multigrid/mg_base.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff --git a/source/numerics/data_out_dof_data_codim.cc b/source/numerics/data_out_dof_data_codim.cc index e085c3d3825b..676a33714ecb 100644 --- a/source/numerics/data_out_dof_data_codim.cc +++ b/source/numerics/data_out_dof_data_codim.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/source/numerics/derivative_approximation.cc b/source/numerics/derivative_approximation.cc index 73f574bdc116..d062b4ec2bd9 100644 --- a/source/numerics/derivative_approximation.cc +++ b/source/numerics/derivative_approximation.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include #include diff --git a/tests/trilinos/tpetra_vector_01.cc b/tests/trilinos/tpetra_vector_01.cc new file mode 100644 index 000000000000..c10ac87bb1e3 --- /dev/null +++ b/tests/trilinos/tpetra_vector_01.cc @@ -0,0 +1,225 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2015 - 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. +// +// --------------------------------------------------------------------- + + +#include + +#include +#include + +#include +#include + +#include "../tests.h" + +// Check LinearAlgebra::TpetraWrappers::Vector assignment and import + + +void +test() +{ + IndexSet parallel_partitioner_1(10); + IndexSet parallel_partitioner_2(10); + unsigned int rank = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); + if (rank == 0) + { + parallel_partitioner_1.add_range(0, 5); + parallel_partitioner_2.add_range(0, 3); + } + else + { + parallel_partitioner_1.add_range(5, 10); + parallel_partitioner_2.add_range(3, 10); + } + parallel_partitioner_1.compress(); + parallel_partitioner_2.compress(); + LinearAlgebra::TpetraWrappers::Vector a; + LinearAlgebra::TpetraWrappers::Vector b(parallel_partitioner_1, + MPI_COMM_WORLD); + LinearAlgebra::TpetraWrappers::Vector c(b); + + AssertThrow(a.size() == 0, ExcMessage("Vector has the wrong size.")); + AssertThrow(b.size() == 10, ExcMessage("Vector has the wrong size.")); + AssertThrow(c.size() == 10, ExcMessage("Vector has the wrong size.")); + + a.reinit(parallel_partitioner_2, MPI_COMM_WORLD); + AssertThrow(a.size() == 10, ExcMessage("Vector has the wrong size.")); + + AssertThrow(parallel_partitioner_1 == b.locally_owned_elements(), + ExcMessage("IndexSet has been modified.")); + AssertThrow(parallel_partitioner_2 == a.locally_owned_elements(), + ExcMessage("IndexSet has been modified.")); + + IndexSet read_write_index_set(10); + if (rank == 0) + read_write_index_set.add_range(0, 6); + else + read_write_index_set.add_range(4, 10); + read_write_index_set.compress(); + + LinearAlgebra::ReadWriteVector read_write_1(read_write_index_set); + LinearAlgebra::ReadWriteVector read_write_2(read_write_index_set); + LinearAlgebra::ReadWriteVector read_write_3(read_write_index_set); + if (rank == 0) + { + for (unsigned int i = 0; i < 6; ++i) + { + read_write_1[i] = i; + read_write_2[i] = 5. + i; + } + } + else + { + for (unsigned int i = 4; i < 10; ++i) + { + read_write_1[i] = i; + read_write_2[i] = 5. + i; + } + } + + a.import(read_write_2, VectorOperation::insert); + AssertThrow(a.size() == 10, ExcMessage("Vector has the wrong size.")); + + read_write_3.import(a, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 6; ++i) + { + AssertThrow(read_write_2[i] == read_write_3[i], + ExcMessage("Vector a has been modified.")); + } + } + else + { + for (unsigned int i = 4; i < 10; ++i) + AssertThrow(read_write_2[i] == read_write_3[i], + ExcMessage("Vector a has been modified.")); + } + + b.import(read_write_1, VectorOperation::insert); + AssertThrow(b.size() == 10, ExcMessage("Vector has the wrong size.")); + + read_write_3.import(b, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 6; ++i) + AssertThrow(read_write_1[i] == read_write_3[i], + ExcMessage("Vector b has been modified.")); + } + else + { + for (unsigned int i = 4; i < 10; ++i) + AssertThrow(read_write_1[i] == read_write_3[i], + ExcMessage("Vector b has been modified.")); + } + + c.import(read_write_2, VectorOperation::insert); + AssertThrow(c.size() == 10, ExcMessage("Vector has the wrong size.")); + + read_write_3.import(c, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 6; ++i) + AssertThrow(read_write_2[i] == read_write_3[i], + ExcMessage("Vector c has been modified.")); + } + else + { + for (unsigned int i = 4; i < 10; ++i) + AssertThrow(read_write_2[i] == read_write_3[i], + ExcMessage("Vector c has been modified.")); + } + + a *= 2; + read_write_3.import(a, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 6; ++i) + AssertThrow(2. * read_write_2[i] == read_write_3[i], + ExcMessage("Problem in operator *=.")); + } + else + { + for (unsigned int i = 4; i < 10; ++i) + AssertThrow(2. * read_write_2[i] == read_write_3[i], + ExcMessage("Problem in operator *=.")); + } + + c /= 2.; + read_write_3.import(c, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 6; ++i) + AssertThrow(0.5 * read_write_2[i] == read_write_3[i], + ExcMessage("Problem in operator /=.")); + } + else + { + for (unsigned int i = 4; i < 10; ++i) + AssertThrow(0.5 * read_write_2[i] == read_write_3[i], + ExcMessage("Problem in operator /=.")); + } + + b += a; + read_write_3.import(b, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 6; ++i) + AssertThrow(2. * read_write_2[i] + read_write_1[i] == read_write_3[i], + ExcMessage("Problem in operator +=.")); + } + else + { + for (unsigned int i = 4; i < 10; ++i) + AssertThrow(2. * read_write_2[i] + read_write_1[i] == read_write_3[i], + ExcMessage("Problem in operator +=.")); + } + + b -= c; + read_write_3.import(b, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 6; ++i) + AssertThrow(1.5 * read_write_2[i] + read_write_1[i] == read_write_3[i], + ExcMessage("Problem in operator -=.")); + } + else + { + for (unsigned int i = 4; i < 10; ++i) + AssertThrow(1.5 * read_write_2[i] + read_write_1[i] == read_write_3[i], + ExcMessage("Problem in operator -=.")); + } + + b.import(read_write_1, VectorOperation::insert); + c.import(read_write_1, VectorOperation::insert); + const double val = b * c; + AssertThrow(val == 285., ExcMessage("Problem in operator *.")); +} + + +int +main(int argc, char **argv) +{ + initlog(); + deallog.depth_console(0); + + Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1); + + test(); + + deallog << "OK" << std::endl; + + return 0; +} diff --git a/tests/trilinos/tpetra_vector_01.mpirun=2.output b/tests/trilinos/tpetra_vector_01.mpirun=2.output new file mode 100644 index 000000000000..0fd8fc12f0b4 --- /dev/null +++ b/tests/trilinos/tpetra_vector_01.mpirun=2.output @@ -0,0 +1,2 @@ + +DEAL::OK diff --git a/tests/trilinos/tpetra_vector_02.cc b/tests/trilinos/tpetra_vector_02.cc new file mode 100644 index 000000000000..8e4875353044 --- /dev/null +++ b/tests/trilinos/tpetra_vector_02.cc @@ -0,0 +1,216 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2015 - 2017 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 + +#include +#include + +#include +#include + +#include "../tests.h" + +// Check LinearAlgebra::TpetraWrappers::Vector add and sadd. + +void +test() +{ + IndexSet parallel_partitioner_1(10); + IndexSet parallel_partitioner_2(10); + unsigned int rank = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); + if (rank == 0) + { + parallel_partitioner_1.add_range(0, 5); + parallel_partitioner_2.add_range(0, 3); + } + else + { + parallel_partitioner_1.add_range(5, 10); + parallel_partitioner_2.add_range(3, 10); + } + parallel_partitioner_1.compress(); + parallel_partitioner_2.compress(); + LinearAlgebra::TpetraWrappers::Vector a(parallel_partitioner_1, + MPI_COMM_WORLD); + LinearAlgebra::TpetraWrappers::Vector b(parallel_partitioner_1, + MPI_COMM_WORLD); + LinearAlgebra::TpetraWrappers::Vector c(parallel_partitioner_2, + MPI_COMM_WORLD); + + IndexSet read_write_index_set(10); + if (rank == 0) + read_write_index_set.add_range(0, 5); + else + read_write_index_set.add_range(5, 10); + read_write_index_set.compress(); + + LinearAlgebra::ReadWriteVector read_write_1(read_write_index_set); + LinearAlgebra::ReadWriteVector read_write_2(read_write_index_set); + LinearAlgebra::ReadWriteVector read_write_3(read_write_index_set); + if (rank == 0) + { + for (unsigned int i = 0; i < 5; ++i) + { + read_write_1[i] = i; + read_write_2[i] = 5. + i; + } + } + else + { + for (unsigned int i = 5; i < 10; ++i) + { + read_write_1[i] = i; + read_write_2[i] = 5. + i; + } + } + + a.import(read_write_1, VectorOperation::insert); + b.import(read_write_2, VectorOperation::insert); + c.import(read_write_2, VectorOperation::insert); + + a.add(1.); + read_write_3.import(a, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 5; ++i) + AssertThrow(1. + read_write_1[i] == read_write_3[i], + ExcMessage("Problem in add(scalar).")); + } + else + { + for (unsigned int i = 5; i < 10; ++i) + AssertThrow(1. + read_write_1[i] == read_write_3[i], + ExcMessage("Problem in add(scalar).")); + } + + a.add(2., b); + read_write_3.import(a, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 5; ++i) + AssertThrow(1. + read_write_1[i] + 2. * read_write_2[i] == + read_write_3[i], + ExcMessage("Problem in add(scalar,Vector).")); + } + else + { + for (unsigned int i = 5; i < 10; ++i) + AssertThrow(1. + read_write_1[i] + 2. * read_write_2[i] == + read_write_3[i], + ExcMessage("Problem in add(scalar,Vector).")); + } + + + LinearAlgebra::TpetraWrappers::Vector d(a); + a.add(2., b, 3., d); + read_write_3.import(a, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 5; ++i) + AssertThrow(4. + 4. * read_write_1[i] + 10. * read_write_2[i] == + read_write_3[i], + ExcMessage("Problem in add(scalar,Vector,scalar,Vector).")); + } + else + { + for (unsigned int i = 5; i < 10; ++i) + AssertThrow(4. + 4. * read_write_1[i] + 10. * read_write_2[i] == + read_write_3[i], + ExcMessage("Problem in add(scalar,Vector,scalar,Vector).")); + } + + + a.import(read_write_1, VectorOperation::insert); + a.sadd(3., 2., c); + read_write_3.import(a, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 5; ++i) + AssertThrow(3. * read_write_1[i] + 2. * read_write_2[i] == + read_write_3[i], + ExcMessage("Problem in sadd(scalar,scalar,Vector).")); + } + else + { + for (unsigned int i = 5; i < 10; ++i) + AssertThrow(3. * read_write_1[i] + 2. * read_write_2[i] == + read_write_3[i], + ExcMessage("Problem in sadd(scalar,scalar,Vector).")); + } + + + a.import(read_write_1, VectorOperation::insert); + a.scale(b); + read_write_3.import(a, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 5; ++i) + AssertThrow(read_write_1[i] * read_write_2[i] == read_write_3[i], + ExcMessage("Problem in scale.")); + } + else + { + for (unsigned int i = 5; i < 10; ++i) + AssertThrow(read_write_1[i] * read_write_2[i] == read_write_3[i], + ExcMessage("Problem in scale.")); + } + + + a.equ(2., c); + read_write_3.import(a, VectorOperation::insert); + if (rank == 0) + { + for (unsigned int i = 0; i < 5; ++i) + AssertThrow(2. * read_write_2[i] == read_write_3[i], + ExcMessage("Problem in scale.")); + } + else + { + for (unsigned int i = 5; i < 10; ++i) + AssertThrow(2. * read_write_2[i] == read_write_3[i], + ExcMessage("Problem in equ.")); + } + + + AssertThrow(b.l1_norm() == 95., ExcMessage("Problem in l1_norm.")); + + const double eps = 1e-6; + AssertThrow(std::fabs(b.l2_norm() - 31.3847096) < eps, + ExcMessage("Problem in l2_norm")); + + AssertThrow(b.linfty_norm() == 14., ExcMessage("Problem in linfty_norm.")); + + a.import(read_write_1, VectorOperation::insert); + const double val = a.add_and_dot(2., a, b); + AssertThrow(val == 1530., ExcMessage("Problem in add_and_dot")); +} + + +int +main(int argc, char **argv) +{ + initlog(); + deallog.depth_console(0); + + Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1); + + test(); + + deallog << "OK" << std::endl; + + return 0; +} diff --git a/tests/trilinos/tpetra_vector_02.mpirun=2.output b/tests/trilinos/tpetra_vector_02.mpirun=2.output new file mode 100644 index 000000000000..0fd8fc12f0b4 --- /dev/null +++ b/tests/trilinos/tpetra_vector_02.mpirun=2.output @@ -0,0 +1,2 @@ + +DEAL::OK diff --git a/tests/trilinos/tpetra_vector_03.cc b/tests/trilinos/tpetra_vector_03.cc new file mode 100644 index 000000000000..4927aaedb82a --- /dev/null +++ b/tests/trilinos/tpetra_vector_03.cc @@ -0,0 +1,101 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Check LinearAlgebra::TpetraWrappers::Vector::import +// for VectorOperation::add and check LinearAlgebra::ReadWriteVector +// for VectorOperation::add/min/max. + +#include +#include + +#include +#include + +#include +#include + +#include "../tests.h" + +void +test() +{ + unsigned int my_id = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); + unsigned int n_procs = Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD); + + IndexSet locally_owned(n_procs * 2); + locally_owned.add_range(my_id * 2, my_id * 2 + 2); + locally_owned.compress(); + + LinearAlgebra::TpetraWrappers::Vector v(locally_owned, MPI_COMM_WORLD); + + IndexSet workaround_set(n_procs * 2); + unsigned int my_first_index = (my_id * 2 + 2) % (n_procs * 2); + unsigned int my_second_index = my_id * 2 + 1; + workaround_set.add_index(my_first_index); + workaround_set.add_index(my_second_index); + workaround_set.add_index(0); + workaround_set.compress(); + LinearAlgebra::ReadWriteVector rw_vector(workaround_set); + + rw_vector(my_first_index) = my_id + 10; + rw_vector(my_second_index) = my_id + 100; + rw_vector(0) = 1.; + // rw_vector(2) = 1.; + v.import(rw_vector, VectorOperation::add); + deallog << "Tpetra first import add:" << std::endl; + v.print(deallog.get_file_stream()); + rw_vector.print(deallog.get_file_stream()); + + rw_vector(my_first_index) = my_id + 20; + rw_vector(my_second_index) = my_id + 200; + rw_vector(0) = 2.; + // rw_vector(2) = 3.; + v.import(rw_vector, VectorOperation::add); + deallog << "Tpetra second import add:" << std::endl; + v.print(deallog.get_file_stream()); + rw_vector.print(deallog.get_file_stream()); + + rw_vector.import(v, VectorOperation::add); + deallog << "ReadWrite import add:" << std::endl; + rw_vector.print(deallog.get_file_stream()); + + rw_vector(my_first_index) = my_id + 100; + rw_vector(my_second_index) = 1; + rw_vector(0) = 4.; + // rw_vector(2) = 3.; + rw_vector.import(v, VectorOperation::min); + deallog << "ReadWrite import min:" << std::endl; + rw_vector.print(deallog.get_file_stream()); + + rw_vector(my_first_index) = my_id + 100; + rw_vector(my_second_index) = 1; + rw_vector(0) = 4.; + // rw_vector(2) = 3.; + rw_vector.import(v, VectorOperation::max); + deallog << "ReadWrite import max:" << std::endl; + rw_vector.print(deallog.get_file_stream()); +} + + + +int +main(int argc, char **argv) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization( + argc, argv, testing_max_num_threads()); + + MPILogInitAll log; + test(); +} diff --git a/tests/trilinos/tpetra_vector_03.mpirun=2.output b/tests/trilinos/tpetra_vector_03.mpirun=2.output new file mode 100644 index 000000000000..5d5f9c0afb64 --- /dev/null +++ b/tests/trilinos/tpetra_vector_03.mpirun=2.output @@ -0,0 +1,70 @@ + +DEAL:0::Tpetra first import add: +0->0: 2.000e+00 +1->1: 1.000e+02 + +IndexSet: {[0,2]} + +[0]: 1.000e+00 +[1]: 1.000e+02 +[2]: 1.000e+01 +DEAL:0::Tpetra second import add: +0->0: 4.000e+00 +1->1: 2.000e+02 + +IndexSet: {[0,2]} + +[0]: 2.000e+00 +[1]: 2.000e+02 +[2]: 2.000e+01 +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: 6.000e+00 +[1]: 4.000e+02 +[2]: 5.000e+01 +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} + +[0]: 4.000e+00 +[1]: 1.000e+00 +[2]: 3.000e+01 +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + +[0]: 4.000e+00 +[1]: 2.000e+02 +[2]: 1.000e+02 + +DEAL:1::Tpetra first import add: +0->2: 1.000e+01 +1->3: 1.010e+02 + +IndexSet: {0, 3} + +[0]: 1.000e+00 +[3]: 1.010e+02 +DEAL:1::Tpetra second import add: +0->2: 3.000e+01 +1->3: 2.010e+02 + +IndexSet: {0, 3} + +[0]: 2.000e+00 +[3]: 2.010e+02 +DEAL:1::ReadWrite import add: +IndexSet: {0, 3} + +[0]: 6.000e+00 +[3]: 4.020e+02 +DEAL:1::ReadWrite import min: +IndexSet: {0, 3} + +[0]: 4.000e+00 +[3]: 1.000e+00 +DEAL:1::ReadWrite import max: +IndexSet: {0, 3} + +[0]: 4.000e+00 +[3]: 2.010e+02 + diff --git a/tests/trilinos/tpetra_vector_03.mpirun=4.output b/tests/trilinos/tpetra_vector_03.mpirun=4.output new file mode 100644 index 000000000000..bb8d36da886b --- /dev/null +++ b/tests/trilinos/tpetra_vector_03.mpirun=4.output @@ -0,0 +1,146 @@ + +DEAL:0::Tpetra first import add: +0->0: 4.000e+00 +1->1: 1.000e+02 + +IndexSet: {[0,2]} + +[0]: 1.000e+00 +[1]: 1.000e+02 +[2]: 1.000e+01 +DEAL:0::Tpetra second import add: +0->0: 8.000e+00 +1->1: 2.000e+02 + +IndexSet: {[0,2]} + +[0]: 2.000e+00 +[1]: 2.000e+02 +[2]: 2.000e+01 +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: 1.000e+01 +[1]: 4.000e+02 +[2]: 5.000e+01 +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} + +[0]: 4.000e+00 +[1]: 1.000e+00 +[2]: 3.000e+01 +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + +[0]: 8.000e+00 +[1]: 2.000e+02 +[2]: 1.000e+02 + +DEAL:1::Tpetra first import add: +0->2: 1.000e+01 +1->3: 1.010e+02 + +IndexSet: {0, [3,4]} + +[0]: 1.000e+00 +[3]: 1.010e+02 +[4]: 1.100e+01 +DEAL:1::Tpetra second import add: +0->2: 3.000e+01 +1->3: 2.010e+02 + +IndexSet: {0, [3,4]} + +[0]: 2.000e+00 +[3]: 2.010e+02 +[4]: 2.100e+01 +DEAL:1::ReadWrite import add: +IndexSet: {0, [3,4]} + +[0]: 1.000e+01 +[3]: 4.020e+02 +[4]: 5.300e+01 +DEAL:1::ReadWrite import min: +IndexSet: {0, [3,4]} + +[0]: 4.000e+00 +[3]: 1.000e+00 +[4]: 3.200e+01 +DEAL:1::ReadWrite import max: +IndexSet: {0, [3,4]} + +[0]: 8.000e+00 +[3]: 2.010e+02 +[4]: 1.010e+02 + + +DEAL:2::Tpetra first import add: +0->4: 1.100e+01 +1->5: 1.020e+02 + +IndexSet: {0, [5,6]} + +[0]: 1.000e+00 +[5]: 1.020e+02 +[6]: 1.200e+01 +DEAL:2::Tpetra second import add: +0->4: 3.200e+01 +1->5: 2.020e+02 + +IndexSet: {0, [5,6]} + +[0]: 2.000e+00 +[5]: 2.020e+02 +[6]: 2.200e+01 +DEAL:2::ReadWrite import add: +IndexSet: {0, [5,6]} + +[0]: 1.000e+01 +[5]: 4.040e+02 +[6]: 5.600e+01 +DEAL:2::ReadWrite import min: +IndexSet: {0, [5,6]} + +[0]: 4.000e+00 +[5]: 1.000e+00 +[6]: 3.400e+01 +DEAL:2::ReadWrite import max: +IndexSet: {0, [5,6]} + +[0]: 8.000e+00 +[5]: 2.020e+02 +[6]: 1.020e+02 + + +DEAL:3::Tpetra first import add: +0->6: 1.200e+01 +1->7: 1.030e+02 + +IndexSet: {0, 7} + +[0]: 1.000e+00 +[7]: 1.030e+02 +DEAL:3::Tpetra second import add: +0->6: 3.400e+01 +1->7: 2.030e+02 + +IndexSet: {0, 7} + +[0]: 2.000e+00 +[7]: 2.030e+02 +DEAL:3::ReadWrite import add: +IndexSet: {0, 7} + +[0]: 1.000e+01 +[7]: 4.060e+02 +DEAL:3::ReadWrite import min: +IndexSet: {0, 7} + +[0]: 4.000e+00 +[7]: 1.000e+00 +DEAL:3::ReadWrite import max: +IndexSet: {0, 7} + +[0]: 8.000e+00 +[7]: 2.030e+02 + From dbbe12525f2b0c396212ba5258f5d513fcaf1a55 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 13 Sep 2018 02:30:37 +0200 Subject: [PATCH 147/507] Change output format --- source/lac/trilinos_tpetra_vector.cc | 6 ++-- .../trilinos/tpetra_vector_03.mpirun=2.output | 16 +++------- .../trilinos/tpetra_vector_03.mpirun=4.output | 32 +++++-------------- 3 files changed, 14 insertions(+), 40 deletions(-) diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc index 0a52aa1972e6..5e3c00b53ad4 100644 --- a/source/lac/trilinos_tpetra_vector.cc +++ b/source/lac/trilinos_tpetra_vector.cc @@ -588,12 +588,10 @@ namespace LinearAlgebra if (across) for (unsigned int i = 0; i < local_length; ++i) - out << i << "->" << vector->getMap()->getGlobalElement(i) << ": " - << vector_1d(i) << std::endl; - // out << val[i] << ' '; + out << vector_1d(i) << ' '; else for (unsigned int i = 0; i < local_length; ++i) - out << val[i] << std::endl; + out << vector_1d(i) << std::endl; out << std::endl; // restore the representation diff --git a/tests/trilinos/tpetra_vector_03.mpirun=2.output b/tests/trilinos/tpetra_vector_03.mpirun=2.output index 5d5f9c0afb64..638319c2f1c3 100644 --- a/tests/trilinos/tpetra_vector_03.mpirun=2.output +++ b/tests/trilinos/tpetra_vector_03.mpirun=2.output @@ -1,17 +1,13 @@ DEAL:0::Tpetra first import add: -0->0: 2.000e+00 -1->1: 1.000e+02 - +2.000e+00 1.000e+02 IndexSet: {[0,2]} [0]: 1.000e+00 [1]: 1.000e+02 [2]: 1.000e+01 DEAL:0::Tpetra second import add: -0->0: 4.000e+00 -1->1: 2.000e+02 - +4.000e+00 2.000e+02 IndexSet: {[0,2]} [0]: 2.000e+00 @@ -37,17 +33,13 @@ IndexSet: {[0,2]} [2]: 1.000e+02 DEAL:1::Tpetra first import add: -0->2: 1.000e+01 -1->3: 1.010e+02 - +1.000e+01 1.010e+02 IndexSet: {0, 3} [0]: 1.000e+00 [3]: 1.010e+02 DEAL:1::Tpetra second import add: -0->2: 3.000e+01 -1->3: 2.010e+02 - +3.000e+01 2.010e+02 IndexSet: {0, 3} [0]: 2.000e+00 diff --git a/tests/trilinos/tpetra_vector_03.mpirun=4.output b/tests/trilinos/tpetra_vector_03.mpirun=4.output index bb8d36da886b..f70ed13b09e8 100644 --- a/tests/trilinos/tpetra_vector_03.mpirun=4.output +++ b/tests/trilinos/tpetra_vector_03.mpirun=4.output @@ -1,17 +1,13 @@ DEAL:0::Tpetra first import add: -0->0: 4.000e+00 -1->1: 1.000e+02 - +4.000e+00 1.000e+02 IndexSet: {[0,2]} [0]: 1.000e+00 [1]: 1.000e+02 [2]: 1.000e+01 DEAL:0::Tpetra second import add: -0->0: 8.000e+00 -1->1: 2.000e+02 - +8.000e+00 2.000e+02 IndexSet: {[0,2]} [0]: 2.000e+00 @@ -37,18 +33,14 @@ IndexSet: {[0,2]} [2]: 1.000e+02 DEAL:1::Tpetra first import add: -0->2: 1.000e+01 -1->3: 1.010e+02 - +1.000e+01 1.010e+02 IndexSet: {0, [3,4]} [0]: 1.000e+00 [3]: 1.010e+02 [4]: 1.100e+01 DEAL:1::Tpetra second import add: -0->2: 3.000e+01 -1->3: 2.010e+02 - +3.000e+01 2.010e+02 IndexSet: {0, [3,4]} [0]: 2.000e+00 @@ -75,18 +67,14 @@ IndexSet: {0, [3,4]} DEAL:2::Tpetra first import add: -0->4: 1.100e+01 -1->5: 1.020e+02 - +1.100e+01 1.020e+02 IndexSet: {0, [5,6]} [0]: 1.000e+00 [5]: 1.020e+02 [6]: 1.200e+01 DEAL:2::Tpetra second import add: -0->4: 3.200e+01 -1->5: 2.020e+02 - +3.200e+01 2.020e+02 IndexSet: {0, [5,6]} [0]: 2.000e+00 @@ -113,17 +101,13 @@ IndexSet: {0, [5,6]} DEAL:3::Tpetra first import add: -0->6: 1.200e+01 -1->7: 1.030e+02 - +1.200e+01 1.030e+02 IndexSet: {0, 7} [0]: 1.000e+00 [7]: 1.030e+02 DEAL:3::Tpetra second import add: -0->6: 3.400e+01 -1->7: 2.030e+02 - +3.400e+01 2.030e+02 IndexSet: {0, 7} [0]: 2.000e+00 From 1bbf0198f12dc8e0238883ec75cf90b4592fb26c Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 14 Sep 2018 13:59:27 +0200 Subject: [PATCH 148/507] Working --- cmake/config/template-arguments.in | 15 +- cmake/configure/configure_2_trilinos.cmake | 3 +- include/deal.II/dofs/dof_accessor.templates.h | 13 +- .../fe/fe_tools_extrapolate.templates.h | 6 +- .../fe/fe_tools_interpolate.templates.h | 10 +- include/deal.II/lac/read_write_vector.h | 12 +- .../deal.II/lac/read_write_vector.templates.h | 16 +- include/deal.II/lac/trilinos_sparse_matrix.h | 8 + include/deal.II/lac/trilinos_tpetra_vector.h | 80 +++--- include/deal.II/lac/vector_element_access.h | 102 +++++-- include/deal.II/multigrid/mg_transfer.h | 4 +- source/fe/mapping_q1_eulerian.cc | 3 +- source/lac/trilinos_sparse_matrix.cc | 84 ++++-- source/lac/trilinos_tpetra_vector.cc | 267 ++++++++++-------- tests/trilinos/tpetra_vector_01.cc | 21 +- tests/trilinos/tpetra_vector_02.cc | 26 +- tests/trilinos/tpetra_vector_03.cc | 9 +- .../trilinos/tpetra_vector_03.mpirun=2.output | 59 ++++ .../trilinos/tpetra_vector_03.mpirun=4.output | 123 ++++++++ 19 files changed, 607 insertions(+), 254 deletions(-) diff --git a/cmake/config/template-arguments.in b/cmake/config/template-arguments.in index 17a9f2ba9477..8a58e905961b 100644 --- a/cmake/config/template-arguments.in +++ b/cmake/config/template-arguments.in @@ -95,7 +95,8 @@ VECTOR_TYPES := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; - @DEAL_II_EXPAND_TPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR@; @DEAL_II_EXPAND_TRILINOS_MPI_BLOCKVECTOR@; @@ -121,7 +122,8 @@ REAL_VECTOR_TYPES := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; - @DEAL_II_EXPAND_TPETRA_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@; @@ -140,7 +142,8 @@ REAL_NONBLOCK_VECTORS := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; - @DEAL_II_EXPAND_TPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR_REAL@; } @@ -148,7 +151,8 @@ 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@; + @DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR@; @DEAL_II_EXPAND_PETSC_MPI_BLOCKVECTOR@ } @@ -167,7 +171,8 @@ VECTORS_WITH_MATRIX := { Vector; @DEAL_II_EXPAND_TRILINOS_MPI_VECTOR@; @DEAL_II_EXPAND_EPETRA_VECTOR@; - @DEAL_II_EXPAND_TPETRA_VECTOR@; + @DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE@; + @DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT@; @DEAL_II_EXPAND_PETSC_MPI_VECTOR@; } diff --git a/cmake/configure/configure_2_trilinos.cmake b/cmake/configure/configure_2_trilinos.cmake index abe66905d82c..661c739b7c7f 100644 --- a/cmake/configure/configure_2_trilinos.cmake +++ b/cmake/configure/configure_2_trilinos.cmake @@ -227,7 +227,8 @@ 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") - SET(DEAL_II_EXPAND_TPETRA_VECTOR "LinearAlgebra::TpetraWrappers::Vector") + SET(DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE "LinearAlgebra::TpetraWrappers::Vector") + #SET(DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT "LinearAlgebra::TpetraWrappers::Vector") ENDIF() IF(${DEAL_II_TRILINOS_WITH_SACADO}) # Note: Only CMake 3.0 and greater support line continuation with the "\" character diff --git a/include/deal.II/dofs/dof_accessor.templates.h b/include/deal.II/dofs/dof_accessor.templates.h index 73b77c07a57d..9b89e6e31f47 100644 --- a/include/deal.II/dofs/dof_accessor.templates.h +++ b/include/deal.II/dofs/dof_accessor.templates.h @@ -1534,12 +1534,13 @@ namespace internal - template + template static void - extract_subvector_to(const LinearAlgebra::TpetraWrappers::Vector &values, - const types::global_dof_index *cache_begin, - const types::global_dof_index *cache_end, - ForwardIterator local_values_begin) + extract_subvector_to( + const LinearAlgebra::TpetraWrappers::Vector &values, + const types::global_dof_index * cache_begin, + const types::global_dof_index * cache_end, + ForwardIterator local_values_begin) { std::vector sorted_indices_pos = sort_indices(cache_begin, cache_end); @@ -1551,7 +1552,7 @@ namespace internal IndexSet index_set(cache_indices.back() + 1); index_set.add_indices(cache_indices.begin(), cache_indices.end()); index_set.compress(); - LinearAlgebra::ReadWriteVector read_write_vector(index_set); + LinearAlgebra::ReadWriteVector read_write_vector(index_set); read_write_vector.import(values, VectorOperation::insert); // Copy the elements from read_write_vector and reorder them. diff --git a/include/deal.II/fe/fe_tools_extrapolate.templates.h b/include/deal.II/fe/fe_tools_extrapolate.templates.h index 850a4c6216ca..ea76059356c7 100644 --- a/include/deal.II/fe/fe_tools_extrapolate.templates.h +++ b/include/deal.II/fe/fe_tools_extrapolate.templates.h @@ -1581,10 +1581,10 @@ namespace FETools # ifdef DEAL_II_WITH_MPI - template + template void - reinit_distributed(const DoFHandler & dh, - LinearAlgebra::TpetraWrappers::Vector &vector) + reinit_distributed(const DoFHandler & dh, + LinearAlgebra::TpetraWrappers::Vector &vector) { const parallel::distributed::Triangulation *parallel_tria = dynamic_cast< diff --git a/include/deal.II/fe/fe_tools_interpolate.templates.h b/include/deal.II/fe/fe_tools_interpolate.templates.h index e2e9b417fe02..9699c0a9b43d 100644 --- a/include/deal.II/fe/fe_tools_interpolate.templates.h +++ b/include/deal.II/fe/fe_tools_interpolate.templates.h @@ -513,17 +513,17 @@ namespace FETools AssertThrow(false, ExcNotImplemented()); } - template + template void back_interpolate( const DoFHandler &, const AffineConstraints< - typename LinearAlgebra::TpetraWrappers::Vector::value_type> &, - const LinearAlgebra::TpetraWrappers::Vector &, + typename LinearAlgebra::TpetraWrappers::Vector::value_type> &, + const LinearAlgebra::TpetraWrappers::Vector &, const DoFHandler &, const AffineConstraints< - typename LinearAlgebra::TpetraWrappers::Vector::value_type> &, - LinearAlgebra::TpetraWrappers::Vector &) + typename LinearAlgebra::TpetraWrappers::Vector::value_type> &, + LinearAlgebra::TpetraWrappers::Vector &) { AssertThrow(false, ExcNotImplemented()); } diff --git a/include/deal.II/lac/read_write_vector.h b/include/deal.II/lac/read_write_vector.h index 70d89ade7a1c..0ed6f9d829d3 100644 --- a/include/deal.II/lac/read_write_vector.h +++ b/include/deal.II/lac/read_write_vector.h @@ -344,8 +344,8 @@ namespace LinearAlgebra * performance. */ void - import(const TpetraWrappers::Vector &tpetra_vec, - VectorOperation::values operation, + import(const TpetraWrappers::Vector &tpetra_vec, + VectorOperation::values operation, const std::shared_ptr &communication_pattern = std::shared_ptr()); @@ -615,10 +615,10 @@ namespace LinearAlgebra * used directly. */ void - import(const Tpetra::Vector<> &tpetra_vector, - const IndexSet & locally_owned_elements, - VectorOperation::values operation, - const MPI_Comm & mpi_comm, + import(const Tpetra::Vector &tpetra_vector, + const IndexSet & locally_owned_elements, + VectorOperation::values operation, + const MPI_Comm & mpi_comm, const std::shared_ptr &communication_pattern); diff --git a/include/deal.II/lac/read_write_vector.templates.h b/include/deal.II/lac/read_write_vector.templates.h index b4437cfd3fbf..87139aedd776 100644 --- a/include/deal.II/lac/read_write_vector.templates.h +++ b/include/deal.II/lac/read_write_vector.templates.h @@ -509,10 +509,10 @@ namespace LinearAlgebra template void ReadWriteVector::import( - const Tpetra::Vector<> &vector, - const IndexSet & source_elements, - VectorOperation::values operation, - const MPI_Comm & mpi_comm, + const Tpetra::Vector &vector, + const IndexSet & source_elements, + VectorOperation::values operation, + const MPI_Comm & mpi_comm, const std::shared_ptr &communication_pattern) { @@ -554,13 +554,13 @@ namespace LinearAlgebra Tpetra::Export<> tpetra_export(tpetra_comm_pattern->get_tpetra_export()); - Tpetra::Vector<> target_vector(tpetra_export.getSourceMap()); + Tpetra::Vector target_vector(tpetra_export.getSourceMap()); target_vector.doImport(vector, tpetra_export, Tpetra::REPLACE); const auto *new_values = target_vector.getData().get(); const auto size = target_vector.getLocalLength(); - using size_type = std::decay::type; + using size_type = typename std::decay::type; Assert(size == 0 || values != nullptr, ExcInternalError("Export failed.")); AssertDimension(size, stored_elements.n_elements()); @@ -741,8 +741,8 @@ namespace LinearAlgebra template void ReadWriteVector::import( - const LinearAlgebra::TpetraWrappers::Vector &trilinos_vec, - VectorOperation::values operation, + const LinearAlgebra::TpetraWrappers::Vector &trilinos_vec, + VectorOperation::values operation, const std::shared_ptr &communication_pattern) { diff --git a/include/deal.II/lac/trilinos_sparse_matrix.h b/include/deal.II/lac/trilinos_sparse_matrix.h index 006dc3171219..b158a224d493 100644 --- a/include/deal.II/lac/trilinos_sparse_matrix.h +++ b/include/deal.II/lac/trilinos_sparse_matrix.h @@ -1317,6 +1317,14 @@ namespace TrilinosWrappers * initialize the matrix with a sparsity pattern to fix the matrix * structure before inserting elements. */ + template + void + set(const size_type row, + const size_type n_cols, + const size_type *col_indices, + const Number * values, + const bool elide_zero_values = false); + void set(const size_type row, const size_type n_cols, diff --git a/include/deal.II/lac/trilinos_tpetra_vector.h b/include/deal.II/lac/trilinos_tpetra_vector.h index df0b0c99c581..798248703ab4 100644 --- a/include/deal.II/lac/trilinos_tpetra_vector.h +++ b/include/deal.II/lac/trilinos_tpetra_vector.h @@ -51,16 +51,20 @@ namespace LinearAlgebra /** * This class implements a wrapper to the Trilinos distributed vector * class Tpetra::Vector. This class is derived from the - * LinearAlgebra::VectorSpaceVector class. Note however that Tpetra only - * works with Number = double. + * LinearAlgebra::VectorSpaceVector class. * * @ingroup TrilinosWrappers * @ingroup Vectors * @author Daniel Arndt, 2018 */ - class Vector : public VectorSpaceVector, public Subscriptor + template + class Vector : public VectorSpaceVector, public Subscriptor { public: + using value_type = Number; + + using size_type = typename VectorSpaceVector::size_type; + /** * Constructor. Create a vector of dimension zero. */ @@ -97,7 +101,7 @@ namespace LinearAlgebra * copied. */ virtual void - reinit(const VectorSpaceVector &V, + reinit(const VectorSpaceVector &V, const bool omit_zeroing_entries = false) override; /** @@ -113,7 +117,7 @@ namespace LinearAlgebra * only allowed if @p s is equal to zero. */ virtual Vector & - operator=(const double s) override; + operator=(const Number s) override; /** * Imports all the elements present in the vector's IndexSet from the @@ -126,7 +130,7 @@ namespace LinearAlgebra */ virtual void import( - const ReadWriteVector & V, + const ReadWriteVector & V, VectorOperation::values operation, std::shared_ptr communication_pattern = std::shared_ptr()) override; @@ -135,64 +139,64 @@ namespace LinearAlgebra * Multiply the entire vector by a fixed factor. */ virtual Vector & - operator*=(const double factor) override; + operator*=(const Number factor) override; /** * Divide the entire vector by a fixed factor. */ virtual Vector & - operator/=(const double factor) override; + operator/=(const Number factor) override; /** * Add the vector @p V to the present one. */ virtual Vector & - operator+=(const VectorSpaceVector &V) override; + operator+=(const VectorSpaceVector &V) override; /** * Subtract the vector @p V from the present one. */ virtual Vector & - operator-=(const VectorSpaceVector &V) override; + operator-=(const VectorSpaceVector &V) override; /** * Return the scalar product of two vectors. The vectors need to have the * same layout. */ - virtual double - operator*(const VectorSpaceVector &V) const override; + virtual Number + operator*(const VectorSpaceVector &V) const override; /** * Add @p a to all components. Note that @p is a scalar not a vector. */ virtual void - add(const double a) override; + add(const Number a) override; /** * Simple addition of a multiple of a vector, i.e. *this += * a*V. The vectors need to have the same layout. */ virtual void - add(const double a, const VectorSpaceVector &V) override; + add(const Number a, const VectorSpaceVector &V) override; /** * Multiple addition of multiple of a vector, i.e. *this> += * a*V+b*W. The vectors need to have the same layout. */ virtual void - add(const double a, - const VectorSpaceVector &V, - const double b, - const VectorSpaceVector &W) override; + add(const Number a, + const VectorSpaceVector &V, + const Number b, + const VectorSpaceVector &W) override; /** * Scaling and simple addition of a multiple of a vector, i.e. *this * = s*(*this)+a*V. */ virtual void - sadd(const double s, - const double a, - const VectorSpaceVector &V) override; + sadd(const Number s, + const Number a, + const VectorSpaceVector &V) override; /** * Scale each element of this vector by the corresponding element in the @@ -201,13 +205,13 @@ namespace LinearAlgebra * vectors need to have the same layout. */ virtual void - scale(const VectorSpaceVector &scaling_factors) override; + scale(const VectorSpaceVector &scaling_factors) override; /** * Assignment *this = a*V. */ virtual void - equ(const double a, const VectorSpaceVector &V) override; + equ(const Number a, const VectorSpaceVector &V) override; /** * Return whether the vector contains only elements with value zero. @@ -218,28 +222,28 @@ namespace LinearAlgebra /** * Return the mean value of the element of this vector. */ - virtual double + virtual Number mean_value() const override; /** * Return the l1 norm of the vector (i.e., the sum of the * absolute values of all entries among all processors). */ - virtual double + virtual typename LinearAlgebra::VectorSpaceVector::real_type l1_norm() const override; /** * Return the l2 norm of the vector (i.e., the square root of * the sum of the square of all entries among all processors). */ - virtual double + virtual typename LinearAlgebra::VectorSpaceVector::real_type l2_norm() const override; /** * Return the maximum norm of the vector (i.e., the maximum absolute value * among all entries and among all processors). */ - virtual double + virtual typename LinearAlgebra::VectorSpaceVector::real_type linfty_norm() const override; /** @@ -264,10 +268,10 @@ namespace LinearAlgebra * implemented as * $\left=\sum_i v_i \bar{w_i}$. */ - virtual double - add_and_dot(const double a, - const VectorSpaceVector &V, - const VectorSpaceVector &W) override; + virtual Number + add_and_dot(const Number a, + const VectorSpaceVector &V, + const VectorSpaceVector &W) override; /** * This function always returns false and is present only for backward * compatibility. @@ -306,14 +310,14 @@ namespace LinearAlgebra * Return a const reference to the underlying Trilinos * Tpetra::Vector class. */ - const Tpetra::Vector<> & + const Tpetra::Vector & trilinos_vector() const; /** * Return a (modifyable) reference to the underlying Trilinos * Tpetra::Vector class. */ - Tpetra::Vector<> & + Tpetra::Vector & trilinos_vector(); /** @@ -367,7 +371,7 @@ namespace LinearAlgebra /** * Pointer to the actual Tpetra vector object. */ - std::unique_ptr> vector; + std::unique_ptr> vector; /** * IndexSet of the elements of the last imported vector. @@ -383,8 +387,9 @@ namespace LinearAlgebra }; + template inline bool - Vector::has_ghost_elements() const + Vector::has_ghost_elements() const { return false; } @@ -395,8 +400,9 @@ namespace LinearAlgebra /** * Declare dealii::LinearAlgebra::TpetraWrappers::Vector as distributed vector. */ -template <> -struct is_serial_vector : std::false_type +template +struct is_serial_vector> + : std::false_type {}; DEAL_II_NAMESPACE_CLOSE diff --git a/include/deal.II/lac/vector_element_access.h b/include/deal.II/lac/vector_element_access.h index b16826058885..22e541033c52 100644 --- a/include/deal.II/lac/vector_element_access.h +++ b/include/deal.II/lac/vector_element_access.h @@ -127,13 +127,13 @@ namespace internal template <> inline void - ElementAccess::add( - const double value, - const types::global_dof_index i, - LinearAlgebra::TpetraWrappers::Vector &V) + ElementAccess>::add( + const double value, + const types::global_dof_index i, + LinearAlgebra::TpetraWrappers::Vector &V) { // Extract local indices in the vector. - Tpetra::Vector<> vector = V.trilinos_vector(); + Tpetra::Vector vector = V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); @@ -144,20 +144,68 @@ namespace internal // We're going to modify the data on host. vector.modify(); vector_1d(trilinos_i) += value; - vector.sync::device_type::memory_space>(); + vector.sync::device_type::memory_space>(); } template <> inline void - ElementAccess::set( - const double value, - const types::global_dof_index i, - LinearAlgebra::TpetraWrappers::Vector &V) + ElementAccess>::add( + const float value, + const types::global_dof_index i, + LinearAlgebra::TpetraWrappers::Vector &V) + { + // Extract local indices in the vector. + Tpetra::Vector vector = V.trilinos_vector(); + TrilinosWrappers::types::int_type trilinos_i = + vector.getMap()->getLocalElement( + static_cast(i)); + + vector.sync(); + auto vector_2d = vector.getLocalView(); + auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); + // We're going to modify the data on host. + vector.modify(); + vector_1d(trilinos_i) += value; + vector.sync::device_type::memory_space>(); + } + + + + template <> + inline void + ElementAccess>::set( + const double value, + const types::global_dof_index i, + LinearAlgebra::TpetraWrappers::Vector &V) + { + // Extract local indices in the vector. + Tpetra::Vector vector = V.trilinos_vector(); + TrilinosWrappers::types::int_type trilinos_i = + vector.getMap()->getLocalElement( + static_cast(i)); + + vector.sync(); + auto vector_2d = vector.getLocalView(); + auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); + // We're going to modify the data on host. + vector.modify(); + vector_1d(trilinos_i) = value; + vector.sync::device_type::memory_space>(); + } + + + + template <> + inline void + ElementAccess>::set( + const float value, + const types::global_dof_index i, + LinearAlgebra::TpetraWrappers::Vector &V) { // Extract local indices in the vector. - Tpetra::Vector<> vector = V.trilinos_vector(); + Tpetra::Vector vector = V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); @@ -168,18 +216,40 @@ namespace internal // We're going to modify the data on host. vector.modify(); vector_1d(trilinos_i) = value; - vector.sync::device_type::memory_space>(); + vector.sync::device_type::memory_space>(); } + template <> inline double - ElementAccess::get( - const LinearAlgebra::TpetraWrappers::Vector &V, - const types::global_dof_index i) + ElementAccess>::get( + const LinearAlgebra::TpetraWrappers::Vector &V, + const types::global_dof_index i) + { + // Extract local indices in the vector. + Tpetra::Vector vector = V.trilinos_vector(); + TrilinosWrappers::types::int_type trilinos_i = + vector.getMap()->getLocalElement( + static_cast(i)); + + vector.sync(); + auto vector_2d = vector.getLocalView(); + auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); + // We're going to modify the data on host. + return vector_1d(trilinos_i); + } + + + + template <> + inline float + ElementAccess>::get( + const LinearAlgebra::TpetraWrappers::Vector &V, + const types::global_dof_index i) { // Extract local indices in the vector. - Tpetra::Vector<> vector = V.trilinos_vector(); + Tpetra::Vector vector = V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); diff --git a/include/deal.II/multigrid/mg_transfer.h b/include/deal.II/multigrid/mg_transfer.h index e4b4f3db2ac9..961b0223dfc3 100644 --- a/include/deal.II/multigrid/mg_transfer.h +++ b/include/deal.II/multigrid/mg_transfer.h @@ -132,8 +132,8 @@ namespace internal }; # ifdef DEAL_II_WITH_MPI - template <> - struct MatrixSelector + template + struct MatrixSelector> { using Sparsity = ::dealii::TrilinosWrappers::SparsityPattern; using Matrix = ::dealii::TrilinosWrappers::SparseMatrix; diff --git a/source/fe/mapping_q1_eulerian.cc b/source/fe/mapping_q1_eulerian.cc index 666a7bef6e04..3c99fb8c8336 100644 --- a/source/fe/mapping_q1_eulerian.cc +++ b/source/fe/mapping_q1_eulerian.cc @@ -77,7 +77,8 @@ MappingQ1Eulerian::get_vertices( Assert(dof_cell->active() == true, ExcInactiveCell()); // now get the values of the shift vectors at the vertices - Vector mapping_values(shiftmap_dof_handler->get_fe().dofs_per_cell); + Vector mapping_values( + shiftmap_dof_handler->get_fe().dofs_per_cell); dof_cell->get_dof_values(*euler_transform_vectors, mapping_values); for (unsigned int i = 0; i < GeometryInfo::vertices_per_cell; ++i) diff --git a/source/lac/trilinos_sparse_matrix.cc b/source/lac/trilinos_sparse_matrix.cc index 350006da3cca..0996f76053ee 100644 --- a/source/lac/trilinos_sparse_matrix.cc +++ b/source/lac/trilinos_sparse_matrix.cc @@ -48,28 +48,28 @@ namespace TrilinosWrappers namespace internal { template - double * + typename VectorType::value_type * begin(VectorType &V) { return V.begin(); } template - const double * + const typename VectorType::value_type * begin(const VectorType &V) { return V.begin(); } template - double * + typename VectorType::value_type * end(VectorType &V) { return V.end(); } template - const double * + const typename VectorType::value_type * end(const VectorType &V) { return V.end(); @@ -104,31 +104,31 @@ namespace TrilinosWrappers return V.trilinos_vector()[0] + V.trilinos_vector().MyLength(); } - template <> - double * - begin(LinearAlgebra::TpetraWrappers::Vector &V) + template + Number * + begin(LinearAlgebra::TpetraWrappers::Vector &V) { return V.trilinos_vector().getDataNonConst().get(); } - template <> - const double * - begin(const LinearAlgebra::TpetraWrappers::Vector &V) + template + const Number * + begin(const LinearAlgebra::TpetraWrappers::Vector &V) { return V.trilinos_vector().getData().get(); } - template <> - double * - end(LinearAlgebra::TpetraWrappers::Vector &V) + template + Number * + end(LinearAlgebra::TpetraWrappers::Vector &V) { return V.trilinos_vector().getDataNonConst().get() + V.trilinos_vector().getLocalLength(); } - template <> - const double * - end(const LinearAlgebra::TpetraWrappers::Vector &V) + template + const Number * + end(const LinearAlgebra::TpetraWrappers::Vector &V) { return V.trilinos_vector().getData().get() + V.trilinos_vector().getLocalLength(); @@ -1540,6 +1540,22 @@ namespace TrilinosWrappers + template + void + SparseMatrix::set(const size_type row, + const size_type n_cols, + const size_type *col_indices, + const Number * values, + const bool elide_zero_values) + { + std::vector trilinos_values(n_cols); + std::copy(values, values + n_cols, trilinos_values.begin()); + this->set( + row, n_cols, col_indices, trilinos_values.data(), elide_zero_values); + } + + + void SparseMatrix::set(const size_type row, const size_type n_cols, @@ -3476,78 +3492,98 @@ namespace TrilinosWrappers template void SparseMatrix::vmult(MPI::Vector &, const MPI::Vector &) const; + template void SparseMatrix::vmult(dealii::Vector &, const dealii::Vector &) const; + template void SparseMatrix::vmult( dealii::LinearAlgebra::distributed::Vector &, const dealii::LinearAlgebra::distributed::Vector &) const; + # ifdef DEAL_II_WITH_MPI template void SparseMatrix::vmult( - dealii::LinearAlgebra::TpetraWrappers::Vector &, - const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + + /*template void + SparseMatrix::vmult( + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const;*/ template void SparseMatrix::vmult( dealii::LinearAlgebra::EpetraWrappers::Vector &, const dealii::LinearAlgebra::EpetraWrappers::Vector &) const; # endif + template void SparseMatrix::Tvmult(MPI::Vector &, const MPI::Vector &) const; + template void SparseMatrix::Tvmult(dealii::Vector &, const dealii::Vector &) const; + template void SparseMatrix::Tvmult( dealii::LinearAlgebra::distributed::Vector &, const dealii::LinearAlgebra::distributed::Vector &) const; + # ifdef DEAL_II_WITH_MPI template void SparseMatrix::Tvmult( - dealii::LinearAlgebra::TpetraWrappers::Vector &, - const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; template void SparseMatrix::Tvmult( dealii::LinearAlgebra::EpetraWrappers::Vector &, const dealii::LinearAlgebra::EpetraWrappers::Vector &) const; # endif + template void SparseMatrix::vmult_add(MPI::Vector &, const MPI::Vector &) const; + template void SparseMatrix::vmult_add(dealii::Vector &, const dealii::Vector &) const; + template void SparseMatrix::vmult_add( dealii::LinearAlgebra::distributed::Vector &, const dealii::LinearAlgebra::distributed::Vector &) const; + # ifdef DEAL_II_WITH_MPI template void SparseMatrix::vmult_add( - dealii::LinearAlgebra::TpetraWrappers::Vector &, - const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; template void SparseMatrix::vmult_add( dealii::LinearAlgebra::EpetraWrappers::Vector &, const dealii::LinearAlgebra::EpetraWrappers::Vector &) const; # endif + template void SparseMatrix::Tvmult_add(MPI::Vector &, const MPI::Vector &) const; + template void SparseMatrix::Tvmult_add(dealii::Vector &, const dealii::Vector &) const; + template void SparseMatrix::Tvmult_add( dealii::LinearAlgebra::distributed::Vector &, const dealii::LinearAlgebra::distributed::Vector &) const; + # ifdef DEAL_II_WITH_MPI template void SparseMatrix::Tvmult_add( - dealii::LinearAlgebra::TpetraWrappers::Vector &, - const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; template void SparseMatrix::Tvmult_add( diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc index 5e3c00b53ad4..88324e6d53a7 100644 --- a/source/lac/trilinos_tpetra_vector.cc +++ b/source/lac/trilinos_tpetra_vector.cc @@ -40,37 +40,41 @@ namespace LinearAlgebra { namespace TpetraWrappers { - Vector::Vector() - : vector(new Tpetra::Vector<>(Teuchos::RCP>( + template + Vector::Vector() + : vector(new Tpetra::Vector(Teuchos::RCP>( new Tpetra::Map<>(0, 0, Utilities::Trilinos::tpetra_comm_self())))) {} - Vector::Vector(const Vector &V) + template + Vector::Vector(const Vector &V) : Subscriptor() - , vector(new Tpetra::Vector<>(V.trilinos_vector(), Teuchos::Copy)) + , vector(new Tpetra::Vector(V.trilinos_vector(), Teuchos::Copy)) {} - Vector::Vector(const IndexSet ¶llel_partitioner, - const MPI_Comm &communicator) - : vector(new Tpetra::Vector<>(Teuchos::rcp(new Tpetra::Map<>( + template + Vector::Vector(const IndexSet ¶llel_partitioner, + const MPI_Comm &communicator) + : vector(new Tpetra::Vector(Teuchos::rcp(new Tpetra::Map<>( parallel_partitioner.make_tpetra_map(communicator, false))))) {} + template void - Vector::reinit(const IndexSet ¶llel_partitioner, - const MPI_Comm &communicator, - const bool omit_zeroing_entries) + Vector::reinit(const IndexSet ¶llel_partitioner, + const MPI_Comm &communicator, + const bool omit_zeroing_entries) { Tpetra::Map<> input_map = parallel_partitioner.make_tpetra_map(communicator, false); if (vector->getMap()->isSameAs(input_map) == false) - vector = std_cxx14::make_unique>( + vector = std_cxx14::make_unique>( Teuchos::rcp(new Tpetra::Map<>(input_map))); else if (omit_zeroing_entries == false) { @@ -80,16 +84,17 @@ namespace LinearAlgebra + template void - Vector::reinit(const VectorSpaceVector &V, - const bool omit_zeroing_entries) + Vector::reinit(const VectorSpaceVector &V, + const bool omit_zeroing_entries) { // Check that casting will work. - Assert(dynamic_cast(&V) != nullptr, + Assert(dynamic_cast *>(&V) != nullptr, ExcVectorTypeNotCompatible()); // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast(V); + const Vector &down_V = dynamic_cast &>(V); reinit(down_V.locally_owned_elements(), down_V.get_mpi_communicator(), @@ -98,8 +103,9 @@ namespace LinearAlgebra - Vector & - Vector::operator=(const Vector &V) + template + Vector & + Vector::operator=(const Vector &V) { // Distinguish three cases: // - First case: both vectors have the same layout. @@ -119,8 +125,8 @@ namespace LinearAlgebra Tpetra::REPLACE); } else - vector = - std_cxx14::make_unique>(V.trilinos_vector()); + vector = std_cxx14::make_unique>( + V.trilinos_vector()); } return *this; @@ -128,10 +134,12 @@ namespace LinearAlgebra - Vector & - Vector::operator=(const double s) + template + Vector & + Vector::operator=(const Number s) { - Assert(s == 0., ExcMessage("Only 0 can be assigned to a vector.")); + Assert(s == Number(0.), + ExcMessage("Only 0 can be assigned to a vector.")); vector->putScalar(s); @@ -140,9 +148,10 @@ namespace LinearAlgebra + template void - Vector::import( - const ReadWriteVector & V, + Vector::import( + const ReadWriteVector & V, VectorOperation::values operation, std::shared_ptr communication_pattern) { @@ -177,17 +186,18 @@ namespace LinearAlgebra } Tpetra::Export<> tpetra_export(tpetra_comm_pattern->get_tpetra_export()); - Tpetra::Vector<> source_vector(tpetra_export.getSourceMap()); + Tpetra::Vector source_vector(tpetra_export.getSourceMap()); - source_vector.sync(); - auto x_2d = source_vector.getLocalView(); + source_vector.template sync(); + auto x_2d = source_vector.template getLocalView(); auto x_1d = Kokkos::subview(x_2d, Kokkos::ALL(), 0); - source_vector.modify(); + source_vector.template modify(); const size_t localLength = source_vector.getLocalLength(); auto values_it = V.begin(); for (size_t k = 0; k < localLength; ++k) x_1d(k) = *values_it++; - source_vector.sync::device_type::memory_space>(); + source_vector.template sync< + typename Tpetra::Vector::device_type::memory_space>(); if (operation == VectorOperation::insert) vector->doExport(source_vector, tpetra_export, Tpetra::REPLACE); else if (operation == VectorOperation::add) @@ -198,8 +208,9 @@ namespace LinearAlgebra - Vector & - Vector::operator*=(const double factor) + template + Vector & + Vector::operator*=(const Number factor) { AssertIsFinite(factor); vector->scale(factor); @@ -209,27 +220,29 @@ namespace LinearAlgebra - Vector & - Vector::operator/=(const double factor) + template + Vector & + Vector::operator/=(const Number factor) { AssertIsFinite(factor); - Assert(factor != 0., ExcZero()); - *this *= 1. / factor; + Assert(factor != Number(0.), ExcZero()); + *this *= Number(1.) / factor; return *this; } - Vector & - Vector::operator+=(const VectorSpaceVector &V) + template + Vector & + Vector::operator+=(const VectorSpaceVector &V) { // Check that casting will work. - Assert(dynamic_cast(&V) != nullptr, + Assert(dynamic_cast *>(&V) != nullptr, ExcVectorTypeNotCompatible()); // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast(V); + const Vector &down_V = dynamic_cast &>(V); // If the maps are the same we can Update right away. if (vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap()))) { @@ -247,8 +260,8 @@ namespace LinearAlgebra data_exchange, Tpetra::ADD);*/ - Tpetra::Vector<> dummy(vector->getMap(), false); - Tpetra::Import<> data_exchange(dummy.getMap(), + Tpetra::Vector dummy(vector->getMap(), false); + Tpetra::Import<> data_exchange(dummy.getMap(), down_V.trilinos_vector().getMap()); dummy.doExport(down_V.trilinos_vector(), @@ -263,8 +276,9 @@ namespace LinearAlgebra - Vector & - Vector::operator-=(const VectorSpaceVector &V) + template + Vector & + Vector::operator-=(const VectorSpaceVector &V) { this->add(-1., V); @@ -273,14 +287,15 @@ namespace LinearAlgebra - double Vector::operator*(const VectorSpaceVector &V) const + template + Number Vector::operator*(const VectorSpaceVector &V) const { // Check that casting will work. - Assert(dynamic_cast(&V) != nullptr, + Assert(dynamic_cast *>(&V) != nullptr, ExcVectorTypeNotCompatible()); // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast(V); + const Vector &down_V = dynamic_cast &>(V); Assert(this->size() == down_V.size(), ExcDimensionMismatch(this->size(), down_V.size())); Assert(vector->getMap()->isSameAs(*down_V.trilinos_vector().getMap()), @@ -291,34 +306,37 @@ namespace LinearAlgebra + template void - Vector::add(const double a) + Vector::add(const Number a) { AssertIsFinite(a); - vector->sync(); - auto vector_2d = vector->getLocalView(); + vector->template sync(); + auto vector_2d = vector->template getLocalView(); auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); - vector->modify(); + vector->template modify(); const size_t localLength = vector->getLocalLength(); for (size_t k = 0; k < localLength; ++k) { vector_1d(k) += a; } - vector->sync::device_type::memory_space>(); + vector->template sync< + typename Tpetra::Vector::device_type::memory_space>(); } + template void - Vector::add(const double a, const VectorSpaceVector &V) + Vector::add(const Number a, const VectorSpaceVector &V) { // Check that casting will work. - Assert(dynamic_cast(&V) != nullptr, + Assert(dynamic_cast *>(&V) != nullptr, ExcVectorTypeNotCompatible()); // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast(V); + const Vector &down_V = dynamic_cast &>(V); AssertIsFinite(a); Assert(vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap())), ExcDifferentParallelPartitioning()); @@ -328,23 +346,24 @@ namespace LinearAlgebra + template void - Vector::add(const double a, - const VectorSpaceVector &V, - const double b, - const VectorSpaceVector &W) + Vector::add(const Number a, + const VectorSpaceVector &V, + const Number b, + const VectorSpaceVector &W) { // Check that casting will work. - Assert(dynamic_cast(&V) != nullptr, + Assert(dynamic_cast *>(&V) != nullptr, ExcVectorTypeNotCompatible()); // Check that casting will work. - Assert(dynamic_cast(&W) != nullptr, + Assert(dynamic_cast *>(&W) != nullptr, ExcVectorTypeNotCompatible()); // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast(V); + const Vector &down_V = dynamic_cast &>(V); // Downcast W. If fails, throws an exception. - const Vector &down_W = dynamic_cast(W); + const Vector &down_W = dynamic_cast &>(W); Assert(vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap())), ExcDifferentParallelPartitioning()); Assert(vector->getMap()->isSameAs(*(down_W.trilinos_vector().getMap())), @@ -358,35 +377,37 @@ namespace LinearAlgebra + template void - Vector::sadd(const double s, - const double a, - const VectorSpaceVector &V) + Vector::sadd(const Number s, + const Number a, + const VectorSpaceVector &V) { // Check that casting will work. - Assert(dynamic_cast(&V) != nullptr, + Assert(dynamic_cast *>(&V) != nullptr, ExcVectorTypeNotCompatible()); *this *= s; // Downcast V. It fails, throws an exception. - const Vector &down_V = dynamic_cast(V); - Vector tmp(down_V); + const Vector &down_V = dynamic_cast &>(V); + Vector tmp(down_V); tmp *= a; *this += tmp; } + template void - Vector::scale(const VectorSpaceVector &scaling_factors) + Vector::scale(const VectorSpaceVector &scaling_factors) { // Check that casting will work. - Assert(dynamic_cast(&scaling_factors) != nullptr, + Assert(dynamic_cast *>(&scaling_factors) != nullptr, ExcVectorTypeNotCompatible()); // Downcast scaling_factors. If fails, throws an exception. - const Vector &down_scaling_factors = - dynamic_cast(scaling_factors); + const Vector &down_scaling_factors = + dynamic_cast &>(scaling_factors); Assert(vector->getMap()->isSameAs( *(down_scaling_factors.trilinos_vector().getMap())), ExcDifferentParallelPartitioning()); @@ -399,15 +420,16 @@ namespace LinearAlgebra + template void - Vector::equ(const double a, const VectorSpaceVector &V) + Vector::equ(const Number a, const VectorSpaceVector &V) { // Check that casting will work. - Assert(dynamic_cast(&V) != nullptr, + Assert(dynamic_cast *>(&V) != nullptr, ExcVectorTypeNotCompatible()); // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast(V); + const Vector &down_V = dynamic_cast &>(V); // If we don't have the same map, copy. if (vector->getMap()->isSameAs(*down_V.trilinos_vector().getMap()) == false) @@ -421,18 +443,19 @@ namespace LinearAlgebra + template bool - Vector::all_zero() const + Vector::all_zero() const { // get a representation of the vector and // loop over all the elements - double * start_ptr = vector->getDataNonConst().get(); - const double *ptr = start_ptr, + Number * start_ptr = vector->getDataNonConst().get(); + const Number *ptr = start_ptr, *eptr = start_ptr + vector->getLocalLength(); unsigned int flag = 0; while (ptr != eptr) { - if (*ptr != 0) + if (*ptr != Number(0)) { flag = 1; break; @@ -453,42 +476,47 @@ namespace LinearAlgebra - double - Vector::mean_value() const + template + Number + Vector::mean_value() const { return vector->meanValue(); } - double - Vector::l1_norm() const + template + typename LinearAlgebra::VectorSpaceVector::real_type + Vector::l1_norm() const { return vector->norm1(); } - double - Vector::l2_norm() const + template + typename LinearAlgebra::VectorSpaceVector::real_type + Vector::l2_norm() const { return vector->norm2(); } - double - Vector::linfty_norm() const + template + typename LinearAlgebra::VectorSpaceVector::real_type + Vector::linfty_norm() const { return vector->normInf(); } - double - Vector::add_and_dot(const double a, - const VectorSpaceVector &V, - const VectorSpaceVector &W) + template + Number + Vector::add_and_dot(const Number a, + const VectorSpaceVector &V, + const VectorSpaceVector &W) { this->add(a, V); @@ -497,16 +525,18 @@ namespace LinearAlgebra - Vector::size_type - Vector::size() const + template + typename Vector::size_type + Vector::size() const { return vector->getGlobalLength(); } + template MPI_Comm - Vector::get_mpi_communicator() const + Vector::get_mpi_communicator() const { const auto tpetra_comm = dynamic_cast *>( vector->getMap()->getComm().get()); @@ -516,21 +546,17 @@ namespace LinearAlgebra + template ::dealii::IndexSet - Vector::locally_owned_elements() const + Vector::locally_owned_elements() const { IndexSet is(size()); // easy case: local range is contiguous if (vector->getMap()->isContiguous()) { -# ifndef DEAL_II_WITH_64BIT_INDICES is.add_range(vector->getMap()->getMinGlobalIndex(), vector->getMap()->getMaxGlobalIndex() + 1); -# else - is.add_range(vector->getMap()->getMinGlobalIndex(), - vector->getMap()->getMaxGlobalIndex() + 1); -# endif } else if (vector->getLocalLength() > 0) { @@ -546,27 +572,30 @@ namespace LinearAlgebra - const Tpetra::Vector<> & - Vector::trilinos_vector() const + template + const Tpetra::Vector & + Vector::trilinos_vector() const { return *vector; } - Tpetra::Vector<> & - Vector::trilinos_vector() + template + Tpetra::Vector & + Vector::trilinos_vector() { return *vector; } + template void - Vector::print(std::ostream & out, - const unsigned int precision, - const bool scientific, - const bool across) const + Vector::print(std::ostream & out, + const unsigned int precision, + const bool scientific, + const bool across) const { AssertThrow(out, ExcIO()); boost::io::ios_flags_saver restore_flags(out); @@ -581,9 +610,9 @@ namespace LinearAlgebra else out.setf(std::ios::fixed, std::ios::floatfield); - vector->sync(); - auto vector_2d = vector->getLocalView(); - auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); + vector->template sync(); + auto vector_2d = vector->template getLocalView(); + auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); const size_t local_length = vector->getLocalLength(); if (across) @@ -601,25 +630,33 @@ namespace LinearAlgebra + template std::size_t - Vector::memory_consumption() const + Vector::memory_consumption() const { return sizeof(*this) + vector->getLocalLength() * - (sizeof(double) + sizeof(TrilinosWrappers::types::int_type)); + (sizeof(Number) + sizeof(TrilinosWrappers::types::int_type)); } + template void - Vector::create_tpetra_comm_pattern(const IndexSet &source_index_set, - const MPI_Comm &mpi_comm) + Vector::create_tpetra_comm_pattern(const IndexSet &source_index_set, + const MPI_Comm &mpi_comm) { source_stored_elements = source_index_set; tpetra_comm_pattern = std::make_shared( locally_owned_elements(), source_index_set, mpi_comm); } + + template class Vector; + template class Vector; + template class Vector>; + template class Vector>; + } // namespace TpetraWrappers } // namespace LinearAlgebra diff --git a/tests/trilinos/tpetra_vector_01.cc b/tests/trilinos/tpetra_vector_01.cc index c10ac87bb1e3..ba39dfa34e84 100644 --- a/tests/trilinos/tpetra_vector_01.cc +++ b/tests/trilinos/tpetra_vector_01.cc @@ -26,7 +26,7 @@ // Check LinearAlgebra::TpetraWrappers::Vector assignment and import - +template void test() { @@ -45,10 +45,10 @@ test() } parallel_partitioner_1.compress(); parallel_partitioner_2.compress(); - LinearAlgebra::TpetraWrappers::Vector a; - LinearAlgebra::TpetraWrappers::Vector b(parallel_partitioner_1, - MPI_COMM_WORLD); - LinearAlgebra::TpetraWrappers::Vector c(b); + LinearAlgebra::TpetraWrappers::Vector a; + LinearAlgebra::TpetraWrappers::Vector b(parallel_partitioner_1, + MPI_COMM_WORLD); + LinearAlgebra::TpetraWrappers::Vector c(b); AssertThrow(a.size() == 0, ExcMessage("Vector has the wrong size.")); AssertThrow(b.size() == 10, ExcMessage("Vector has the wrong size.")); @@ -69,9 +69,9 @@ test() read_write_index_set.add_range(4, 10); read_write_index_set.compress(); - LinearAlgebra::ReadWriteVector read_write_1(read_write_index_set); - LinearAlgebra::ReadWriteVector read_write_2(read_write_index_set); - LinearAlgebra::ReadWriteVector read_write_3(read_write_index_set); + LinearAlgebra::ReadWriteVector read_write_1(read_write_index_set); + LinearAlgebra::ReadWriteVector read_write_2(read_write_index_set); + LinearAlgebra::ReadWriteVector read_write_3(read_write_index_set); if (rank == 0) { for (unsigned int i = 0; i < 6; ++i) @@ -204,7 +204,7 @@ test() b.import(read_write_1, VectorOperation::insert); c.import(read_write_1, VectorOperation::insert); - const double val = b * c; + const Number val = b * c; AssertThrow(val == 285., ExcMessage("Problem in operator *.")); } @@ -217,7 +217,8 @@ main(int argc, char **argv) Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1); - test(); + test(); + test(); deallog << "OK" << std::endl; diff --git a/tests/trilinos/tpetra_vector_02.cc b/tests/trilinos/tpetra_vector_02.cc index 8e4875353044..a775c7ec3025 100644 --- a/tests/trilinos/tpetra_vector_02.cc +++ b/tests/trilinos/tpetra_vector_02.cc @@ -26,6 +26,7 @@ // Check LinearAlgebra::TpetraWrappers::Vector add and sadd. +template void test() { @@ -44,12 +45,12 @@ test() } parallel_partitioner_1.compress(); parallel_partitioner_2.compress(); - LinearAlgebra::TpetraWrappers::Vector a(parallel_partitioner_1, - MPI_COMM_WORLD); - LinearAlgebra::TpetraWrappers::Vector b(parallel_partitioner_1, - MPI_COMM_WORLD); - LinearAlgebra::TpetraWrappers::Vector c(parallel_partitioner_2, - MPI_COMM_WORLD); + LinearAlgebra::TpetraWrappers::Vector a(parallel_partitioner_1, + MPI_COMM_WORLD); + LinearAlgebra::TpetraWrappers::Vector b(parallel_partitioner_1, + MPI_COMM_WORLD); + LinearAlgebra::TpetraWrappers::Vector c(parallel_partitioner_2, + MPI_COMM_WORLD); IndexSet read_write_index_set(10); if (rank == 0) @@ -58,9 +59,9 @@ test() read_write_index_set.add_range(5, 10); read_write_index_set.compress(); - LinearAlgebra::ReadWriteVector read_write_1(read_write_index_set); - LinearAlgebra::ReadWriteVector read_write_2(read_write_index_set); - LinearAlgebra::ReadWriteVector read_write_3(read_write_index_set); + LinearAlgebra::ReadWriteVector read_write_1(read_write_index_set); + LinearAlgebra::ReadWriteVector read_write_2(read_write_index_set); + LinearAlgebra::ReadWriteVector read_write_3(read_write_index_set); if (rank == 0) { for (unsigned int i = 0; i < 5; ++i) @@ -188,14 +189,14 @@ test() AssertThrow(b.l1_norm() == 95., ExcMessage("Problem in l1_norm.")); - const double eps = 1e-6; + const Number eps = 1e-6; AssertThrow(std::fabs(b.l2_norm() - 31.3847096) < eps, ExcMessage("Problem in l2_norm")); AssertThrow(b.linfty_norm() == 14., ExcMessage("Problem in linfty_norm.")); a.import(read_write_1, VectorOperation::insert); - const double val = a.add_and_dot(2., a, b); + const Number val = a.add_and_dot(2., a, b); AssertThrow(val == 1530., ExcMessage("Problem in add_and_dot")); } @@ -208,7 +209,8 @@ main(int argc, char **argv) Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1); - test(); + test(); + test(); deallog << "OK" << std::endl; diff --git a/tests/trilinos/tpetra_vector_03.cc b/tests/trilinos/tpetra_vector_03.cc index 4927aaedb82a..650296a4913a 100644 --- a/tests/trilinos/tpetra_vector_03.cc +++ b/tests/trilinos/tpetra_vector_03.cc @@ -28,6 +28,7 @@ #include "../tests.h" +template void test() { @@ -38,7 +39,8 @@ test() locally_owned.add_range(my_id * 2, my_id * 2 + 2); locally_owned.compress(); - LinearAlgebra::TpetraWrappers::Vector v(locally_owned, MPI_COMM_WORLD); + LinearAlgebra::TpetraWrappers::Vector v(locally_owned, + MPI_COMM_WORLD); IndexSet workaround_set(n_procs * 2); unsigned int my_first_index = (my_id * 2 + 2) % (n_procs * 2); @@ -47,7 +49,7 @@ test() workaround_set.add_index(my_second_index); workaround_set.add_index(0); workaround_set.compress(); - LinearAlgebra::ReadWriteVector rw_vector(workaround_set); + LinearAlgebra::ReadWriteVector rw_vector(workaround_set); rw_vector(my_first_index) = my_id + 10; rw_vector(my_second_index) = my_id + 100; @@ -97,5 +99,6 @@ main(int argc, char **argv) argc, argv, testing_max_num_threads()); MPILogInitAll log; - test(); + test(); + test(); } diff --git a/tests/trilinos/tpetra_vector_03.mpirun=2.output b/tests/trilinos/tpetra_vector_03.mpirun=2.output index 638319c2f1c3..e94f192176bc 100644 --- a/tests/trilinos/tpetra_vector_03.mpirun=2.output +++ b/tests/trilinos/tpetra_vector_03.mpirun=2.output @@ -31,7 +31,66 @@ IndexSet: {[0,2]} [0]: 4.000e+00 [1]: 2.000e+02 [2]: 1.000e+02 +DEAL:0::Tpetra first import add: +2.000e+00 1.000e+02 +IndexSet: {[0,2]} + +[0]: 1.000e+00 +[1]: 1.000e+02 +[2]: 1.000e+01 +DEAL:0::Tpetra second import add: +4.000e+00 2.000e+02 +IndexSet: {[0,2]} + +[0]: 2.000e+00 +[1]: 2.000e+02 +[2]: 2.000e+01 +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: 6.000e+00 +[1]: 4.000e+02 +[2]: 5.000e+01 +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} +[0]: 4.000e+00 +[1]: 1.000e+00 +[2]: 3.000e+01 +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + +[0]: 4.000e+00 +[1]: 2.000e+02 +[2]: 1.000e+02 + +DEAL:1::Tpetra first import add: +1.000e+01 1.010e+02 +IndexSet: {0, 3} + +[0]: 1.000e+00 +[3]: 1.010e+02 +DEAL:1::Tpetra second import add: +3.000e+01 2.010e+02 +IndexSet: {0, 3} + +[0]: 2.000e+00 +[3]: 2.010e+02 +DEAL:1::ReadWrite import add: +IndexSet: {0, 3} + +[0]: 6.000e+00 +[3]: 4.020e+02 +DEAL:1::ReadWrite import min: +IndexSet: {0, 3} + +[0]: 4.000e+00 +[3]: 1.000e+00 +DEAL:1::ReadWrite import max: +IndexSet: {0, 3} + +[0]: 4.000e+00 +[3]: 2.010e+02 DEAL:1::Tpetra first import add: 1.000e+01 1.010e+02 IndexSet: {0, 3} diff --git a/tests/trilinos/tpetra_vector_03.mpirun=4.output b/tests/trilinos/tpetra_vector_03.mpirun=4.output index f70ed13b09e8..5fbf8dea2d1f 100644 --- a/tests/trilinos/tpetra_vector_03.mpirun=4.output +++ b/tests/trilinos/tpetra_vector_03.mpirun=4.output @@ -28,6 +28,38 @@ IndexSet: {[0,2]} DEAL:0::ReadWrite import max: IndexSet: {[0,2]} +[0]: 8.000e+00 +[1]: 2.000e+02 +[2]: 1.000e+02 +DEAL:0::Tpetra first import add: +4.000e+00 1.000e+02 +IndexSet: {[0,2]} + +[0]: 1.000e+00 +[1]: 1.000e+02 +[2]: 1.000e+01 +DEAL:0::Tpetra second import add: +8.000e+00 2.000e+02 +IndexSet: {[0,2]} + +[0]: 2.000e+00 +[1]: 2.000e+02 +[2]: 2.000e+01 +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: 1.000e+01 +[1]: 4.000e+02 +[2]: 5.000e+01 +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} + +[0]: 4.000e+00 +[1]: 1.000e+00 +[2]: 3.000e+01 +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + [0]: 8.000e+00 [1]: 2.000e+02 [2]: 1.000e+02 @@ -61,6 +93,38 @@ IndexSet: {0, [3,4]} DEAL:1::ReadWrite import max: IndexSet: {0, [3,4]} +[0]: 8.000e+00 +[3]: 2.010e+02 +[4]: 1.010e+02 +DEAL:1::Tpetra first import add: +1.000e+01 1.010e+02 +IndexSet: {0, [3,4]} + +[0]: 1.000e+00 +[3]: 1.010e+02 +[4]: 1.100e+01 +DEAL:1::Tpetra second import add: +3.000e+01 2.010e+02 +IndexSet: {0, [3,4]} + +[0]: 2.000e+00 +[3]: 2.010e+02 +[4]: 2.100e+01 +DEAL:1::ReadWrite import add: +IndexSet: {0, [3,4]} + +[0]: 1.000e+01 +[3]: 4.020e+02 +[4]: 5.300e+01 +DEAL:1::ReadWrite import min: +IndexSet: {0, [3,4]} + +[0]: 4.000e+00 +[3]: 1.000e+00 +[4]: 3.200e+01 +DEAL:1::ReadWrite import max: +IndexSet: {0, [3,4]} + [0]: 8.000e+00 [3]: 2.010e+02 [4]: 1.010e+02 @@ -98,8 +162,67 @@ IndexSet: {0, [5,6]} [0]: 8.000e+00 [5]: 2.020e+02 [6]: 1.020e+02 +DEAL:2::Tpetra first import add: +1.100e+01 1.020e+02 +IndexSet: {0, [5,6]} +[0]: 1.000e+00 +[5]: 1.020e+02 +[6]: 1.200e+01 +DEAL:2::Tpetra second import add: +3.200e+01 2.020e+02 +IndexSet: {0, [5,6]} +[0]: 2.000e+00 +[5]: 2.020e+02 +[6]: 2.200e+01 +DEAL:2::ReadWrite import add: +IndexSet: {0, [5,6]} + +[0]: 1.000e+01 +[5]: 4.040e+02 +[6]: 5.600e+01 +DEAL:2::ReadWrite import min: +IndexSet: {0, [5,6]} + +[0]: 4.000e+00 +[5]: 1.000e+00 +[6]: 3.400e+01 +DEAL:2::ReadWrite import max: +IndexSet: {0, [5,6]} + +[0]: 8.000e+00 +[5]: 2.020e+02 +[6]: 1.020e+02 + + +DEAL:3::Tpetra first import add: +1.200e+01 1.030e+02 +IndexSet: {0, 7} + +[0]: 1.000e+00 +[7]: 1.030e+02 +DEAL:3::Tpetra second import add: +3.400e+01 2.030e+02 +IndexSet: {0, 7} + +[0]: 2.000e+00 +[7]: 2.030e+02 +DEAL:3::ReadWrite import add: +IndexSet: {0, 7} + +[0]: 1.000e+01 +[7]: 4.060e+02 +DEAL:3::ReadWrite import min: +IndexSet: {0, 7} + +[0]: 4.000e+00 +[7]: 1.000e+00 +DEAL:3::ReadWrite import max: +IndexSet: {0, 7} + +[0]: 8.000e+00 +[7]: 2.030e+02 DEAL:3::Tpetra first import add: 1.200e+01 1.030e+02 IndexSet: {0, 7} From 36447358f536ab190b3c81d06616cdf718db17d7 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 14 Sep 2018 17:34:33 +0200 Subject: [PATCH 149/507] Also instantiate for value_type float --- cmake/configure/configure_2_trilinos.cmake | 2 +- include/deal.II/lac/trilinos_sparse_matrix.h | 56 ++++++++++++--- source/lac/trilinos_sparse_matrix.cc | 76 +++++++++++++------- 3 files changed, 97 insertions(+), 37 deletions(-) diff --git a/cmake/configure/configure_2_trilinos.cmake b/cmake/configure/configure_2_trilinos.cmake index 661c739b7c7f..c159fe255270 100644 --- a/cmake/configure/configure_2_trilinos.cmake +++ b/cmake/configure/configure_2_trilinos.cmake @@ -228,7 +228,7 @@ MACRO(FEATURE_TRILINOS_CONFIGURE_EXTERNAL) IF (TRILINOS_WITH_MPI) SET(DEAL_II_EXPAND_EPETRA_VECTOR "LinearAlgebra::EpetraWrappers::Vector") SET(DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE "LinearAlgebra::TpetraWrappers::Vector") - #SET(DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT "LinearAlgebra::TpetraWrappers::Vector") + SET(DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT "LinearAlgebra::TpetraWrappers::Vector") ENDIF() IF(${DEAL_II_TRILINOS_WITH_SACADO}) # Note: Only CMake 3.0 and greater support line continuation with the "\" character diff --git a/include/deal.II/lac/trilinos_sparse_matrix.h b/include/deal.II/lac/trilinos_sparse_matrix.h index b158a224d493..2ae42c5ef157 100644 --- a/include/deal.II/lac/trilinos_sparse_matrix.h +++ b/include/deal.II/lac/trilinos_sparse_matrix.h @@ -1325,13 +1325,6 @@ namespace TrilinosWrappers const Number * values, const bool elide_zero_values = false); - void - set(const size_type row, - const size_type n_cols, - const size_type * col_indices, - const TrilinosScalar *values, - const bool elide_zero_values = false); - /** * Add @p value to the element (i,j). * @@ -1588,7 +1581,13 @@ namespace TrilinosWrappers * distributed. Otherwise, an exception will be thrown. */ template - void + typename std::enable_if::value>::type + vmult(VectorType &dst, const VectorType &src) const; + + template + typename std::enable_if::value>::type vmult(VectorType &dst, const VectorType &src) const; /** @@ -1602,7 +1601,13 @@ namespace TrilinosWrappers * see the discussion about @p VectorType in vmult(). */ template - void + typename std::enable_if::value>::type + Tvmult(VectorType &dst, const VectorType &src) const; + + template + typename std::enable_if::value>::type Tvmult(VectorType &dst, const VectorType &src) const; /** @@ -2992,6 +2997,32 @@ namespace TrilinosWrappers // Inline the set() and add() functions, since they will be called // frequently, and the compiler can optimize away some unnecessary loops // when the sizes are given at compile time. + template <> + void + SparseMatrix::set(const size_type row, + const size_type n_cols, + const size_type * col_indices, + const TrilinosScalar *values, + const bool elide_zero_values); + + + + template + void + SparseMatrix::set(const size_type row, + const size_type n_cols, + const size_type *col_indices, + const Number * values, + const bool elide_zero_values) + { + std::vector trilinos_values(n_cols); + std::copy(values, values + n_cols, trilinos_values.begin()); + this->set( + row, n_cols, col_indices, trilinos_values.data(), elide_zero_values); + } + + + inline void SparseMatrix::set(const size_type i, const size_type j, @@ -3298,6 +3329,13 @@ namespace TrilinosWrappers } // namespace LinearOperatorImplementation } // namespace internal + template <> + void + SparseMatrix::set(const size_type row, + const size_type n_cols, + const size_type * col_indices, + const TrilinosScalar *values, + const bool elide_zero_values); # endif // DOXYGEN } /* namespace TrilinosWrappers */ diff --git a/source/lac/trilinos_sparse_matrix.cc b/source/lac/trilinos_sparse_matrix.cc index 0996f76053ee..250a6d051918 100644 --- a/source/lac/trilinos_sparse_matrix.cc +++ b/source/lac/trilinos_sparse_matrix.cc @@ -1540,28 +1540,13 @@ namespace TrilinosWrappers - template + template <> void - SparseMatrix::set(const size_type row, - const size_type n_cols, - const size_type *col_indices, - const Number * values, - const bool elide_zero_values) - { - std::vector trilinos_values(n_cols); - std::copy(values, values + n_cols, trilinos_values.begin()); - this->set( - row, n_cols, col_indices, trilinos_values.data(), elide_zero_values); - } - - - - void - SparseMatrix::set(const size_type row, - const size_type n_cols, - const size_type * col_indices, - const TrilinosScalar *values, - const bool elide_zero_values) + SparseMatrix::set(const size_type row, + const size_type n_cols, + const size_type * col_indices, + const TrilinosScalar *values, + const bool elide_zero_values) { AssertIndexRange(row, this->m()); @@ -2124,7 +2109,8 @@ namespace TrilinosWrappers template - void + typename std::enable_if< + std::is_same::value>::type SparseMatrix::vmult(VectorType &dst, const VectorType &src) const { Assert(&src != &dst, ExcSourceEqualsDestination()); @@ -2157,7 +2143,18 @@ namespace TrilinosWrappers template - void + typename std::enable_if< + !std::is_same::value>::type + SparseMatrix::vmult(VectorType & /*dst*/, const VectorType & /*src*/) const + { + AssertThrow(false, ExcNotImplemented()); + } + + + + template + typename std::enable_if< + std::is_same::value>::type SparseMatrix::Tvmult(VectorType &dst, const VectorType &src) const { Assert(&src != &dst, ExcSourceEqualsDestination()); @@ -2186,6 +2183,16 @@ namespace TrilinosWrappers + template + typename std::enable_if< + !std::is_same::value>::type + SparseMatrix::Tvmult(VectorType & /*dst*/, const VectorType & /*src*/) const + { + AssertThrow(false, ExcNotImplemented()); + } + + + template void SparseMatrix::vmult_add(VectorType &dst, const VectorType &src) const @@ -3508,10 +3515,10 @@ namespace TrilinosWrappers dealii::LinearAlgebra::TpetraWrappers::Vector &, const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; - /*template void - SparseMatrix::vmult( - dealii::LinearAlgebra::TpetraWrappers::Vector &, - const dealii::LinearAlgebra::TpetraWrappers::Vector &) const;*/ + template void + SparseMatrix::vmult( + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; template void SparseMatrix::vmult( @@ -3537,6 +3544,11 @@ namespace TrilinosWrappers dealii::LinearAlgebra::TpetraWrappers::Vector &, const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + template void + SparseMatrix::Tvmult( + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + template void SparseMatrix::Tvmult( dealii::LinearAlgebra::EpetraWrappers::Vector &, @@ -3561,6 +3573,11 @@ namespace TrilinosWrappers dealii::LinearAlgebra::TpetraWrappers::Vector &, const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + template void + SparseMatrix::vmult_add( + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + template void SparseMatrix::vmult_add( dealii::LinearAlgebra::EpetraWrappers::Vector &, @@ -3585,6 +3602,11 @@ namespace TrilinosWrappers dealii::LinearAlgebra::TpetraWrappers::Vector &, const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + template void + SparseMatrix::Tvmult_add( + dealii::LinearAlgebra::TpetraWrappers::Vector &, + const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; + template void SparseMatrix::Tvmult_add( dealii::LinearAlgebra::EpetraWrappers::Vector &, From 54e52a86a8ccf6c6839854db03530071bcf998cb Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 19 Sep 2018 23:54:23 +0200 Subject: [PATCH 150/507] Support older Trilinos versions --- .../lac/trilinos_tpetra_communication_pattern.h | 1 + source/base/index_set.cc | 4 ++-- source/lac/trilinos_tpetra_vector.cc | 10 +++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/deal.II/lac/trilinos_tpetra_communication_pattern.h b/include/deal.II/lac/trilinos_tpetra_communication_pattern.h index 8dc7cf787472..a3a23726fecb 100644 --- a/include/deal.II/lac/trilinos_tpetra_communication_pattern.h +++ b/include/deal.II/lac/trilinos_tpetra_communication_pattern.h @@ -25,6 +25,7 @@ # include +# include # include # include diff --git a/source/base/index_set.cc b/source/base/index_set.cc index 6fe2920ffe39..143efc6dc6b4 100644 --- a/source/base/index_set.cc +++ b/source/base/index_set.cc @@ -571,9 +571,9 @@ IndexSet::make_tpetra_map(const MPI_Comm &communicator, fill_index_vector(indices); std::vector int_indices(indices.size()); std::copy(indices.begin(), indices.end(), int_indices.begin()); + const Teuchos::ArrayView arr_view(int_indices); return Tpetra::Map<>(size(), - (n_elements() > 0 ? int_indices.data() : nullptr), - n_elements(), + arr_view, 0, # ifdef DEAL_II_WITH_MPI Teuchos::rcp(new Teuchos::MpiComm(communicator)) diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc index 88324e6d53a7..dae177f7e5c4 100644 --- a/source/lac/trilinos_tpetra_vector.cc +++ b/source/lac/trilinos_tpetra_vector.cc @@ -561,9 +561,13 @@ namespace LinearAlgebra else if (vector->getLocalLength() > 0) { const size_type n_indices = vector->getLocalLength(); - auto vector_indices = vector->getMap()->getMyGlobalIndices(); - is.add_indices((unsigned int *)&vector_indices[0], - (unsigned int *)&vector_indices[0] + n_indices); + std::vector vector_indices; + vector_indices.reserve(n_indices); + for (unsigned int i = 0; i < n_indices; ++i) + vector_indices.push_back(vector->getMap()->getGlobalElement(i)); + + is.add_indices(vector_indices.data(), + vector_indices.data() + n_indices); } is.compress(); From 633af9f85da2e17e91d29c2a9e2baedaa9b2870f Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 20 Sep 2018 16:07:40 +0200 Subject: [PATCH 151/507] Test for complex values --- tests/trilinos/tpetra_vector_01.cc | 24 +- tests/trilinos/tpetra_vector_02.cc | 34 ++- tests/trilinos/tpetra_vector_03.cc | 2 + .../trilinos/tpetra_vector_03.mpirun=2.output | 118 +++++++++ .../trilinos/tpetra_vector_03.mpirun=4.output | 246 ++++++++++++++++++ 5 files changed, 402 insertions(+), 22 deletions(-) diff --git a/tests/trilinos/tpetra_vector_01.cc b/tests/trilinos/tpetra_vector_01.cc index ba39dfa34e84..a294f785032c 100644 --- a/tests/trilinos/tpetra_vector_01.cc +++ b/tests/trilinos/tpetra_vector_01.cc @@ -147,13 +147,13 @@ test() if (rank == 0) { for (unsigned int i = 0; i < 6; ++i) - AssertThrow(2. * read_write_2[i] == read_write_3[i], + AssertThrow(Number(2.) * read_write_2[i] == read_write_3[i], ExcMessage("Problem in operator *=.")); } else { for (unsigned int i = 4; i < 10; ++i) - AssertThrow(2. * read_write_2[i] == read_write_3[i], + AssertThrow(Number(2.) * read_write_2[i] == read_write_3[i], ExcMessage("Problem in operator *=.")); } @@ -162,13 +162,13 @@ test() if (rank == 0) { for (unsigned int i = 0; i < 6; ++i) - AssertThrow(0.5 * read_write_2[i] == read_write_3[i], + AssertThrow(Number(0.5) * read_write_2[i] == read_write_3[i], ExcMessage("Problem in operator /=.")); } else { for (unsigned int i = 4; i < 10; ++i) - AssertThrow(0.5 * read_write_2[i] == read_write_3[i], + AssertThrow(Number(0.5) * read_write_2[i] == read_write_3[i], ExcMessage("Problem in operator /=.")); } @@ -177,13 +177,15 @@ test() if (rank == 0) { for (unsigned int i = 0; i < 6; ++i) - AssertThrow(2. * read_write_2[i] + read_write_1[i] == read_write_3[i], + AssertThrow(Number(2.) * read_write_2[i] + read_write_1[i] == + read_write_3[i], ExcMessage("Problem in operator +=.")); } else { for (unsigned int i = 4; i < 10; ++i) - AssertThrow(2. * read_write_2[i] + read_write_1[i] == read_write_3[i], + AssertThrow(Number(2.) * read_write_2[i] + read_write_1[i] == + read_write_3[i], ExcMessage("Problem in operator +=.")); } @@ -192,20 +194,22 @@ test() if (rank == 0) { for (unsigned int i = 0; i < 6; ++i) - AssertThrow(1.5 * read_write_2[i] + read_write_1[i] == read_write_3[i], + AssertThrow(Number(1.5) * read_write_2[i] + read_write_1[i] == + read_write_3[i], ExcMessage("Problem in operator -=.")); } else { for (unsigned int i = 4; i < 10; ++i) - AssertThrow(1.5 * read_write_2[i] + read_write_1[i] == read_write_3[i], + AssertThrow(Number(1.5) * read_write_2[i] + read_write_1[i] == + read_write_3[i], ExcMessage("Problem in operator -=.")); } b.import(read_write_1, VectorOperation::insert); c.import(read_write_1, VectorOperation::insert); const Number val = b * c; - AssertThrow(val == 285., ExcMessage("Problem in operator *.")); + AssertThrow(val == Number(285.), ExcMessage("Problem in operator *.")); } @@ -219,6 +223,8 @@ main(int argc, char **argv) test(); test(); + test>(); + test>(); deallog << "OK" << std::endl; diff --git a/tests/trilinos/tpetra_vector_02.cc b/tests/trilinos/tpetra_vector_02.cc index a775c7ec3025..41b62d9a4c33 100644 --- a/tests/trilinos/tpetra_vector_02.cc +++ b/tests/trilinos/tpetra_vector_02.cc @@ -88,13 +88,13 @@ test() if (rank == 0) { for (unsigned int i = 0; i < 5; ++i) - AssertThrow(1. + read_write_1[i] == read_write_3[i], + AssertThrow(Number(1.) + read_write_1[i] == read_write_3[i], ExcMessage("Problem in add(scalar).")); } else { for (unsigned int i = 5; i < 10; ++i) - AssertThrow(1. + read_write_1[i] == read_write_3[i], + AssertThrow(Number(1.) + read_write_1[i] == read_write_3[i], ExcMessage("Problem in add(scalar).")); } @@ -103,14 +103,16 @@ test() if (rank == 0) { for (unsigned int i = 0; i < 5; ++i) - AssertThrow(1. + read_write_1[i] + 2. * read_write_2[i] == + AssertThrow(Number(1.) + read_write_1[i] + + Number(2.) * read_write_2[i] == read_write_3[i], ExcMessage("Problem in add(scalar,Vector).")); } else { for (unsigned int i = 5; i < 10; ++i) - AssertThrow(1. + read_write_1[i] + 2. * read_write_2[i] == + AssertThrow(Number(1.) + read_write_1[i] + + Number(2.) * read_write_2[i] == read_write_3[i], ExcMessage("Problem in add(scalar,Vector).")); } @@ -122,14 +124,16 @@ test() if (rank == 0) { for (unsigned int i = 0; i < 5; ++i) - AssertThrow(4. + 4. * read_write_1[i] + 10. * read_write_2[i] == + AssertThrow(Number(4.) + Number(4.) * read_write_1[i] + + Number(10.) * read_write_2[i] == read_write_3[i], ExcMessage("Problem in add(scalar,Vector,scalar,Vector).")); } else { for (unsigned int i = 5; i < 10; ++i) - AssertThrow(4. + 4. * read_write_1[i] + 10. * read_write_2[i] == + AssertThrow(Number(4.) + Number(4.) * read_write_1[i] + + Number(10.) * read_write_2[i] == read_write_3[i], ExcMessage("Problem in add(scalar,Vector,scalar,Vector).")); } @@ -141,14 +145,16 @@ test() if (rank == 0) { for (unsigned int i = 0; i < 5; ++i) - AssertThrow(3. * read_write_1[i] + 2. * read_write_2[i] == + AssertThrow(Number(3.) * read_write_1[i] + + Number(2.) * read_write_2[i] == read_write_3[i], ExcMessage("Problem in sadd(scalar,scalar,Vector).")); } else { for (unsigned int i = 5; i < 10; ++i) - AssertThrow(3. * read_write_1[i] + 2. * read_write_2[i] == + AssertThrow(Number(3.) * read_write_1[i] + + Number(2.) * read_write_2[i] == read_write_3[i], ExcMessage("Problem in sadd(scalar,scalar,Vector).")); } @@ -176,28 +182,28 @@ test() if (rank == 0) { for (unsigned int i = 0; i < 5; ++i) - AssertThrow(2. * read_write_2[i] == read_write_3[i], + AssertThrow(Number(2.) * read_write_2[i] == read_write_3[i], ExcMessage("Problem in scale.")); } else { for (unsigned int i = 5; i < 10; ++i) - AssertThrow(2. * read_write_2[i] == read_write_3[i], + AssertThrow((Number)2. * read_write_2[i] == read_write_3[i], ExcMessage("Problem in equ.")); } AssertThrow(b.l1_norm() == 95., ExcMessage("Problem in l1_norm.")); - const Number eps = 1e-6; - AssertThrow(std::fabs(b.l2_norm() - 31.3847096) < eps, + const double eps = 1e-6; + AssertThrow(std::fabs(b.l2_norm() - Number(31.3847096)) < eps, ExcMessage("Problem in l2_norm")); AssertThrow(b.linfty_norm() == 14., ExcMessage("Problem in linfty_norm.")); a.import(read_write_1, VectorOperation::insert); const Number val = a.add_and_dot(2., a, b); - AssertThrow(val == 1530., ExcMessage("Problem in add_and_dot")); + AssertThrow(val == Number(1530.), ExcMessage("Problem in add_and_dot")); } @@ -211,6 +217,8 @@ main(int argc, char **argv) test(); test(); + test>(); + test>(); deallog << "OK" << std::endl; diff --git a/tests/trilinos/tpetra_vector_03.cc b/tests/trilinos/tpetra_vector_03.cc index 650296a4913a..d97b8ce13ad2 100644 --- a/tests/trilinos/tpetra_vector_03.cc +++ b/tests/trilinos/tpetra_vector_03.cc @@ -101,4 +101,6 @@ main(int argc, char **argv) MPILogInitAll log; test(); test(); + test>(); + test>(); } diff --git a/tests/trilinos/tpetra_vector_03.mpirun=2.output b/tests/trilinos/tpetra_vector_03.mpirun=2.output index e94f192176bc..0a598a5c3b1a 100644 --- a/tests/trilinos/tpetra_vector_03.mpirun=2.output +++ b/tests/trilinos/tpetra_vector_03.mpirun=2.output @@ -63,6 +63,70 @@ IndexSet: {[0,2]} [0]: 4.000e+00 [1]: 2.000e+02 [2]: 1.000e+02 +DEAL:0::Tpetra first import add: +(2.000e+00,0.000e+00) (1.000e+02,0.000e+00) +IndexSet: {[0,2]} + +[0]: (1.000e+00,0.000e+00) +[1]: (1.000e+02,0.000e+00) +[2]: (1.000e+01,0.000e+00) +DEAL:0::Tpetra second import add: +(4.000e+00,0.000e+00) (2.000e+02,0.000e+00) +IndexSet: {[0,2]} + +[0]: (2.000e+00,0.000e+00) +[1]: (2.000e+02,0.000e+00) +[2]: (2.000e+01,0.000e+00) +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: (6.000e+00,0.000e+00) +[1]: (4.000e+02,0.000e+00) +[2]: (5.000e+01,0.000e+00) +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} + +[0]: (4.000e+00,0.000e+00) +[1]: (1.000e+00,0.000e+00) +[2]: (3.000e+01,0.000e+00) +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + +[0]: (4.000e+00,0.000e+00) +[1]: (2.000e+02,0.000e+00) +[2]: (1.000e+02,0.000e+00) +DEAL:0::Tpetra first import add: +(2.000e+00,0.000e+00) (1.000e+02,0.000e+00) +IndexSet: {[0,2]} + +[0]: (1.000e+00,0.000e+00) +[1]: (1.000e+02,0.000e+00) +[2]: (1.000e+01,0.000e+00) +DEAL:0::Tpetra second import add: +(4.000e+00,0.000e+00) (2.000e+02,0.000e+00) +IndexSet: {[0,2]} + +[0]: (2.000e+00,0.000e+00) +[1]: (2.000e+02,0.000e+00) +[2]: (2.000e+01,0.000e+00) +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: (6.000e+00,0.000e+00) +[1]: (4.000e+02,0.000e+00) +[2]: (5.000e+01,0.000e+00) +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} + +[0]: (4.000e+00,0.000e+00) +[1]: (1.000e+00,0.000e+00) +[2]: (3.000e+01,0.000e+00) +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + +[0]: (4.000e+00,0.000e+00) +[1]: (2.000e+02,0.000e+00) +[2]: (1.000e+02,0.000e+00) DEAL:1::Tpetra first import add: 1.000e+01 1.010e+02 @@ -118,4 +182,58 @@ IndexSet: {0, 3} [0]: 4.000e+00 [3]: 2.010e+02 +DEAL:1::Tpetra first import add: +(1.000e+01,0.000e+00) (1.010e+02,0.000e+00) +IndexSet: {0, 3} + +[0]: (1.000e+00,0.000e+00) +[3]: (1.010e+02,0.000e+00) +DEAL:1::Tpetra second import add: +(3.000e+01,0.000e+00) (2.010e+02,0.000e+00) +IndexSet: {0, 3} + +[0]: (2.000e+00,0.000e+00) +[3]: (2.010e+02,0.000e+00) +DEAL:1::ReadWrite import add: +IndexSet: {0, 3} + +[0]: (6.000e+00,0.000e+00) +[3]: (4.020e+02,0.000e+00) +DEAL:1::ReadWrite import min: +IndexSet: {0, 3} + +[0]: (4.000e+00,0.000e+00) +[3]: (1.000e+00,0.000e+00) +DEAL:1::ReadWrite import max: +IndexSet: {0, 3} + +[0]: (4.000e+00,0.000e+00) +[3]: (2.010e+02,0.000e+00) +DEAL:1::Tpetra first import add: +(1.000e+01,0.000e+00) (1.010e+02,0.000e+00) +IndexSet: {0, 3} + +[0]: (1.000e+00,0.000e+00) +[3]: (1.010e+02,0.000e+00) +DEAL:1::Tpetra second import add: +(3.000e+01,0.000e+00) (2.010e+02,0.000e+00) +IndexSet: {0, 3} + +[0]: (2.000e+00,0.000e+00) +[3]: (2.010e+02,0.000e+00) +DEAL:1::ReadWrite import add: +IndexSet: {0, 3} + +[0]: (6.000e+00,0.000e+00) +[3]: (4.020e+02,0.000e+00) +DEAL:1::ReadWrite import min: +IndexSet: {0, 3} + +[0]: (4.000e+00,0.000e+00) +[3]: (1.000e+00,0.000e+00) +DEAL:1::ReadWrite import max: +IndexSet: {0, 3} + +[0]: (4.000e+00,0.000e+00) +[3]: (2.010e+02,0.000e+00) diff --git a/tests/trilinos/tpetra_vector_03.mpirun=4.output b/tests/trilinos/tpetra_vector_03.mpirun=4.output index 5fbf8dea2d1f..a65e3464e6e7 100644 --- a/tests/trilinos/tpetra_vector_03.mpirun=4.output +++ b/tests/trilinos/tpetra_vector_03.mpirun=4.output @@ -63,6 +63,70 @@ IndexSet: {[0,2]} [0]: 8.000e+00 [1]: 2.000e+02 [2]: 1.000e+02 +DEAL:0::Tpetra first import add: +(4.000e+00,0.000e+00) (1.000e+02,0.000e+00) +IndexSet: {[0,2]} + +[0]: (1.000e+00,0.000e+00) +[1]: (1.000e+02,0.000e+00) +[2]: (1.000e+01,0.000e+00) +DEAL:0::Tpetra second import add: +(8.000e+00,0.000e+00) (2.000e+02,0.000e+00) +IndexSet: {[0,2]} + +[0]: (2.000e+00,0.000e+00) +[1]: (2.000e+02,0.000e+00) +[2]: (2.000e+01,0.000e+00) +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: (1.000e+01,0.000e+00) +[1]: (4.000e+02,0.000e+00) +[2]: (5.000e+01,0.000e+00) +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} + +[0]: (4.000e+00,0.000e+00) +[1]: (1.000e+00,0.000e+00) +[2]: (3.000e+01,0.000e+00) +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + +[0]: (8.000e+00,0.000e+00) +[1]: (2.000e+02,0.000e+00) +[2]: (1.000e+02,0.000e+00) +DEAL:0::Tpetra first import add: +(4.000e+00,0.000e+00) (1.000e+02,0.000e+00) +IndexSet: {[0,2]} + +[0]: (1.000e+00,0.000e+00) +[1]: (1.000e+02,0.000e+00) +[2]: (1.000e+01,0.000e+00) +DEAL:0::Tpetra second import add: +(8.000e+00,0.000e+00) (2.000e+02,0.000e+00) +IndexSet: {[0,2]} + +[0]: (2.000e+00,0.000e+00) +[1]: (2.000e+02,0.000e+00) +[2]: (2.000e+01,0.000e+00) +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: (1.000e+01,0.000e+00) +[1]: (4.000e+02,0.000e+00) +[2]: (5.000e+01,0.000e+00) +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} + +[0]: (4.000e+00,0.000e+00) +[1]: (1.000e+00,0.000e+00) +[2]: (3.000e+01,0.000e+00) +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + +[0]: (8.000e+00,0.000e+00) +[1]: (2.000e+02,0.000e+00) +[2]: (1.000e+02,0.000e+00) DEAL:1::Tpetra first import add: 1.000e+01 1.010e+02 @@ -128,6 +192,70 @@ IndexSet: {0, [3,4]} [0]: 8.000e+00 [3]: 2.010e+02 [4]: 1.010e+02 +DEAL:1::Tpetra first import add: +(1.000e+01,0.000e+00) (1.010e+02,0.000e+00) +IndexSet: {0, [3,4]} + +[0]: (1.000e+00,0.000e+00) +[3]: (1.010e+02,0.000e+00) +[4]: (1.100e+01,0.000e+00) +DEAL:1::Tpetra second import add: +(3.000e+01,0.000e+00) (2.010e+02,0.000e+00) +IndexSet: {0, [3,4]} + +[0]: (2.000e+00,0.000e+00) +[3]: (2.010e+02,0.000e+00) +[4]: (2.100e+01,0.000e+00) +DEAL:1::ReadWrite import add: +IndexSet: {0, [3,4]} + +[0]: (1.000e+01,0.000e+00) +[3]: (4.020e+02,0.000e+00) +[4]: (5.300e+01,0.000e+00) +DEAL:1::ReadWrite import min: +IndexSet: {0, [3,4]} + +[0]: (4.000e+00,0.000e+00) +[3]: (1.000e+00,0.000e+00) +[4]: (3.200e+01,0.000e+00) +DEAL:1::ReadWrite import max: +IndexSet: {0, [3,4]} + +[0]: (8.000e+00,0.000e+00) +[3]: (2.010e+02,0.000e+00) +[4]: (1.010e+02,0.000e+00) +DEAL:1::Tpetra first import add: +(1.000e+01,0.000e+00) (1.010e+02,0.000e+00) +IndexSet: {0, [3,4]} + +[0]: (1.000e+00,0.000e+00) +[3]: (1.010e+02,0.000e+00) +[4]: (1.100e+01,0.000e+00) +DEAL:1::Tpetra second import add: +(3.000e+01,0.000e+00) (2.010e+02,0.000e+00) +IndexSet: {0, [3,4]} + +[0]: (2.000e+00,0.000e+00) +[3]: (2.010e+02,0.000e+00) +[4]: (2.100e+01,0.000e+00) +DEAL:1::ReadWrite import add: +IndexSet: {0, [3,4]} + +[0]: (1.000e+01,0.000e+00) +[3]: (4.020e+02,0.000e+00) +[4]: (5.300e+01,0.000e+00) +DEAL:1::ReadWrite import min: +IndexSet: {0, [3,4]} + +[0]: (4.000e+00,0.000e+00) +[3]: (1.000e+00,0.000e+00) +[4]: (3.200e+01,0.000e+00) +DEAL:1::ReadWrite import max: +IndexSet: {0, [3,4]} + +[0]: (8.000e+00,0.000e+00) +[3]: (2.010e+02,0.000e+00) +[4]: (1.010e+02,0.000e+00) DEAL:2::Tpetra first import add: @@ -194,6 +322,70 @@ IndexSet: {0, [5,6]} [0]: 8.000e+00 [5]: 2.020e+02 [6]: 1.020e+02 +DEAL:2::Tpetra first import add: +(1.100e+01,0.000e+00) (1.020e+02,0.000e+00) +IndexSet: {0, [5,6]} + +[0]: (1.000e+00,0.000e+00) +[5]: (1.020e+02,0.000e+00) +[6]: (1.200e+01,0.000e+00) +DEAL:2::Tpetra second import add: +(3.200e+01,0.000e+00) (2.020e+02,0.000e+00) +IndexSet: {0, [5,6]} + +[0]: (2.000e+00,0.000e+00) +[5]: (2.020e+02,0.000e+00) +[6]: (2.200e+01,0.000e+00) +DEAL:2::ReadWrite import add: +IndexSet: {0, [5,6]} + +[0]: (1.000e+01,0.000e+00) +[5]: (4.040e+02,0.000e+00) +[6]: (5.600e+01,0.000e+00) +DEAL:2::ReadWrite import min: +IndexSet: {0, [5,6]} + +[0]: (4.000e+00,0.000e+00) +[5]: (1.000e+00,0.000e+00) +[6]: (3.400e+01,0.000e+00) +DEAL:2::ReadWrite import max: +IndexSet: {0, [5,6]} + +[0]: (8.000e+00,0.000e+00) +[5]: (2.020e+02,0.000e+00) +[6]: (1.020e+02,0.000e+00) +DEAL:2::Tpetra first import add: +(1.100e+01,0.000e+00) (1.020e+02,0.000e+00) +IndexSet: {0, [5,6]} + +[0]: (1.000e+00,0.000e+00) +[5]: (1.020e+02,0.000e+00) +[6]: (1.200e+01,0.000e+00) +DEAL:2::Tpetra second import add: +(3.200e+01,0.000e+00) (2.020e+02,0.000e+00) +IndexSet: {0, [5,6]} + +[0]: (2.000e+00,0.000e+00) +[5]: (2.020e+02,0.000e+00) +[6]: (2.200e+01,0.000e+00) +DEAL:2::ReadWrite import add: +IndexSet: {0, [5,6]} + +[0]: (1.000e+01,0.000e+00) +[5]: (4.040e+02,0.000e+00) +[6]: (5.600e+01,0.000e+00) +DEAL:2::ReadWrite import min: +IndexSet: {0, [5,6]} + +[0]: (4.000e+00,0.000e+00) +[5]: (1.000e+00,0.000e+00) +[6]: (3.400e+01,0.000e+00) +DEAL:2::ReadWrite import max: +IndexSet: {0, [5,6]} + +[0]: (8.000e+00,0.000e+00) +[5]: (2.020e+02,0.000e+00) +[6]: (1.020e+02,0.000e+00) DEAL:3::Tpetra first import add: @@ -250,4 +442,58 @@ IndexSet: {0, 7} [0]: 8.000e+00 [7]: 2.030e+02 +DEAL:3::Tpetra first import add: +(1.200e+01,0.000e+00) (1.030e+02,0.000e+00) +IndexSet: {0, 7} + +[0]: (1.000e+00,0.000e+00) +[7]: (1.030e+02,0.000e+00) +DEAL:3::Tpetra second import add: +(3.400e+01,0.000e+00) (2.030e+02,0.000e+00) +IndexSet: {0, 7} + +[0]: (2.000e+00,0.000e+00) +[7]: (2.030e+02,0.000e+00) +DEAL:3::ReadWrite import add: +IndexSet: {0, 7} + +[0]: (1.000e+01,0.000e+00) +[7]: (4.060e+02,0.000e+00) +DEAL:3::ReadWrite import min: +IndexSet: {0, 7} + +[0]: (4.000e+00,0.000e+00) +[7]: (1.000e+00,0.000e+00) +DEAL:3::ReadWrite import max: +IndexSet: {0, 7} + +[0]: (8.000e+00,0.000e+00) +[7]: (2.030e+02,0.000e+00) +DEAL:3::Tpetra first import add: +(1.200e+01,0.000e+00) (1.030e+02,0.000e+00) +IndexSet: {0, 7} + +[0]: (1.000e+00,0.000e+00) +[7]: (1.030e+02,0.000e+00) +DEAL:3::Tpetra second import add: +(3.400e+01,0.000e+00) (2.030e+02,0.000e+00) +IndexSet: {0, 7} + +[0]: (2.000e+00,0.000e+00) +[7]: (2.030e+02,0.000e+00) +DEAL:3::ReadWrite import add: +IndexSet: {0, 7} + +[0]: (1.000e+01,0.000e+00) +[7]: (4.060e+02,0.000e+00) +DEAL:3::ReadWrite import min: +IndexSet: {0, 7} + +[0]: (4.000e+00,0.000e+00) +[7]: (1.000e+00,0.000e+00) +DEAL:3::ReadWrite import max: +IndexSet: {0, 7} + +[0]: (8.000e+00,0.000e+00) +[7]: (2.030e+02,0.000e+00) From 282be8824a15c0d7f07f0a7e872e81af8ab5f44e Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 20 Sep 2018 21:39:06 +0200 Subject: [PATCH 152/507] Update external Trilinos documentation --- doc/external-libs/trilinos.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/external-libs/trilinos.html b/doc/external-libs/trilinos.html index d950f55b11c0..4e3a51552298 100644 --- a/doc/external-libs/trilinos.html +++ b/doc/external-libs/trilinos.html @@ -94,6 +94,8 @@
    Installing Trilinos
    -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 \ From 5717ffc1dbccb0c89af777e7d2bf00e1d004d715 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 4 Oct 2018 05:26:55 +0200 Subject: [PATCH 153/507] Fix test --- tests/trilinos/tpetra_vector_02.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/trilinos/tpetra_vector_02.cc b/tests/trilinos/tpetra_vector_02.cc index 41b62d9a4c33..132231491b18 100644 --- a/tests/trilinos/tpetra_vector_02.cc +++ b/tests/trilinos/tpetra_vector_02.cc @@ -118,7 +118,7 @@ test() } - LinearAlgebra::TpetraWrappers::Vector d(a); + LinearAlgebra::TpetraWrappers::Vector d(a); a.add(2., b, 3., d); read_write_3.import(a, VectorOperation::insert); if (rank == 0) From 3f9e73ecf3fb88a82360a0bcb36b4d201c482411 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 5 Oct 2018 06:40:56 +0200 Subject: [PATCH 154/507] Use definition headers instead of declaration headers --- source/lac/trilinos_tpetra_vector.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc index dae177f7e5c4..264f21da77c9 100644 --- a/source/lac/trilinos_tpetra_vector.cc +++ b/source/lac/trilinos_tpetra_vector.cc @@ -28,8 +28,8 @@ # include # include -# include -# include +# include +# include # include @@ -660,7 +660,6 @@ namespace LinearAlgebra template class Vector; template class Vector>; template class Vector>; - } // namespace TpetraWrappers } // namespace LinearAlgebra From f1f9065aa3aee80ed59e8bb1c5eb40364cac1084 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 7 Oct 2018 04:37:41 +0200 Subject: [PATCH 155/507] Adress Wolfgang's comments a.k.a add more documentation and switches --- include/deal.II/base/utilities.h | 8 ++++ .../deal.II/lac/read_write_vector.templates.h | 45 ++++++++++--------- include/deal.II/lac/trilinos_sparse_matrix.h | 16 +++++++ source/base/utilities.cc | 2 + 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/include/deal.II/base/utilities.h b/include/deal.II/base/utilities.h index 71d05faf24ea..dc7414587e54 100644 --- a/include/deal.II/base/utilities.h +++ b/include/deal.II/base/utilities.h @@ -888,6 +888,14 @@ namespace Utilities const Epetra_Comm & comm_self(); + /** + * Return a Teuchos::Comm object needed for creation of Tpetra::Maps. + * + * If deal.II has been configured to use a compiler that does not support + * MPI then the resulting communicator will be a serial one. Otherwise, + * the communicator will correspond to MPI_COMM_SELF, i.e. a communicator + * that comprises only this one processor. + */ const Teuchos::RCP> & tpetra_comm_self(); diff --git a/include/deal.II/lac/read_write_vector.templates.h b/include/deal.II/lac/read_write_vector.templates.h index 87139aedd776..9da3c32e68e0 100644 --- a/include/deal.II/lac/read_write_vector.templates.h +++ b/include/deal.II/lac/read_write_vector.templates.h @@ -565,30 +565,33 @@ namespace LinearAlgebra Assert(size == 0 || values != nullptr, ExcInternalError("Export failed.")); AssertDimension(size, stored_elements.n_elements()); - if (operation == VectorOperation::insert) - { - for (size_type i = 0; i < size; ++i) - values[i] = new_values[i]; - } - else if (operation == VectorOperation::add) - { - for (size_type i = 0; i < size; ++i) - values[i] += new_values[i]; - } - else if (operation == VectorOperation::min) + switch (operation) { - for (size_type i = 0; i < size; ++i) - if (std::real(new_values[i]) - std::real(values[i]) < 0.0) - values[i] = new_values[i]; - } - else if (operation == VectorOperation::max) - { - for (size_type i = 0; i < size; ++i) - if (std::real(new_values[i]) - std::real(values[i]) > 0.0) + case VectorOperation::insert: + for (size_type i = 0; i < size; ++i) values[i] = new_values[i]; + break; + + case VectorOperation::add: + for (size_type i = 0; i < size; ++i) + values[i] += new_values[i]; + break; + + case VectorOperation::min: + for (size_type i = 0; i < size; ++i) + if (std::real(new_values[i]) - std::real(values[i]) < 0.0) + values[i] = new_values[i]; + break; + + case VectorOperation::max: + for (size_type i = 0; i < size; ++i) + if (std::real(new_values[i]) - std::real(values[i]) > 0.0) + values[i] = new_values[i]; + break; + + default: + AssertThrow(false, ExcNotImplemented()); } - else - AssertThrow(false, ExcNotImplemented()); } diff --git a/include/deal.II/lac/trilinos_sparse_matrix.h b/include/deal.II/lac/trilinos_sparse_matrix.h index 2ae42c5ef157..368fc70a12d4 100644 --- a/include/deal.II/lac/trilinos_sparse_matrix.h +++ b/include/deal.II/lac/trilinos_sparse_matrix.h @@ -1576,6 +1576,9 @@ namespace TrilinosWrappers * initialized with the same IndexSet that was used for the column indices * of the matrix. * + * This function will be called when the underlying number type for the + * matrix object and the one one for the vector object are the same. + * * In case of a serial vector, this function will only work when * running on one processor, since the matrix object is inherently * distributed. Otherwise, an exception will be thrown. @@ -1585,6 +1588,11 @@ namespace TrilinosWrappers TrilinosScalar>::value>::type vmult(VectorType &dst, const VectorType &src) const; + /** + * Same as the function above for the case that the underlying number type + * for the matrix object and the one for the vector object do not coincide. + * This case is not implemented. Calling it will result in an runtime error. + */ template typename std::enable_if::value>::type @@ -1599,12 +1607,20 @@ namespace TrilinosWrappers * * This function can be called with several types of vector objects, * see the discussion about @p VectorType in vmult(). + * + * This function will be called when the underlying number type for the + * matrix object and the one one for the vector object are the same. */ template typename std::enable_if::value>::type Tvmult(VectorType &dst, const VectorType &src) const; + /** + * Same as the function above for the case that the underlying number type + * for the matrix object and the one for the vector object do not coincide. + * This case is not implemented. Calling it will result in an runtime error. + */ template typename std::enable_if::value>::type diff --git a/source/base/utilities.cc b/source/base/utilities.cc index ff4d0d957322..d5f120192bf6 100644 --- a/source/base/utilities.cc +++ b/source/base/utilities.cc @@ -993,6 +993,8 @@ namespace Utilities return communicator; } + + const Epetra_Comm & comm_self() { From a557e238cbe3b30ca12afb24b56bc1b8a977f6b5 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 2 Nov 2018 19:59:37 +0100 Subject: [PATCH 156/507] Use correct template parameters also for 64bit-indices --- include/deal.II/base/index_set.h | 2 +- include/deal.II/lac/read_write_vector.h | 13 +++-- .../deal.II/lac/read_write_vector.templates.h | 14 +++-- .../trilinos_tpetra_communication_pattern.h | 10 ++-- include/deal.II/lac/trilinos_tpetra_vector.h | 7 ++- include/deal.II/lac/vector_element_access.h | 30 ++++++---- source/base/index_set.cc | 28 ++++----- .../trilinos_tpetra_communication_pattern.cc | 22 +++---- source/lac/trilinos_tpetra_vector.cc | 58 ++++++++++++------- 9 files changed, 109 insertions(+), 75 deletions(-) diff --git a/include/deal.II/base/index_set.h b/include/deal.II/base/index_set.h index 2e21fab64498..afb90fe2d784 100644 --- a/include/deal.II/base/index_set.h +++ b/include/deal.II/base/index_set.h @@ -448,7 +448,7 @@ class IndexSet make_trilinos_map(const MPI_Comm &communicator = MPI_COMM_WORLD, const bool overlapping = false) const; - Tpetra::Map<> + Tpetra::Map make_tpetra_map(const MPI_Comm &communicator = MPI_COMM_WORLD, const bool overlapping = false) const; #endif diff --git a/include/deal.II/lac/read_write_vector.h b/include/deal.II/lac/read_write_vector.h index 0ed6f9d829d3..b72a95eae233 100644 --- a/include/deal.II/lac/read_write_vector.h +++ b/include/deal.II/lac/read_write_vector.h @@ -615,12 +615,13 @@ namespace LinearAlgebra * used directly. */ void - import(const Tpetra::Vector &tpetra_vector, - const IndexSet & locally_owned_elements, - VectorOperation::values operation, - const MPI_Comm & mpi_comm, - const std::shared_ptr - &communication_pattern); + import( + const Tpetra::Vector &tpetra_vector, + const IndexSet & locally_owned_elements, + VectorOperation::values operation, + const MPI_Comm & mpi_comm, + const std::shared_ptr + &communication_pattern); /** * Import all the elements present in the vector's IndexSet from the input diff --git a/include/deal.II/lac/read_write_vector.templates.h b/include/deal.II/lac/read_write_vector.templates.h index 9da3c32e68e0..572c28f1dec9 100644 --- a/include/deal.II/lac/read_write_vector.templates.h +++ b/include/deal.II/lac/read_write_vector.templates.h @@ -509,10 +509,10 @@ namespace LinearAlgebra template void ReadWriteVector::import( - const Tpetra::Vector &vector, - const IndexSet & source_elements, - VectorOperation::values operation, - const MPI_Comm & mpi_comm, + const Tpetra::Vector &vector, + const IndexSet & source_elements, + VectorOperation::values operation, + const MPI_Comm & mpi_comm, const std::shared_ptr &communication_pattern) { @@ -552,9 +552,11 @@ namespace LinearAlgebra "LinearAlgebra::TpetraWrappers::CommunicationPattern.")); } - Tpetra::Export<> tpetra_export(tpetra_comm_pattern->get_tpetra_export()); + Tpetra::Export tpetra_export( + tpetra_comm_pattern->get_tpetra_export()); - Tpetra::Vector target_vector(tpetra_export.getSourceMap()); + Tpetra::Vector target_vector( + tpetra_export.getSourceMap()); target_vector.doImport(vector, tpetra_export, Tpetra::REPLACE); const auto *new_values = target_vector.getData().get(); diff --git a/include/deal.II/lac/trilinos_tpetra_communication_pattern.h b/include/deal.II/lac/trilinos_tpetra_communication_pattern.h index a3a23726fecb..fd3e074b2aa9 100644 --- a/include/deal.II/lac/trilinos_tpetra_communication_pattern.h +++ b/include/deal.II/lac/trilinos_tpetra_communication_pattern.h @@ -70,13 +70,13 @@ namespace LinearAlgebra /** * Return the underlying Tpetra::Import object. */ - const Tpetra::Import<> & + const Tpetra::Import & get_tpetra_import() const; /** * Return the underlying Tpetra::Export object. */ - const Tpetra::Export<> & + const Tpetra::Export & get_tpetra_export() const; private: @@ -88,12 +88,14 @@ namespace LinearAlgebra /** * Shared pointer to the Tpetra::Import object used. */ - std::unique_ptr> tpetra_import; + std::unique_ptr> + tpetra_import; /** * Shared pointer to the Tpetra::Export object used. */ - std::unique_ptr> tpetra_export; + std::unique_ptr> + tpetra_export; }; } // end of namespace TpetraWrappers } // end of namespace LinearAlgebra diff --git a/include/deal.II/lac/trilinos_tpetra_vector.h b/include/deal.II/lac/trilinos_tpetra_vector.h index 798248703ab4..911863c9d99e 100644 --- a/include/deal.II/lac/trilinos_tpetra_vector.h +++ b/include/deal.II/lac/trilinos_tpetra_vector.h @@ -310,14 +310,14 @@ namespace LinearAlgebra * Return a const reference to the underlying Trilinos * Tpetra::Vector class. */ - const Tpetra::Vector & + const Tpetra::Vector & trilinos_vector() const; /** * Return a (modifyable) reference to the underlying Trilinos * Tpetra::Vector class. */ - Tpetra::Vector & + Tpetra::Vector & trilinos_vector(); /** @@ -371,7 +371,8 @@ namespace LinearAlgebra /** * Pointer to the actual Tpetra vector object. */ - std::unique_ptr> vector; + std::unique_ptr> + vector; /** * IndexSet of the elements of the last imported vector. diff --git a/include/deal.II/lac/vector_element_access.h b/include/deal.II/lac/vector_element_access.h index 22e541033c52..4a81d97fdbc1 100644 --- a/include/deal.II/lac/vector_element_access.h +++ b/include/deal.II/lac/vector_element_access.h @@ -133,7 +133,8 @@ namespace internal LinearAlgebra::TpetraWrappers::Vector &V) { // Extract local indices in the vector. - Tpetra::Vector vector = V.trilinos_vector(); + Tpetra::Vector vector = + V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); @@ -144,7 +145,8 @@ namespace internal // We're going to modify the data on host. vector.modify(); vector_1d(trilinos_i) += value; - vector.sync::device_type::memory_space>(); + vector.sync:: + device_type::memory_space>(); } @@ -157,7 +159,8 @@ namespace internal LinearAlgebra::TpetraWrappers::Vector &V) { // Extract local indices in the vector. - Tpetra::Vector vector = V.trilinos_vector(); + Tpetra::Vector vector = + V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); @@ -168,7 +171,8 @@ namespace internal // We're going to modify the data on host. vector.modify(); vector_1d(trilinos_i) += value; - vector.sync::device_type::memory_space>(); + vector.sync:: + device_type::memory_space>(); } @@ -181,7 +185,8 @@ namespace internal LinearAlgebra::TpetraWrappers::Vector &V) { // Extract local indices in the vector. - Tpetra::Vector vector = V.trilinos_vector(); + Tpetra::Vector vector = + V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); @@ -192,7 +197,8 @@ namespace internal // We're going to modify the data on host. vector.modify(); vector_1d(trilinos_i) = value; - vector.sync::device_type::memory_space>(); + vector.sync:: + device_type::memory_space>(); } @@ -205,7 +211,8 @@ namespace internal LinearAlgebra::TpetraWrappers::Vector &V) { // Extract local indices in the vector. - Tpetra::Vector vector = V.trilinos_vector(); + Tpetra::Vector vector = + V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); @@ -216,7 +223,8 @@ namespace internal // We're going to modify the data on host. vector.modify(); vector_1d(trilinos_i) = value; - vector.sync::device_type::memory_space>(); + vector.sync:: + device_type::memory_space>(); } @@ -228,7 +236,8 @@ namespace internal const types::global_dof_index i) { // Extract local indices in the vector. - Tpetra::Vector vector = V.trilinos_vector(); + Tpetra::Vector vector = + V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); @@ -249,7 +258,8 @@ namespace internal const types::global_dof_index i) { // Extract local indices in the vector. - Tpetra::Vector vector = V.trilinos_vector(); + Tpetra::Vector vector = + V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); diff --git a/source/base/index_set.cc b/source/base/index_set.cc index 143efc6dc6b4..d9257454852e 100644 --- a/source/base/index_set.cc +++ b/source/base/index_set.cc @@ -520,7 +520,7 @@ IndexSet::fill_index_vector(std::vector &indices) const #ifdef DEAL_II_WITH_TRILINOS -Tpetra::Map<> +Tpetra::Map IndexSet::make_tpetra_map(const MPI_Comm &communicator, const bool overlapping) const { @@ -556,29 +556,31 @@ IndexSet::make_tpetra_map(const MPI_Comm &communicator, const bool linear = overlapping ? false : is_ascending_and_one_to_one(communicator); if (linear) - return Tpetra::Map<>(size(), - n_elements(), - 0, + return Tpetra::Map( + size(), + n_elements(), + 0, # ifdef DEAL_II_WITH_MPI - Teuchos::rcp(new Teuchos::MpiComm(communicator)) + Teuchos::rcp(new Teuchos::MpiComm(communicator)) # else - Teuchos::rcp(new Teuchos::Comm()) + Teuchos::rcp(new Teuchos::Comm()) # endif ); else { std::vector indices; fill_index_vector(indices); - std::vector int_indices(indices.size()); + std::vector int_indices(indices.size()); std::copy(indices.begin(), indices.end(), int_indices.begin()); - const Teuchos::ArrayView arr_view(int_indices); - return Tpetra::Map<>(size(), - arr_view, - 0, + const Teuchos::ArrayView arr_view(int_indices); + return Tpetra::Map( + size(), + arr_view, + 0, # ifdef DEAL_II_WITH_MPI - Teuchos::rcp(new Teuchos::MpiComm(communicator)) + Teuchos::rcp(new Teuchos::MpiComm(communicator)) # else - Teuchos::rcp(new Teuchos::Comm()) + Teuchos::rcp(new Teuchos::Comm()) # endif ); } diff --git a/source/lac/trilinos_tpetra_communication_pattern.cc b/source/lac/trilinos_tpetra_communication_pattern.cc index e78dfda3d3d1..626622d49d36 100644 --- a/source/lac/trilinos_tpetra_communication_pattern.cc +++ b/source/lac/trilinos_tpetra_communication_pattern.cc @@ -55,20 +55,22 @@ namespace LinearAlgebra { comm = std::make_shared(communicator); - auto vector_space_vector_map = Teuchos::rcp(new Tpetra::Map<>( - vector_space_vector_index_set.make_tpetra_map(*comm, false))); - auto read_write_vector_map = Teuchos::rcp(new Tpetra::Map<>( - read_write_vector_index_set.make_tpetra_map(*comm, true))); + auto vector_space_vector_map = + Teuchos::rcp(new Tpetra::Map( + vector_space_vector_index_set.make_tpetra_map(*comm, false))); + auto read_write_vector_map = + Teuchos::rcp(new Tpetra::Map( + read_write_vector_index_set.make_tpetra_map(*comm, true))); // Target map is read_write_vector_map // Source map is vector_space_vector_map. This map must have uniquely // owned GID. tpetra_import = - std_cxx14::make_unique>(read_write_vector_map, - vector_space_vector_map); + std_cxx14::make_unique>( + read_write_vector_map, vector_space_vector_map); tpetra_export = - std_cxx14::make_unique>(read_write_vector_map, - vector_space_vector_map); + std_cxx14::make_unique>( + read_write_vector_map, vector_space_vector_map); } @@ -81,7 +83,7 @@ namespace LinearAlgebra - const Tpetra::Import<> & + const Tpetra::Import & CommunicationPattern::get_tpetra_import() const { return *tpetra_import; @@ -89,7 +91,7 @@ namespace LinearAlgebra - const Tpetra::Export<> & + const Tpetra::Export & CommunicationPattern::get_tpetra_export() const { return *tpetra_export; diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc index 264f21da77c9..f4e368669728 100644 --- a/source/lac/trilinos_tpetra_vector.cc +++ b/source/lac/trilinos_tpetra_vector.cc @@ -42,8 +42,12 @@ namespace LinearAlgebra { template Vector::Vector() - : vector(new Tpetra::Vector(Teuchos::RCP>( - new Tpetra::Map<>(0, 0, Utilities::Trilinos::tpetra_comm_self())))) + : vector(new Tpetra::Vector( + Teuchos::RCP>( + new Tpetra::Map( + 0, + 0, + Utilities::Trilinos::tpetra_comm_self())))) {} @@ -51,7 +55,9 @@ namespace LinearAlgebra template Vector::Vector(const Vector &V) : Subscriptor() - , vector(new Tpetra::Vector(V.trilinos_vector(), Teuchos::Copy)) + , vector(new Tpetra::Vector( + V.trilinos_vector(), + Teuchos::Copy)) {} @@ -59,8 +65,9 @@ namespace LinearAlgebra template Vector::Vector(const IndexSet ¶llel_partitioner, const MPI_Comm &communicator) - : vector(new Tpetra::Vector(Teuchos::rcp(new Tpetra::Map<>( - parallel_partitioner.make_tpetra_map(communicator, false))))) + : vector(new Tpetra::Vector( + Teuchos::rcp(new Tpetra::Map( + parallel_partitioner.make_tpetra_map(communicator, false))))) {} @@ -71,11 +78,12 @@ namespace LinearAlgebra const MPI_Comm &communicator, const bool omit_zeroing_entries) { - Tpetra::Map<> input_map = + Tpetra::Map input_map = parallel_partitioner.make_tpetra_map(communicator, false); if (vector->getMap()->isSameAs(input_map) == false) - vector = std_cxx14::make_unique>( - Teuchos::rcp(new Tpetra::Map<>(input_map))); + vector = std_cxx14::make_unique< + Tpetra::Vector>(Teuchos::rcp( + new Tpetra::Map(input_map))); else if (omit_zeroing_entries == false) { vector->putScalar(0.); @@ -117,15 +125,16 @@ namespace LinearAlgebra { if (size() == V.size()) { - Tpetra::Import<> data_exchange(vector->getMap(), - V.trilinos_vector().getMap()); + Tpetra::Import data_exchange( + vector->getMap(), V.trilinos_vector().getMap()); vector->doImport(V.trilinos_vector(), data_exchange, Tpetra::REPLACE); } else - vector = std_cxx14::make_unique>( + vector = std_cxx14::make_unique< + Tpetra::Vector>( V.trilinos_vector()); } @@ -185,8 +194,10 @@ namespace LinearAlgebra "LinearAlgebra::TpetraWrappers::CommunicationPattern.")); } - Tpetra::Export<> tpetra_export(tpetra_comm_pattern->get_tpetra_export()); - Tpetra::Vector source_vector(tpetra_export.getSourceMap()); + Tpetra::Export tpetra_export( + tpetra_comm_pattern->get_tpetra_export()); + Tpetra::Vector source_vector( + tpetra_export.getSourceMap()); source_vector.template sync(); auto x_2d = source_vector.template getLocalView(); @@ -197,7 +208,8 @@ namespace LinearAlgebra for (size_t k = 0; k < localLength; ++k) x_1d(k) = *values_it++; source_vector.template sync< - typename Tpetra::Vector::device_type::memory_space>(); + typename Tpetra::Vector:: + device_type::memory_space>(); if (operation == VectorOperation::insert) vector->doExport(source_vector, tpetra_export, Tpetra::REPLACE); else if (operation == VectorOperation::add) @@ -254,15 +266,16 @@ namespace LinearAlgebra ExcDimensionMismatch(this->size(), down_V.size())); // TODO: The code doesn't work as expected so we use a workaround. - /*Tpetra::Export<> data_exchange(vector->getMap(), - down_V.trilinos_vector().getMap()); + /*Tpetra::Export + data_exchange(vector->getMap(), down_V.trilinos_vector().getMap()); vector->doExport(down_V.trilinos_vector(), data_exchange, Tpetra::ADD);*/ - Tpetra::Vector dummy(vector->getMap(), false); - Tpetra::Import<> data_exchange(dummy.getMap(), - down_V.trilinos_vector().getMap()); + Tpetra::Vector dummy( + vector->getMap(), false); + Tpetra::Import data_exchange( + dummy.getMap(), down_V.trilinos_vector().getMap()); dummy.doExport(down_V.trilinos_vector(), data_exchange, @@ -322,7 +335,8 @@ namespace LinearAlgebra vector_1d(k) += a; } vector->template sync< - typename Tpetra::Vector::device_type::memory_space>(); + typename Tpetra::Vector:: + device_type::memory_space>(); } @@ -577,7 +591,7 @@ namespace LinearAlgebra template - const Tpetra::Vector & + const Tpetra::Vector & Vector::trilinos_vector() const { return *vector; @@ -586,7 +600,7 @@ namespace LinearAlgebra template - Tpetra::Vector & + Tpetra::Vector & Vector::trilinos_vector() { return *vector; From 07794a069292a47a4a25567b0a702f47a2a8da4a Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 28 Jan 2019 18:09:41 +0100 Subject: [PATCH 157/507] Add include files and restrict complex values --- include/deal.II/base/utilities.h | 2 ++ source/lac/trilinos_tpetra_vector.cc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/deal.II/base/utilities.h b/include/deal.II/base/utilities.h index dc7414587e54..ed8724b16211 100644 --- a/include/deal.II/base/utilities.h +++ b/include/deal.II/base/utilities.h @@ -30,6 +30,8 @@ #ifdef DEAL_II_WITH_TRILINOS # include # include +# include +# include # ifdef DEAL_II_WITH_MPI # include # else diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc index f4e368669728..8f20b0682817 100644 --- a/source/lac/trilinos_tpetra_vector.cc +++ b/source/lac/trilinos_tpetra_vector.cc @@ -672,8 +672,10 @@ namespace LinearAlgebra template class Vector; template class Vector; +#ifdef DEAL_II_WITH_COMPLEX_VALUES template class Vector>; template class Vector>; +#endif } // namespace TpetraWrappers } // namespace LinearAlgebra From 1581b8987ffdadf041a5937f3ab5595c2be53c13 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 2 Feb 2019 15:53:03 +0100 Subject: [PATCH 158/507] Fix complex tests --- tests/trilinos/tpetra_vector_01.cc | 2 + tests/trilinos/tpetra_vector_02.cc | 2 + tests/trilinos/tpetra_vector_03.cc | 2 + ...03.with_complex_values=off.mpirun=2.output | 121 +++++++++ ...03.with_complex_values=off.mpirun=4.output | 253 ++++++++++++++++++ ...03.with_complex_values=on.mpirun=2.output} | 0 ...03.with_complex_values=on.mpirun=4.output} | 0 7 files changed, 380 insertions(+) create mode 100644 tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=2.output create mode 100644 tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=4.output rename tests/trilinos/{tpetra_vector_03.mpirun=2.output => tpetra_vector_03.with_complex_values=on.mpirun=2.output} (100%) rename tests/trilinos/{tpetra_vector_03.mpirun=4.output => tpetra_vector_03.with_complex_values=on.mpirun=4.output} (100%) diff --git a/tests/trilinos/tpetra_vector_01.cc b/tests/trilinos/tpetra_vector_01.cc index a294f785032c..90c13ee39064 100644 --- a/tests/trilinos/tpetra_vector_01.cc +++ b/tests/trilinos/tpetra_vector_01.cc @@ -223,8 +223,10 @@ main(int argc, char **argv) test(); test(); +#ifdef DEAL_II_WITH_COMPLEX_VALUES test>(); test>(); +#endif deallog << "OK" << std::endl; diff --git a/tests/trilinos/tpetra_vector_02.cc b/tests/trilinos/tpetra_vector_02.cc index 132231491b18..5f44f3a7b269 100644 --- a/tests/trilinos/tpetra_vector_02.cc +++ b/tests/trilinos/tpetra_vector_02.cc @@ -217,8 +217,10 @@ main(int argc, char **argv) test(); test(); +#ifdef DEAL_II_WITH_COMPLEX_VALUES test>(); test>(); +#endif deallog << "OK" << std::endl; diff --git a/tests/trilinos/tpetra_vector_03.cc b/tests/trilinos/tpetra_vector_03.cc index d97b8ce13ad2..e807d30462b4 100644 --- a/tests/trilinos/tpetra_vector_03.cc +++ b/tests/trilinos/tpetra_vector_03.cc @@ -101,6 +101,8 @@ main(int argc, char **argv) MPILogInitAll log; test(); test(); +#ifdef DEAL_II_WITH_COMPLEX_VALUES test>(); test>(); +#endif } diff --git a/tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=2.output b/tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=2.output new file mode 100644 index 000000000000..e94f192176bc --- /dev/null +++ b/tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=2.output @@ -0,0 +1,121 @@ + +DEAL:0::Tpetra first import add: +2.000e+00 1.000e+02 +IndexSet: {[0,2]} + +[0]: 1.000e+00 +[1]: 1.000e+02 +[2]: 1.000e+01 +DEAL:0::Tpetra second import add: +4.000e+00 2.000e+02 +IndexSet: {[0,2]} + +[0]: 2.000e+00 +[1]: 2.000e+02 +[2]: 2.000e+01 +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: 6.000e+00 +[1]: 4.000e+02 +[2]: 5.000e+01 +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} + +[0]: 4.000e+00 +[1]: 1.000e+00 +[2]: 3.000e+01 +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + +[0]: 4.000e+00 +[1]: 2.000e+02 +[2]: 1.000e+02 +DEAL:0::Tpetra first import add: +2.000e+00 1.000e+02 +IndexSet: {[0,2]} + +[0]: 1.000e+00 +[1]: 1.000e+02 +[2]: 1.000e+01 +DEAL:0::Tpetra second import add: +4.000e+00 2.000e+02 +IndexSet: {[0,2]} + +[0]: 2.000e+00 +[1]: 2.000e+02 +[2]: 2.000e+01 +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: 6.000e+00 +[1]: 4.000e+02 +[2]: 5.000e+01 +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} + +[0]: 4.000e+00 +[1]: 1.000e+00 +[2]: 3.000e+01 +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + +[0]: 4.000e+00 +[1]: 2.000e+02 +[2]: 1.000e+02 + +DEAL:1::Tpetra first import add: +1.000e+01 1.010e+02 +IndexSet: {0, 3} + +[0]: 1.000e+00 +[3]: 1.010e+02 +DEAL:1::Tpetra second import add: +3.000e+01 2.010e+02 +IndexSet: {0, 3} + +[0]: 2.000e+00 +[3]: 2.010e+02 +DEAL:1::ReadWrite import add: +IndexSet: {0, 3} + +[0]: 6.000e+00 +[3]: 4.020e+02 +DEAL:1::ReadWrite import min: +IndexSet: {0, 3} + +[0]: 4.000e+00 +[3]: 1.000e+00 +DEAL:1::ReadWrite import max: +IndexSet: {0, 3} + +[0]: 4.000e+00 +[3]: 2.010e+02 +DEAL:1::Tpetra first import add: +1.000e+01 1.010e+02 +IndexSet: {0, 3} + +[0]: 1.000e+00 +[3]: 1.010e+02 +DEAL:1::Tpetra second import add: +3.000e+01 2.010e+02 +IndexSet: {0, 3} + +[0]: 2.000e+00 +[3]: 2.010e+02 +DEAL:1::ReadWrite import add: +IndexSet: {0, 3} + +[0]: 6.000e+00 +[3]: 4.020e+02 +DEAL:1::ReadWrite import min: +IndexSet: {0, 3} + +[0]: 4.000e+00 +[3]: 1.000e+00 +DEAL:1::ReadWrite import max: +IndexSet: {0, 3} + +[0]: 4.000e+00 +[3]: 2.010e+02 + diff --git a/tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=4.output b/tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=4.output new file mode 100644 index 000000000000..5fbf8dea2d1f --- /dev/null +++ b/tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=4.output @@ -0,0 +1,253 @@ + +DEAL:0::Tpetra first import add: +4.000e+00 1.000e+02 +IndexSet: {[0,2]} + +[0]: 1.000e+00 +[1]: 1.000e+02 +[2]: 1.000e+01 +DEAL:0::Tpetra second import add: +8.000e+00 2.000e+02 +IndexSet: {[0,2]} + +[0]: 2.000e+00 +[1]: 2.000e+02 +[2]: 2.000e+01 +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: 1.000e+01 +[1]: 4.000e+02 +[2]: 5.000e+01 +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} + +[0]: 4.000e+00 +[1]: 1.000e+00 +[2]: 3.000e+01 +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + +[0]: 8.000e+00 +[1]: 2.000e+02 +[2]: 1.000e+02 +DEAL:0::Tpetra first import add: +4.000e+00 1.000e+02 +IndexSet: {[0,2]} + +[0]: 1.000e+00 +[1]: 1.000e+02 +[2]: 1.000e+01 +DEAL:0::Tpetra second import add: +8.000e+00 2.000e+02 +IndexSet: {[0,2]} + +[0]: 2.000e+00 +[1]: 2.000e+02 +[2]: 2.000e+01 +DEAL:0::ReadWrite import add: +IndexSet: {[0,2]} + +[0]: 1.000e+01 +[1]: 4.000e+02 +[2]: 5.000e+01 +DEAL:0::ReadWrite import min: +IndexSet: {[0,2]} + +[0]: 4.000e+00 +[1]: 1.000e+00 +[2]: 3.000e+01 +DEAL:0::ReadWrite import max: +IndexSet: {[0,2]} + +[0]: 8.000e+00 +[1]: 2.000e+02 +[2]: 1.000e+02 + +DEAL:1::Tpetra first import add: +1.000e+01 1.010e+02 +IndexSet: {0, [3,4]} + +[0]: 1.000e+00 +[3]: 1.010e+02 +[4]: 1.100e+01 +DEAL:1::Tpetra second import add: +3.000e+01 2.010e+02 +IndexSet: {0, [3,4]} + +[0]: 2.000e+00 +[3]: 2.010e+02 +[4]: 2.100e+01 +DEAL:1::ReadWrite import add: +IndexSet: {0, [3,4]} + +[0]: 1.000e+01 +[3]: 4.020e+02 +[4]: 5.300e+01 +DEAL:1::ReadWrite import min: +IndexSet: {0, [3,4]} + +[0]: 4.000e+00 +[3]: 1.000e+00 +[4]: 3.200e+01 +DEAL:1::ReadWrite import max: +IndexSet: {0, [3,4]} + +[0]: 8.000e+00 +[3]: 2.010e+02 +[4]: 1.010e+02 +DEAL:1::Tpetra first import add: +1.000e+01 1.010e+02 +IndexSet: {0, [3,4]} + +[0]: 1.000e+00 +[3]: 1.010e+02 +[4]: 1.100e+01 +DEAL:1::Tpetra second import add: +3.000e+01 2.010e+02 +IndexSet: {0, [3,4]} + +[0]: 2.000e+00 +[3]: 2.010e+02 +[4]: 2.100e+01 +DEAL:1::ReadWrite import add: +IndexSet: {0, [3,4]} + +[0]: 1.000e+01 +[3]: 4.020e+02 +[4]: 5.300e+01 +DEAL:1::ReadWrite import min: +IndexSet: {0, [3,4]} + +[0]: 4.000e+00 +[3]: 1.000e+00 +[4]: 3.200e+01 +DEAL:1::ReadWrite import max: +IndexSet: {0, [3,4]} + +[0]: 8.000e+00 +[3]: 2.010e+02 +[4]: 1.010e+02 + + +DEAL:2::Tpetra first import add: +1.100e+01 1.020e+02 +IndexSet: {0, [5,6]} + +[0]: 1.000e+00 +[5]: 1.020e+02 +[6]: 1.200e+01 +DEAL:2::Tpetra second import add: +3.200e+01 2.020e+02 +IndexSet: {0, [5,6]} + +[0]: 2.000e+00 +[5]: 2.020e+02 +[6]: 2.200e+01 +DEAL:2::ReadWrite import add: +IndexSet: {0, [5,6]} + +[0]: 1.000e+01 +[5]: 4.040e+02 +[6]: 5.600e+01 +DEAL:2::ReadWrite import min: +IndexSet: {0, [5,6]} + +[0]: 4.000e+00 +[5]: 1.000e+00 +[6]: 3.400e+01 +DEAL:2::ReadWrite import max: +IndexSet: {0, [5,6]} + +[0]: 8.000e+00 +[5]: 2.020e+02 +[6]: 1.020e+02 +DEAL:2::Tpetra first import add: +1.100e+01 1.020e+02 +IndexSet: {0, [5,6]} + +[0]: 1.000e+00 +[5]: 1.020e+02 +[6]: 1.200e+01 +DEAL:2::Tpetra second import add: +3.200e+01 2.020e+02 +IndexSet: {0, [5,6]} + +[0]: 2.000e+00 +[5]: 2.020e+02 +[6]: 2.200e+01 +DEAL:2::ReadWrite import add: +IndexSet: {0, [5,6]} + +[0]: 1.000e+01 +[5]: 4.040e+02 +[6]: 5.600e+01 +DEAL:2::ReadWrite import min: +IndexSet: {0, [5,6]} + +[0]: 4.000e+00 +[5]: 1.000e+00 +[6]: 3.400e+01 +DEAL:2::ReadWrite import max: +IndexSet: {0, [5,6]} + +[0]: 8.000e+00 +[5]: 2.020e+02 +[6]: 1.020e+02 + + +DEAL:3::Tpetra first import add: +1.200e+01 1.030e+02 +IndexSet: {0, 7} + +[0]: 1.000e+00 +[7]: 1.030e+02 +DEAL:3::Tpetra second import add: +3.400e+01 2.030e+02 +IndexSet: {0, 7} + +[0]: 2.000e+00 +[7]: 2.030e+02 +DEAL:3::ReadWrite import add: +IndexSet: {0, 7} + +[0]: 1.000e+01 +[7]: 4.060e+02 +DEAL:3::ReadWrite import min: +IndexSet: {0, 7} + +[0]: 4.000e+00 +[7]: 1.000e+00 +DEAL:3::ReadWrite import max: +IndexSet: {0, 7} + +[0]: 8.000e+00 +[7]: 2.030e+02 +DEAL:3::Tpetra first import add: +1.200e+01 1.030e+02 +IndexSet: {0, 7} + +[0]: 1.000e+00 +[7]: 1.030e+02 +DEAL:3::Tpetra second import add: +3.400e+01 2.030e+02 +IndexSet: {0, 7} + +[0]: 2.000e+00 +[7]: 2.030e+02 +DEAL:3::ReadWrite import add: +IndexSet: {0, 7} + +[0]: 1.000e+01 +[7]: 4.060e+02 +DEAL:3::ReadWrite import min: +IndexSet: {0, 7} + +[0]: 4.000e+00 +[7]: 1.000e+00 +DEAL:3::ReadWrite import max: +IndexSet: {0, 7} + +[0]: 8.000e+00 +[7]: 2.030e+02 + diff --git a/tests/trilinos/tpetra_vector_03.mpirun=2.output b/tests/trilinos/tpetra_vector_03.with_complex_values=on.mpirun=2.output similarity index 100% rename from tests/trilinos/tpetra_vector_03.mpirun=2.output rename to tests/trilinos/tpetra_vector_03.with_complex_values=on.mpirun=2.output diff --git a/tests/trilinos/tpetra_vector_03.mpirun=4.output b/tests/trilinos/tpetra_vector_03.with_complex_values=on.mpirun=4.output similarity index 100% rename from tests/trilinos/tpetra_vector_03.mpirun=4.output rename to tests/trilinos/tpetra_vector_03.with_complex_values=on.mpirun=4.output From dd2b650e34e6f01e37ec9f7b82973fcf706fe8fb Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 2 Feb 2019 17:17:09 +0100 Subject: [PATCH 159/507] Indentation --- include/deal.II/base/utilities.h | 2 +- source/lac/trilinos_tpetra_vector.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/deal.II/base/utilities.h b/include/deal.II/base/utilities.h index ed8724b16211..13694ea9497b 100644 --- a/include/deal.II/base/utilities.h +++ b/include/deal.II/base/utilities.h @@ -30,8 +30,8 @@ #ifdef DEAL_II_WITH_TRILINOS # include # include -# include # include +# include # ifdef DEAL_II_WITH_MPI # include # else diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc index 8f20b0682817..6eb2b6e1f71d 100644 --- a/source/lac/trilinos_tpetra_vector.cc +++ b/source/lac/trilinos_tpetra_vector.cc @@ -672,10 +672,10 @@ namespace LinearAlgebra template class Vector; template class Vector; -#ifdef DEAL_II_WITH_COMPLEX_VALUES +# ifdef DEAL_II_WITH_COMPLEX_VALUES template class Vector>; template class Vector>; -#endif +# endif } // namespace TpetraWrappers } // namespace LinearAlgebra From c1356b3c4ad5a1e7503166467a1d5e568eb0711d Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 5 Feb 2019 21:56:33 +0100 Subject: [PATCH 160/507] Make Tpetra optional --- cmake/configure/configure_2_trilinos.cmake | 10 ++++++---- include/deal.II/base/config.h.in | 1 + include/deal.II/base/index_set.h | 6 +++++- include/deal.II/dofs/dof_accessor.templates.h | 2 ++ .../fe/fe_tools_extrapolate.templates.h | 2 ++ .../fe/fe_tools_interpolate.templates.h | 2 ++ include/deal.II/lac/read_write_vector.h | 6 ++++++ .../deal.II/lac/read_write_vector.templates.h | 7 +++++++ .../trilinos_tpetra_communication_pattern.h | 14 +++++--------- include/deal.II/lac/trilinos_tpetra_vector.h | 2 +- include/deal.II/lac/vector_element_access.h | 2 ++ include/deal.II/multigrid/mg_transfer.h | 2 ++ source/base/index_set.cc | 19 ++++++++++--------- source/lac/trilinos_sparse_matrix.cc | 10 ++++++++++ .../trilinos_tpetra_communication_pattern.cc | 2 +- source/lac/trilinos_tpetra_vector.cc | 2 +- ...run=2.with_trilinos_with_tpetra=on.output} | 0 ...run=2.with_trilinos_with_tpetra=on.output} | 0 ...n.with_complex_values=off.mpirun=2.output} | 0 ...n.with_complex_values=off.mpirun=4.output} | 0 ...on.with_complex_values=on.mpirun=2.output} | 0 ...on.with_complex_values=on.mpirun=4.output} | 0 22 files changed, 63 insertions(+), 26 deletions(-) rename tests/trilinos/{tpetra_vector_01.mpirun=2.output => tpetra_vector_01.mpirun=2.with_trilinos_with_tpetra=on.output} (100%) rename tests/trilinos/{tpetra_vector_02.mpirun=2.output => tpetra_vector_02.mpirun=2.with_trilinos_with_tpetra=on.output} (100%) rename tests/trilinos/{tpetra_vector_03.with_complex_values=off.mpirun=2.output => tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=off.mpirun=2.output} (100%) rename tests/trilinos/{tpetra_vector_03.with_complex_values=off.mpirun=4.output => tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=off.mpirun=4.output} (100%) rename tests/trilinos/{tpetra_vector_03.with_complex_values=on.mpirun=2.output => tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=on.mpirun=2.output} (100%) rename tests/trilinos/{tpetra_vector_03.with_complex_values=on.mpirun=4.output => tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=on.mpirun=4.output} (100%) diff --git a/cmake/configure/configure_2_trilinos.cmake b/cmake/configure/configure_2_trilinos.cmake index c159fe255270..eca8862a0a40 100644 --- a/cmake/configure/configure_2_trilinos.cmake +++ b/cmake/configure/configure_2_trilinos.cmake @@ -42,7 +42,7 @@ MACRO(FEATURE_TRILINOS_FIND_EXTERNAL var) ) FOREACH(_module - Amesos Epetra Ifpack AztecOO Teuchos Tpetra ML MueLu + Amesos Epetra Ifpack AztecOO Teuchos ML MueLu ) ITEM_MATCHES(_module_found ${_module} ${Trilinos_PACKAGE_LIST}) IF(_module_found) @@ -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}") @@ -227,8 +227,10 @@ 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") - SET(DEAL_II_EXPAND_TPETRA_VECTOR_DOUBLE "LinearAlgebra::TpetraWrappers::Vector") - SET(DEAL_II_EXPAND_TPETRA_VECTOR_FLOAT "LinearAlgebra::TpetraWrappers::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") + ENDIF() ENDIF() IF(${DEAL_II_TRILINOS_WITH_SACADO}) # Note: Only CMake 3.0 and greater support line continuation with the "\" character diff --git a/include/deal.II/base/config.h.in b/include/deal.II/base/config.h.in index 23690507599d..6cf6971a90f7 100644 --- a/include/deal.II/base/config.h.in +++ b/include/deal.II/base/config.h.in @@ -186,6 +186,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 diff --git a/include/deal.II/base/index_set.h b/include/deal.II/base/index_set.h index afb90fe2d784..4800633ada5d 100644 --- a/include/deal.II/base/index_set.h +++ b/include/deal.II/base/index_set.h @@ -31,7 +31,9 @@ #ifdef DEAL_II_WITH_TRILINOS # include -# include +# ifdef DEAL_II_TRILINOS_WITH_TPETRA +# include +# endif #endif #if defined(DEAL_II_WITH_MPI) || defined(DEAL_II_WITH_PETSC) @@ -448,9 +450,11 @@ class IndexSet make_trilinos_map(const MPI_Comm &communicator = MPI_COMM_WORLD, const bool overlapping = false) const; +# ifdef DEAL_II_TRILINOS_WITH_TPETRA Tpetra::Map make_tpetra_map(const MPI_Comm &communicator = MPI_COMM_WORLD, const bool overlapping = false) const; +# endif #endif diff --git a/include/deal.II/dofs/dof_accessor.templates.h b/include/deal.II/dofs/dof_accessor.templates.h index 9b89e6e31f47..d7a097f66917 100644 --- a/include/deal.II/dofs/dof_accessor.templates.h +++ b/include/deal.II/dofs/dof_accessor.templates.h @@ -1534,6 +1534,7 @@ namespace internal +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template static void extract_subvector_to( @@ -1559,6 +1560,7 @@ namespace internal for (unsigned int i = 0; i < cache_size; ++i, ++local_values_begin) *local_values_begin = read_write_vector[sorted_indices_pos[i]]; } +# endif diff --git a/include/deal.II/fe/fe_tools_extrapolate.templates.h b/include/deal.II/fe/fe_tools_extrapolate.templates.h index ea76059356c7..eb210626d7c5 100644 --- a/include/deal.II/fe/fe_tools_extrapolate.templates.h +++ b/include/deal.II/fe/fe_tools_extrapolate.templates.h @@ -1581,6 +1581,7 @@ namespace FETools # ifdef DEAL_II_WITH_MPI +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template void reinit_distributed(const DoFHandler & dh, @@ -1595,6 +1596,7 @@ namespace FETools const IndexSet &locally_owned_dofs = dh.locally_owned_dofs(); vector.reinit(locally_owned_dofs, parallel_tria->get_communicator()); } +# endif template void diff --git a/include/deal.II/fe/fe_tools_interpolate.templates.h b/include/deal.II/fe/fe_tools_interpolate.templates.h index 9699c0a9b43d..a453ae0572b4 100644 --- a/include/deal.II/fe/fe_tools_interpolate.templates.h +++ b/include/deal.II/fe/fe_tools_interpolate.templates.h @@ -513,6 +513,7 @@ namespace FETools AssertThrow(false, ExcNotImplemented()); } +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template void back_interpolate( @@ -527,6 +528,7 @@ namespace FETools { AssertThrow(false, ExcNotImplemented()); } +# endif #endif diff --git a/include/deal.II/lac/read_write_vector.h b/include/deal.II/lac/read_write_vector.h index b72a95eae233..f752ff815aa1 100644 --- a/include/deal.II/lac/read_write_vector.h +++ b/include/deal.II/lac/read_write_vector.h @@ -335,6 +335,7 @@ namespace LinearAlgebra std::shared_ptr()); # ifdef DEAL_II_WITH_MPI +# ifdef DEAL_II_TRILINOS_WITH_TPETRA /** * Imports all the elements present in the vector's IndexSet from the input * vector @p tpetra_vec. VectorOperation::values @p operation is used to @@ -349,6 +350,7 @@ namespace LinearAlgebra const std::shared_ptr &communication_pattern = std::shared_ptr()); +# endif /** * Imports all the elements present in the vector's IndexSet from the input @@ -609,6 +611,7 @@ namespace LinearAlgebra protected: #ifdef DEAL_II_WITH_TRILINOS +# ifdef DEAL_II_TRILINOS_WITH_TPETRA /** * Import all the elements present in the vector's IndexSet from the input * vector @p tpetra_vector. This is an helper function and it should not be @@ -622,6 +625,7 @@ namespace LinearAlgebra const MPI_Comm & mpi_comm, const std::shared_ptr &communication_pattern); +# endif /** * Import all the elements present in the vector's IndexSet from the input @@ -656,6 +660,7 @@ namespace LinearAlgebra resize_val(const size_type new_allocated_size); #if defined(DEAL_II_WITH_TRILINOS) && defined(DEAL_II_WITH_MPI) +# ifdef DEAL_II_TRILINOS_WITH_TPETRA /** * Return a TpetraWrappers::CommunicationPattern and store it for future * use. @@ -663,6 +668,7 @@ namespace LinearAlgebra TpetraWrappers::CommunicationPattern create_tpetra_comm_pattern(const IndexSet &source_index_set, const MPI_Comm &mpi_comm); +# endif /** * Return a EpetraWrappers::CommunicationPattern and store it for future diff --git a/include/deal.II/lac/read_write_vector.templates.h b/include/deal.II/lac/read_write_vector.templates.h index 572c28f1dec9..1444b00856d5 100644 --- a/include/deal.II/lac/read_write_vector.templates.h +++ b/include/deal.II/lac/read_write_vector.templates.h @@ -506,6 +506,7 @@ namespace LinearAlgebra #if defined(DEAL_II_WITH_TRILINOS) && defined(DEAL_II_WITH_MPI) +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template void ReadWriteVector::import( @@ -595,6 +596,7 @@ namespace LinearAlgebra AssertThrow(false, ExcNotImplemented()); } } +# endif @@ -743,6 +745,7 @@ namespace LinearAlgebra +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template void ReadWriteVector::import( @@ -757,6 +760,7 @@ namespace LinearAlgebra trilinos_vec.get_mpi_communicator(), communication_pattern); } +# endif @@ -901,6 +905,7 @@ namespace LinearAlgebra #if defined(DEAL_II_WITH_TRILINOS) && defined(DEAL_II_WITH_MPI) +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template TpetraWrappers::CommunicationPattern ReadWriteVector::create_tpetra_comm_pattern( @@ -915,6 +920,8 @@ namespace LinearAlgebra return epetra_comm_pattern; } +# endif + template diff --git a/include/deal.II/lac/trilinos_tpetra_communication_pattern.h b/include/deal.II/lac/trilinos_tpetra_communication_pattern.h index fd3e074b2aa9..45c6f1d34dd9 100644 --- a/include/deal.II/lac/trilinos_tpetra_communication_pattern.h +++ b/include/deal.II/lac/trilinos_tpetra_communication_pattern.h @@ -19,16 +19,14 @@ #include -#ifdef DEAL_II_WITH_TRILINOS +#if defined(DEAL_II_TRILINOS_WITH_TPETRA) && defined(DEAL_II_WITH_MPI) -# ifdef DEAL_II_WITH_MPI +# include -# include +# include +# include -# include -# include - -# include +# include DEAL_II_NAMESPACE_OPEN @@ -102,8 +100,6 @@ namespace LinearAlgebra DEAL_II_NAMESPACE_CLOSE -# endif - #endif #endif diff --git a/include/deal.II/lac/trilinos_tpetra_vector.h b/include/deal.II/lac/trilinos_tpetra_vector.h index 911863c9d99e..a91d4e4b5547 100644 --- a/include/deal.II/lac/trilinos_tpetra_vector.h +++ b/include/deal.II/lac/trilinos_tpetra_vector.h @@ -19,7 +19,7 @@ #include -#if defined(DEAL_II_WITH_TRILINOS) && defined(DEAL_II_WITH_MPI) +#if defined(DEAL_II_TRILINOS_WITH_TPETRA) && defined(DEAL_II_WITH_MPI) # include # include diff --git a/include/deal.II/lac/vector_element_access.h b/include/deal.II/lac/vector_element_access.h index 4a81d97fdbc1..236203e19840 100644 --- a/include/deal.II/lac/vector_element_access.h +++ b/include/deal.II/lac/vector_element_access.h @@ -125,6 +125,7 @@ namespace internal +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template <> inline void ElementAccess>::add( @@ -270,6 +271,7 @@ namespace internal // We're going to modify the data on host. return vector_1d(trilinos_i); } +# endif #endif } // namespace internal diff --git a/include/deal.II/multigrid/mg_transfer.h b/include/deal.II/multigrid/mg_transfer.h index 961b0223dfc3..82a82150e89e 100644 --- a/include/deal.II/multigrid/mg_transfer.h +++ b/include/deal.II/multigrid/mg_transfer.h @@ -132,6 +132,7 @@ namespace internal }; # ifdef DEAL_II_WITH_MPI +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template struct MatrixSelector> { @@ -163,6 +164,7 @@ namespace internal true); } }; +# endif template <> struct MatrixSelector diff --git a/source/base/index_set.cc b/source/base/index_set.cc index d9257454852e..9e5cc43c279f 100644 --- a/source/base/index_set.cc +++ b/source/base/index_set.cc @@ -519,6 +519,7 @@ IndexSet::fill_index_vector(std::vector &indices) const #ifdef DEAL_II_WITH_TRILINOS +# ifdef DEAL_II_TRILINOS_WITH_TPETRA Tpetra::Map IndexSet::make_tpetra_map(const MPI_Comm &communicator, @@ -527,7 +528,7 @@ IndexSet::make_tpetra_map(const MPI_Comm &communicator, compress(); (void)communicator; -# ifdef DEBUG +# ifdef DEBUG if (!overlapping) { const size_type n_global_elements = @@ -549,7 +550,7 @@ IndexSet::make_tpetra_map(const MPI_Comm &communicator, "by any processor, or there are indices that are " "claimed by multiple processors.")); } -# endif +# endif // Find out if the IndexSet is ascending and 1:1. This corresponds to a // linear Tpetra::Map. Overlapping IndexSets are never 1:1. @@ -560,11 +561,11 @@ IndexSet::make_tpetra_map(const MPI_Comm &communicator, size(), n_elements(), 0, -# ifdef DEAL_II_WITH_MPI +# ifdef DEAL_II_WITH_MPI Teuchos::rcp(new Teuchos::MpiComm(communicator)) -# else +# else Teuchos::rcp(new Teuchos::Comm()) -# endif +# endif ); else { @@ -577,14 +578,15 @@ IndexSet::make_tpetra_map(const MPI_Comm &communicator, size(), arr_view, 0, -# ifdef DEAL_II_WITH_MPI +# ifdef DEAL_II_WITH_MPI Teuchos::rcp(new Teuchos::MpiComm(communicator)) -# else +# else Teuchos::rcp(new Teuchos::Comm()) -# endif +# endif ); } } +# endif @@ -657,7 +659,6 @@ IndexSet::make_trilinos_map(const MPI_Comm &communicator, #endif - bool IndexSet::is_ascending_and_one_to_one(const MPI_Comm &communicator) const { diff --git a/source/lac/trilinos_sparse_matrix.cc b/source/lac/trilinos_sparse_matrix.cc index 250a6d051918..d87c7e88c18b 100644 --- a/source/lac/trilinos_sparse_matrix.cc +++ b/source/lac/trilinos_sparse_matrix.cc @@ -104,6 +104,7 @@ namespace TrilinosWrappers return V.trilinos_vector()[0] + V.trilinos_vector().MyLength(); } +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template Number * begin(LinearAlgebra::TpetraWrappers::Vector &V) @@ -133,6 +134,7 @@ namespace TrilinosWrappers return V.trilinos_vector().getData().get() + V.trilinos_vector().getLocalLength(); } +# endif # endif } // namespace internal @@ -3510,6 +3512,7 @@ namespace TrilinosWrappers const dealii::LinearAlgebra::distributed::Vector &) const; # ifdef DEAL_II_WITH_MPI +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template void SparseMatrix::vmult( dealii::LinearAlgebra::TpetraWrappers::Vector &, @@ -3519,6 +3522,7 @@ namespace TrilinosWrappers SparseMatrix::vmult( dealii::LinearAlgebra::TpetraWrappers::Vector &, const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; +# endif template void SparseMatrix::vmult( @@ -3539,6 +3543,7 @@ namespace TrilinosWrappers const dealii::LinearAlgebra::distributed::Vector &) const; # ifdef DEAL_II_WITH_MPI +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template void SparseMatrix::Tvmult( dealii::LinearAlgebra::TpetraWrappers::Vector &, @@ -3548,6 +3553,7 @@ namespace TrilinosWrappers SparseMatrix::Tvmult( dealii::LinearAlgebra::TpetraWrappers::Vector &, const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; +# endif template void SparseMatrix::Tvmult( @@ -3568,6 +3574,7 @@ namespace TrilinosWrappers const dealii::LinearAlgebra::distributed::Vector &) const; # ifdef DEAL_II_WITH_MPI +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template void SparseMatrix::vmult_add( dealii::LinearAlgebra::TpetraWrappers::Vector &, @@ -3577,6 +3584,7 @@ namespace TrilinosWrappers SparseMatrix::vmult_add( dealii::LinearAlgebra::TpetraWrappers::Vector &, const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; +# endif template void SparseMatrix::vmult_add( @@ -3597,6 +3605,7 @@ namespace TrilinosWrappers const dealii::LinearAlgebra::distributed::Vector &) const; # ifdef DEAL_II_WITH_MPI +# ifdef DEAL_II_TRILINOS_WITH_TPETRA template void SparseMatrix::Tvmult_add( dealii::LinearAlgebra::TpetraWrappers::Vector &, @@ -3606,6 +3615,7 @@ namespace TrilinosWrappers SparseMatrix::Tvmult_add( dealii::LinearAlgebra::TpetraWrappers::Vector &, const dealii::LinearAlgebra::TpetraWrappers::Vector &) const; +# endif template void SparseMatrix::Tvmult_add( diff --git a/source/lac/trilinos_tpetra_communication_pattern.cc b/source/lac/trilinos_tpetra_communication_pattern.cc index 626622d49d36..99d3aa5f57c4 100644 --- a/source/lac/trilinos_tpetra_communication_pattern.cc +++ b/source/lac/trilinos_tpetra_communication_pattern.cc @@ -17,7 +17,7 @@ #include -#ifdef DEAL_II_WITH_TRILINOS +#ifdef DEAL_II_TRILINOS_WITH_TPETRA # ifdef DEAL_II_WITH_MPI diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc index 6eb2b6e1f71d..428182e91614 100644 --- a/source/lac/trilinos_tpetra_vector.cc +++ b/source/lac/trilinos_tpetra_vector.cc @@ -17,7 +17,7 @@ #include -#ifdef DEAL_II_WITH_TRILINOS +#ifdef DEAL_II_TRILINOS_WITH_TPETRA # ifdef DEAL_II_WITH_MPI diff --git a/tests/trilinos/tpetra_vector_01.mpirun=2.output b/tests/trilinos/tpetra_vector_01.mpirun=2.with_trilinos_with_tpetra=on.output similarity index 100% rename from tests/trilinos/tpetra_vector_01.mpirun=2.output rename to tests/trilinos/tpetra_vector_01.mpirun=2.with_trilinos_with_tpetra=on.output diff --git a/tests/trilinos/tpetra_vector_02.mpirun=2.output b/tests/trilinos/tpetra_vector_02.mpirun=2.with_trilinos_with_tpetra=on.output similarity index 100% rename from tests/trilinos/tpetra_vector_02.mpirun=2.output rename to tests/trilinos/tpetra_vector_02.mpirun=2.with_trilinos_with_tpetra=on.output diff --git a/tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=2.output b/tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=off.mpirun=2.output similarity index 100% rename from tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=2.output rename to tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=off.mpirun=2.output diff --git a/tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=4.output b/tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=off.mpirun=4.output similarity index 100% rename from tests/trilinos/tpetra_vector_03.with_complex_values=off.mpirun=4.output rename to tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=off.mpirun=4.output diff --git a/tests/trilinos/tpetra_vector_03.with_complex_values=on.mpirun=2.output b/tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=on.mpirun=2.output similarity index 100% rename from tests/trilinos/tpetra_vector_03.with_complex_values=on.mpirun=2.output rename to tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=on.mpirun=2.output diff --git a/tests/trilinos/tpetra_vector_03.with_complex_values=on.mpirun=4.output b/tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=on.mpirun=4.output similarity index 100% rename from tests/trilinos/tpetra_vector_03.with_complex_values=on.mpirun=4.output rename to tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=on.mpirun=4.output From 2fb42804a16d8ab7667f30757c9459e9cface8a2 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 10 Feb 2019 00:53:53 +0100 Subject: [PATCH 161/507] Check if Tpetra is usable --- cmake/configure/configure_2_trilinos.cmake | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/cmake/configure/configure_2_trilinos.cmake b/cmake/configure/configure_2_trilinos.cmake index eca8862a0a40..9b3c86139577 100644 --- a/cmake/configure/configure_2_trilinos.cmake +++ b/cmake/configure/configure_2_trilinos.cmake @@ -158,6 +158,41 @@ 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}) + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_VERSION_FLAG}") + 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: From c4c347acd7dfe495eaed9bd1bcf04d97cdca13d9 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 18 Feb 2019 12:44:20 +0100 Subject: [PATCH 162/507] Check for imaginary parts --- .../deal.II/lac/read_write_vector.templates.h | 88 ++++++++++++++++--- 1 file changed, 76 insertions(+), 12 deletions(-) diff --git a/include/deal.II/lac/read_write_vector.templates.h b/include/deal.II/lac/read_write_vector.templates.h index 1444b00856d5..cfbbc7db890b 100644 --- a/include/deal.II/lac/read_write_vector.templates.h +++ b/include/deal.II/lac/read_write_vector.templates.h @@ -581,15 +581,39 @@ namespace LinearAlgebra break; case VectorOperation::min: + // To ensure that this code also compiles with complex + // numbers, we only compare the real part of the + // variable. Note that min/max do not make sense with complex + // numbers. for (size_type i = 0; i < size; ++i) - if (std::real(new_values[i]) - std::real(values[i]) < 0.0) - values[i] = new_values[i]; + { + Assert( + std::imag(new_values[i]) == 0., + ExcMessage( + "VectorOperation::min is not defined if there is an imaginary part!)")); + Assert( + std::imag(values[i]) == 0., + ExcMessage( + "VectorOperation::min is not defined if there is an imaginary part!)")); + if (std::real(new_values[i]) - std::real(values[i]) < 0.0) + values[i] = new_values[i]; + } break; case VectorOperation::max: for (size_type i = 0; i < size; ++i) - if (std::real(new_values[i]) - std::real(values[i]) > 0.0) - values[i] = new_values[i]; + { + Assert( + std::imag(new_values[i]) == 0., + ExcMessage( + "VectorOperation::max is not defined if there is an imaginary part!)")); + Assert( + std::imag(values[i]) == 0., + ExcMessage( + "VectorOperation::max is not defined if there is an imaginary part!)")); + if (std::real(new_values[i]) - std::real(values[i]) > 0.0) + values[i] = new_values[i]; + } break; default: @@ -697,8 +721,18 @@ namespace LinearAlgebra // variable. Note that min/max do not make sense with complex // numbers. for (int i = 0; i < size; ++i) - if (std::real(new_values[i]) - std::real(values[i]) < 0.0) - values[i] = new_values[i]; + { + Assert( + std::imag(new_values[i]) == 0., + ExcMessage( + "VectorOperation::min is not defined if there is an imaginary part!)")); + Assert( + std::imag(values[i]) == 0., + ExcMessage( + "VectorOperation::min is not defined if there is an imaginary part!)")); + if (std::real(new_values[i]) - std::real(values[i]) < 0.0) + values[i] = new_values[i]; + } } else if (operation == VectorOperation::max) { @@ -713,8 +747,18 @@ namespace LinearAlgebra ExcInternalError("Import failed.")); for (int i = 0; i < size; ++i) - if (std::real(new_values[i]) - std::real(values[i]) > 0.0) - values[i] = new_values[i]; + { + Assert( + std::imag(new_values[i]) == 0., + ExcMessage( + "VectorOperation::max is not defined if there is an imaginary part!)")); + Assert( + std::imag(values[i]) == 0., + ExcMessage( + "VectorOperation::max is not defined if there is an imaginary part!)")); + if (std::real(new_values[i]) - std::real(values[i]) > 0.0) + values[i] = new_values[i]; + } } else AssertThrow(false, ExcNotImplemented()); @@ -828,8 +872,18 @@ namespace LinearAlgebra // variable. Note that min/max do not make sense with complex // numbers. for (unsigned int i = 0; i < n_elements; ++i) - if (std::real(tmp[i]) - std::real(values[i]) < 0.0) - values[i] = tmp[i]; + { + Assert( + std::imag(new_values[i]) == 0., + ExcMessage( + "VectorOperation::min is not defined if there is an imaginary part!)")); + Assert( + std::imag(values[i]) == 0., + ExcMessage( + "VectorOperation::min is not defined if there is an imaginary part!)")); + if (std::real(tmp[i]) - std::real(values[i]) < 0.0) + values[i] = tmp[i]; + } } else if (operation == VectorOperation::max) { @@ -842,8 +896,18 @@ namespace LinearAlgebra AssertCuda(error_code); for (unsigned int i = 0; i < n_elements; ++i) - if (std::real(tmp[i]) - std::real(values[i]) > 0.0) - values[i] = tmp[i]; + { + Assert( + std::imag(new_values[i]) == 0., + ExcMessage( + "VectorOperation::max is not defined if there is an imaginary part!)")); + Assert( + std::imag(values[i]) == 0., + ExcMessage( + "VectorOperation::max is not defined if there is an imaginary part!)")); + if (std::real(tmp[i]) - std::real(values[i]) > 0.0) + values[i] = tmp[i]; + } } else AssertThrow(false, ExcNotImplemented()); From 3f17effecbffe9217219e092a6d7576b81d94ca9 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 18 Feb 2019 14:58:40 +0100 Subject: [PATCH 163/507] Copyright dates and documentation --- include/deal.II/lac/trilinos_epetra_vector.h | 12 ++++++------ include/deal.II/lac/trilinos_sparse_matrix.h | 8 ++++---- .../lac/trilinos_tpetra_communication_pattern.h | 2 +- include/deal.II/lac/trilinos_tpetra_vector.h | 14 +++++++------- source/base/index_set.cc | 1 + .../lac/trilinos_tpetra_communication_pattern.cc | 2 +- source/lac/trilinos_tpetra_vector.cc | 2 +- tests/trilinos/tpetra_vector_01.cc | 2 +- tests/trilinos/tpetra_vector_02.cc | 2 +- tests/trilinos/tpetra_vector_03.cc | 2 +- 10 files changed, 24 insertions(+), 23 deletions(-) diff --git a/include/deal.II/lac/trilinos_epetra_vector.h b/include/deal.II/lac/trilinos_epetra_vector.h index b11b63ca616d..24b21e2774ee 100644 --- a/include/deal.II/lac/trilinos_epetra_vector.h +++ b/include/deal.II/lac/trilinos_epetra_vector.h @@ -55,7 +55,8 @@ namespace LinearAlgebra * This class implements a wrapper to the Trilinos distributed vector * class Epetra_FEVector. This class is derived from the * LinearAlgebra::VectorSpaceVector class. Note however that Epetra only - * works with Number = double. + * works with Number = double. This class requires Trilinos to be compiled + * with MPI support. * * @ingroup TrilinosWrappers * @ingroup Vectors @@ -96,7 +97,7 @@ namespace LinearAlgebra const bool omit_zeroing_entries = false); /** - * Change the dimension to that of the vector V. The elements of V are not + * Change the dimension to that of the vector @p V. The elements of @p V are not * copied. */ virtual void @@ -120,8 +121,7 @@ namespace LinearAlgebra /** * Imports all the elements present in the vector's IndexSet from the - * input - * vector @p V. VectorOperation::values @p operation is used to decide if + * input vector @p V. VectorOperation::values @p operation is used to decide if * the elements in @p V should be added to the current vector or replace the * current elements. The last parameter can be used if the same * communication pattern is used multiple times. This can be used to @@ -335,8 +335,8 @@ namespace LinearAlgebra memory_consumption() const override; /** - * The vectors have different partitioning, i.e. they have use different - * IndexSet. + * The vectors have different partitioning, i.e. their IndexSet objects + * don't represent the same indices. */ DeclException0(ExcDifferentParallelPartitioning); diff --git a/include/deal.II/lac/trilinos_sparse_matrix.h b/include/deal.II/lac/trilinos_sparse_matrix.h index 368fc70a12d4..4f8e955cb869 100644 --- a/include/deal.II/lac/trilinos_sparse_matrix.h +++ b/include/deal.II/lac/trilinos_sparse_matrix.h @@ -1577,7 +1577,7 @@ namespace TrilinosWrappers * of the matrix. * * This function will be called when the underlying number type for the - * matrix object and the one one for the vector object are the same. + * matrix object and the one for the vector object are the same. * * In case of a serial vector, this function will only work when * running on one processor, since the matrix object is inherently @@ -1591,7 +1591,7 @@ namespace TrilinosWrappers /** * Same as the function above for the case that the underlying number type * for the matrix object and the one for the vector object do not coincide. - * This case is not implemented. Calling it will result in an runtime error. + * This case is not implemented. Calling it will result in a runtime error. */ template typename std::enable_if typename std::enable_if typename std::enable_if Date: Mon, 18 Feb 2019 14:59:28 +0100 Subject: [PATCH 164/507] Generalize template specialization --- include/deal.II/lac/vector_element_access.h | 147 +++++++------------- 1 file changed, 48 insertions(+), 99 deletions(-) diff --git a/include/deal.II/lac/vector_element_access.h b/include/deal.II/lac/vector_element_access.h index 236203e19840..9e00b8de5807 100644 --- a/include/deal.II/lac/vector_element_access.h +++ b/include/deal.II/lac/vector_element_access.h @@ -126,147 +126,96 @@ namespace internal # ifdef DEAL_II_TRILINOS_WITH_TPETRA - template <> - inline void - ElementAccess>::add( - const double value, - const types::global_dof_index i, - LinearAlgebra::TpetraWrappers::Vector &V) + template + struct ElementAccess> { - // Extract local indices in the vector. - Tpetra::Vector vector = - V.trilinos_vector(); - TrilinosWrappers::types::int_type trilinos_i = - vector.getMap()->getLocalElement( - static_cast(i)); - - vector.sync(); - auto vector_2d = vector.getLocalView(); - auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); - // We're going to modify the data on host. - vector.modify(); - vector_1d(trilinos_i) += value; - vector.sync:: - device_type::memory_space>(); - } - - + public: + using VectorType = LinearAlgebra::TpetraWrappers::Vector; + static void + add(const typename VectorType::value_type value, + const types::global_dof_index i, + VectorType & V); - template <> - inline void - ElementAccess>::add( - const float value, - const types::global_dof_index i, - LinearAlgebra::TpetraWrappers::Vector &V) - { - // Extract local indices in the vector. - Tpetra::Vector vector = - V.trilinos_vector(); - TrilinosWrappers::types::int_type trilinos_i = - vector.getMap()->getLocalElement( - static_cast(i)); + static void + set(typename VectorType::value_type value, + const types::global_dof_index i, + VectorType & V); - vector.sync(); - auto vector_2d = vector.getLocalView(); - auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); - // We're going to modify the data on host. - vector.modify(); - vector_1d(trilinos_i) += value; - vector.sync:: - device_type::memory_space>(); - } + static typename VectorType::value_type + get(const VectorType &V, const types::global_dof_index i); + }; - template <> + template inline void - ElementAccess>::set( - const double value, - const types::global_dof_index i, - LinearAlgebra::TpetraWrappers::Vector &V) + ElementAccess>::add( + const typename VectorType::value_type value, + const types::global_dof_index i, + LinearAlgebra::TpetraWrappers::Vector &V) { // Extract local indices in the vector. - Tpetra::Vector vector = + Tpetra::Vector vector = V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); - vector.sync(); - auto vector_2d = vector.getLocalView(); + vector.template sync(); + auto vector_2d = vector.template getLocalView(); auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); // We're going to modify the data on host. - vector.modify(); - vector_1d(trilinos_i) = value; - vector.sync:: - device_type::memory_space>(); + vector.template modify(); + vector_1d(trilinos_i) += value; + vector.template sync< + typename Tpetra::Vector:: + device_type::memory_space>(); } - template <> + template inline void - ElementAccess>::set( - const float value, - const types::global_dof_index i, - LinearAlgebra::TpetraWrappers::Vector &V) + ElementAccess>::set( + const typename VectorType::value_type value, + const types::global_dof_index i, + LinearAlgebra::TpetraWrappers::Vector &V) { // Extract local indices in the vector. - Tpetra::Vector vector = + Tpetra::Vector vector = V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); - vector.sync(); - auto vector_2d = vector.getLocalView(); + vector.template sync(); + auto vector_2d = vector.template getLocalView(); auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); // We're going to modify the data on host. - vector.modify(); + vector.template modify(); vector_1d(trilinos_i) = value; - vector.sync:: - device_type::memory_space>(); + vector.template sync< + typename Tpetra::Vector:: + device_type::memory_space>(); } - template <> - inline double - ElementAccess>::get( - const LinearAlgebra::TpetraWrappers::Vector &V, - const types::global_dof_index i) - { - // Extract local indices in the vector. - Tpetra::Vector vector = - V.trilinos_vector(); - TrilinosWrappers::types::int_type trilinos_i = - vector.getMap()->getLocalElement( - static_cast(i)); - - vector.sync(); - auto vector_2d = vector.getLocalView(); - auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); - // We're going to modify the data on host. - return vector_1d(trilinos_i); - } - - - - template <> - inline float - ElementAccess>::get( - const LinearAlgebra::TpetraWrappers::Vector &V, - const types::global_dof_index i) + template + inline typename LinearAlgebra::TpetraWrappers::Vector::value_type + ElementAccess>::get( + const LinearAlgebra::TpetraWrappers::Vector &V, + const types::global_dof_index i) { // Extract local indices in the vector. - Tpetra::Vector vector = + Tpetra::Vector vector = V.trilinos_vector(); TrilinosWrappers::types::int_type trilinos_i = vector.getMap()->getLocalElement( static_cast(i)); - vector.sync(); - auto vector_2d = vector.getLocalView(); + vector.template sync(); + auto vector_2d = vector.template getLocalView(); auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); // We're going to modify the data on host. return vector_1d(trilinos_i); From bc11b29a358853de1152cd9d358049a0bbee19f4 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 18 Feb 2019 15:00:10 +0100 Subject: [PATCH 165/507] Call the base class constructor explicitly --- source/lac/trilinos_epetra_vector.cc | 6 ++++-- source/lac/trilinos_tpetra_vector.cc | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/source/lac/trilinos_epetra_vector.cc b/source/lac/trilinos_epetra_vector.cc index cc1857686f9b..64f2daad3fcf 100644 --- a/source/lac/trilinos_epetra_vector.cc +++ b/source/lac/trilinos_epetra_vector.cc @@ -41,7 +41,8 @@ namespace LinearAlgebra namespace EpetraWrappers { Vector::Vector() - : vector(new Epetra_FEVector( + : Subscriptor() + , vector(new Epetra_FEVector( Epetra_Map(0, 0, 0, Utilities::Trilinos::comm_self()))) {} @@ -56,7 +57,8 @@ namespace LinearAlgebra Vector::Vector(const IndexSet ¶llel_partitioner, const MPI_Comm &communicator) - : vector(new Epetra_FEVector( + : Subscriptor() + , vector(new Epetra_FEVector( parallel_partitioner.make_trilinos_map(communicator, false))) {} diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc index 451acc9ce3c4..7df8249fd6c0 100644 --- a/source/lac/trilinos_tpetra_vector.cc +++ b/source/lac/trilinos_tpetra_vector.cc @@ -42,7 +42,8 @@ namespace LinearAlgebra { template Vector::Vector() - : vector(new Tpetra::Vector( + : Subscriptor() + , vector(new Tpetra::Vector( Teuchos::RCP>( new Tpetra::Map( 0, @@ -65,7 +66,8 @@ namespace LinearAlgebra template Vector::Vector(const IndexSet ¶llel_partitioner, const MPI_Comm &communicator) - : vector(new Tpetra::Vector( + : Subscriptor() + , vector(new Tpetra::Vector( Teuchos::rcp(new Tpetra::Map( parallel_partitioner.make_tpetra_map(communicator, false))))) {} From ed90c83bc159d2cd4917e3d0f926f75f69a2fd27 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 18 Feb 2019 18:28:50 +0100 Subject: [PATCH 166/507] Clarify TODO for operator+= --- source/lac/trilinos_tpetra_vector.cc | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc index 7df8249fd6c0..ea218f8309f8 100644 --- a/source/lac/trilinos_tpetra_vector.cc +++ b/source/lac/trilinos_tpetra_vector.cc @@ -257,7 +257,7 @@ namespace LinearAlgebra // Downcast V. If fails, throws an exception. const Vector &down_V = dynamic_cast &>(V); - // If the maps are the same we can Update right away. + // If the maps are the same we can update right away. if (vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap()))) { vector->update(1., down_V.trilinos_vector(), 1.); @@ -267,21 +267,16 @@ namespace LinearAlgebra Assert(this->size() == down_V.size(), ExcDimensionMismatch(this->size(), down_V.size())); - // TODO: The code doesn't work as expected so we use a workaround. - /*Tpetra::Export - data_exchange(vector->getMap(), down_V.trilinos_vector().getMap()); - vector->doExport(down_V.trilinos_vector(), - data_exchange, - Tpetra::ADD);*/ - + // TODO: Tpetra doesn't have a combine mode that also updates local + // elements, maybe there is a better workaround. Tpetra::Vector dummy( vector->getMap(), false); Tpetra::Import data_exchange( - dummy.getMap(), down_V.trilinos_vector().getMap()); + down_V.trilinos_vector().getMap(), dummy.getMap()); - dummy.doExport(down_V.trilinos_vector(), + dummy.doImport(down_V.trilinos_vector(), data_exchange, - Tpetra::REPLACE); + Tpetra::INSERT); vector->update(1.0, dummy, 1.0); } From 8fa282a2c8ca4dc339fce857d0d8d085b3cd3d93 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 18 Feb 2019 18:30:50 +0100 Subject: [PATCH 167/507] Document some return values a bit better --- include/deal.II/lac/trilinos_sparse_matrix.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/deal.II/lac/trilinos_sparse_matrix.h b/include/deal.II/lac/trilinos_sparse_matrix.h index 4f8e955cb869..183875e6bec3 100644 --- a/include/deal.II/lac/trilinos_sparse_matrix.h +++ b/include/deal.II/lac/trilinos_sparse_matrix.h @@ -1578,6 +1578,7 @@ namespace TrilinosWrappers * * This function will be called when the underlying number type for the * matrix object and the one for the vector object are the same. + * Despite looking complicated, the return type is just `void`. * * In case of a serial vector, this function will only work when * running on one processor, since the matrix object is inherently @@ -1592,6 +1593,7 @@ namespace TrilinosWrappers * Same as the function above for the case that the underlying number type * for the matrix object and the one for the vector object do not coincide. * This case is not implemented. Calling it will result in a runtime error. + * Despite looking complicated, the return type is just `void`. */ template typename std::enable_if typename std::enable_if typename std::enable_if Date: Wed, 20 Feb 2019 15:54:10 +0100 Subject: [PATCH 168/507] Avoid ambiguous function declaration/variable initialization --- include/deal.II/lac/block_linear_operator.h | 21 ++++++++-------- include/deal.II/lac/linear_operator.h | 28 ++++++++++----------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/include/deal.II/lac/block_linear_operator.h b/include/deal.II/lac/block_linear_operator.h index 50868de147f5..12f9aba972a9 100644 --- a/include/deal.II/lac/block_linear_operator.h +++ b/include/deal.II/lac/block_linear_operator.h @@ -623,8 +623,8 @@ block_operator(const BlockMatrixType &block_matrix) using BlockType = typename BlockLinearOperator::BlockType; - BlockLinearOperator return_op( - BlockPayload(block_matrix, block_matrix)); + BlockLinearOperator return_op{ + BlockPayload(block_matrix, block_matrix)}; return_op.n_block_rows = [&block_matrix]() -> unsigned int { return block_matrix.n_block_rows(); @@ -698,9 +698,8 @@ block_operator( using BlockType = typename BlockLinearOperator::BlockType; - BlockLinearOperator return_op( - (BlockPayload())); // TODO: Create block payload so that this can be - // initialized correctly + // TODO: Create block payload so that this can be initialized correctly + BlockLinearOperator return_op{BlockPayload()}; return_op.n_block_rows = []() -> unsigned int { return m; }; @@ -744,8 +743,8 @@ block_diagonal_operator(const BlockMatrixType &block_matrix) using BlockType = typename BlockLinearOperator::BlockType; - BlockLinearOperator return_op( - BlockPayload(block_matrix, block_matrix)); + BlockLinearOperator return_op{ + BlockPayload(block_matrix, block_matrix)}; return_op.n_block_rows = [&block_matrix]() -> unsigned int { return block_matrix.n_block_rows(); @@ -910,8 +909,8 @@ block_forward_substitution( const BlockLinearOperator &block_operator, const BlockLinearOperator &diagonal_inverse) { - LinearOperator return_op( - (typename BlockPayload::BlockType(diagonal_inverse))); + LinearOperator return_op{ + typename BlockPayload::BlockType(diagonal_inverse)}; return_op.reinit_range_vector = diagonal_inverse.reinit_range_vector; return_op.reinit_domain_vector = diagonal_inverse.reinit_domain_vector; @@ -1025,8 +1024,8 @@ block_back_substitution( const BlockLinearOperator &block_operator, const BlockLinearOperator &diagonal_inverse) { - LinearOperator return_op( - (typename BlockPayload::BlockType(diagonal_inverse))); + LinearOperator return_op{ + typename BlockPayload::BlockType(diagonal_inverse)}; return_op.reinit_range_vector = diagonal_inverse.reinit_range_vector; return_op.reinit_domain_vector = diagonal_inverse.reinit_domain_vector; diff --git a/include/deal.II/lac/linear_operator.h b/include/deal.II/lac/linear_operator.h index b8e118fe112c..00b19126e099 100644 --- a/include/deal.II/lac/linear_operator.h +++ b/include/deal.II/lac/linear_operator.h @@ -389,9 +389,9 @@ operator+(const LinearOperator &first_op, } else { - LinearOperator return_op( + LinearOperator return_op{ static_cast(first_op) + - static_cast(second_op)); + static_cast(second_op)}; return_op.reinit_range_vector = first_op.reinit_range_vector; return_op.reinit_domain_vector = first_op.reinit_domain_vector; @@ -585,9 +585,9 @@ operator*(const LinearOperator & first_op, } else { - LinearOperator return_op( + LinearOperator return_op{ static_cast(first_op) * - static_cast(second_op)); + static_cast(second_op)}; return_op.reinit_domain_vector = second_op.reinit_domain_vector; return_op.reinit_range_vector = first_op.reinit_range_vector; @@ -649,7 +649,7 @@ template LinearOperator transpose_operator(const LinearOperator &op) { - LinearOperator return_op(op.transpose_payload()); + LinearOperator return_op{op.transpose_payload()}; return_op.reinit_range_vector = op.reinit_domain_vector; return_op.reinit_domain_vector = op.reinit_range_vector; @@ -693,8 +693,8 @@ inverse_operator(const LinearOperator &op, Solver & solver, const Preconditioner & preconditioner) { - LinearOperator return_op( - op.inverse_payload(solver, preconditioner)); + LinearOperator return_op{ + op.inverse_payload(solver, preconditioner)}; return_op.reinit_range_vector = op.reinit_domain_vector; return_op.reinit_domain_vector = op.reinit_range_vector; @@ -750,8 +750,8 @@ inverse_operator(const LinearOperator &op, Solver & solver, const LinearOperator &preconditioner) { - LinearOperator return_op( - op.inverse_payload(solver, preconditioner)); + LinearOperator return_op{ + op.inverse_payload(solver, preconditioner)}; return_op.reinit_range_vector = op.reinit_domain_vector; return_op.reinit_domain_vector = op.reinit_range_vector; @@ -856,7 +856,7 @@ template < LinearOperator identity_operator(const std::function &reinit_vector) { - LinearOperator return_op((Payload())); + LinearOperator return_op{Payload()}; return_op.reinit_range_vector = reinit_vector; return_op.reinit_domain_vector = reinit_vector; @@ -909,7 +909,7 @@ template LinearOperator null_operator(const LinearOperator &op) { - LinearOperator return_op(op.null_payload()); + LinearOperator return_op{op.null_payload()}; return_op.is_null_operator = true; @@ -946,7 +946,7 @@ template < LinearOperator mean_value_filter(const std::function &reinit_vector) { - LinearOperator return_op((Payload())); + LinearOperator return_op{Payload()}; return_op.reinit_range_vector = reinit_vector; return_op.reinit_domain_vector = reinit_vector; @@ -1402,8 +1402,8 @@ linear_operator(const OperatorExemplar &operator_exemplar, const Matrix &matrix) { using namespace internal::LinearOperatorImplementation; // Initialize the payload based on the input exemplar matrix - LinearOperator return_op( - Payload(operator_exemplar, matrix)); + LinearOperator return_op{ + Payload(operator_exemplar, matrix)}; // Always store a reference to matrix and operator_exemplar in the lambda // functions. This ensures that a modification of the matrix after the From 01fbb861229284937d9a783eeb6b5bf421d4a1ab Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 20 Feb 2019 16:49:54 +0100 Subject: [PATCH 169/507] Add a few more TpetraWrappers and EpetraWrapper tests with a matrix-vector product --- include/deal.II/lac/trilinos_sparse_matrix.h | 1 + tests/trilinos/sparse_matrix_vector_12.cc | 126 ++++++++++++++++++ tests/trilinos/sparse_matrix_vector_12.output | 2 + tests/trilinos/sparse_matrix_vector_13.cc | 125 +++++++++++++++++ tests/trilinos/sparse_matrix_vector_13.output | 2 + tests/trilinos/sparse_matrix_vector_14.cc | 126 ++++++++++++++++++ tests/trilinos/sparse_matrix_vector_14.output | 2 + tests/trilinos/sparse_matrix_vector_15.cc | 125 +++++++++++++++++ tests/trilinos/sparse_matrix_vector_15.output | 2 + 9 files changed, 511 insertions(+) create mode 100644 tests/trilinos/sparse_matrix_vector_12.cc create mode 100644 tests/trilinos/sparse_matrix_vector_12.output create mode 100644 tests/trilinos/sparse_matrix_vector_13.cc create mode 100644 tests/trilinos/sparse_matrix_vector_13.output create mode 100644 tests/trilinos/sparse_matrix_vector_14.cc create mode 100644 tests/trilinos/sparse_matrix_vector_14.output create mode 100644 tests/trilinos/sparse_matrix_vector_15.cc create mode 100644 tests/trilinos/sparse_matrix_vector_15.output diff --git a/include/deal.II/lac/trilinos_sparse_matrix.h b/include/deal.II/lac/trilinos_sparse_matrix.h index 183875e6bec3..b07e06c6f3c0 100644 --- a/include/deal.II/lac/trilinos_sparse_matrix.h +++ b/include/deal.II/lac/trilinos_sparse_matrix.h @@ -1566,6 +1566,7 @@ namespace TrilinosWrappers *
      *
    • TrilinosWrappers::MPI::Vector, *
    • LinearAlgebra::EpetraWrappers::Vector, + *
    • LinearAlgebra::TpetraWrappers::Vector, *
    • Vector, *
    • LinearAlgebra::distributed::Vector. *
    diff --git a/tests/trilinos/sparse_matrix_vector_12.cc b/tests/trilinos/sparse_matrix_vector_12.cc new file mode 100644 index 000000000000..398cf9150aa5 --- /dev/null +++ b/tests/trilinos/sparse_matrix_vector_12.cc @@ -0,0 +1,126 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2013 - 2017 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. +// +// --------------------------------------------------------------------- + + + +// check SparseMatrix::vmult, vmult_add with +// LinearAlgebra::EpetraWrappers::Vector + +#include + +#include +#include +#include + +#include +#include + +#include "../tests.h" + + +void +test(LinearAlgebra::EpetraWrappers::Vector &v, + LinearAlgebra::EpetraWrappers::Vector &w) +{ + LinearAlgebra::ReadWriteVector read_write_v(v.size()); + LinearAlgebra::ReadWriteVector read_write_w(w.size()); + + TrilinosWrappers::SparseMatrix m(w.size(), v.size(), v.size()); + for (unsigned int i = 0; i < m.m(); ++i) + for (unsigned int j = 0; j < m.n(); ++j) + m.set(i, j, i + 2 * j); + + for (unsigned int i = 0; i < v.size(); ++i) + read_write_v(i) = i; + + m.compress(VectorOperation::insert); + v.import(read_write_v, VectorOperation::insert); + + // w:=Mv + m.vmult(w, v); + + // make sure we get the expected result + read_write_w.import(w, VectorOperation::insert); + for (unsigned int i = 0; i < m.m(); ++i) + { + double result = 0; + for (unsigned int j = 0; j < m.n(); ++j) + result += (i + 2 * j) * j; + AssertThrow(read_write_w(i) == result, ExcInternalError()); + } + + m.vmult_add(w, v); + + // make sure we get the expected result + read_write_w.import(w, VectorOperation::insert); + for (unsigned int i = 0; i < m.m(); ++i) + { + double result = 0; + for (unsigned int j = 0; j < m.n(); ++j) + result += (i + 2 * j) * j; + AssertThrow(read_write_w(i) == result + result, ExcInternalError()); + } + + deallog << "OK" << std::endl; +} + + + +int +main(int argc, char **argv) +{ + initlog(); + + Utilities::MPI::MPI_InitFinalize mpi_initialization( + argc, argv, testing_max_num_threads()); + + + try + { + { + LinearAlgebra::EpetraWrappers::Vector v(complete_index_set(100), + MPI_COMM_SELF); + LinearAlgebra::EpetraWrappers::Vector w(complete_index_set(95), + MPI_COMM_SELF); + test(v, w); + } + } + 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; + }; +} diff --git a/tests/trilinos/sparse_matrix_vector_12.output b/tests/trilinos/sparse_matrix_vector_12.output new file mode 100644 index 000000000000..0fd8fc12f0b4 --- /dev/null +++ b/tests/trilinos/sparse_matrix_vector_12.output @@ -0,0 +1,2 @@ + +DEAL::OK diff --git a/tests/trilinos/sparse_matrix_vector_13.cc b/tests/trilinos/sparse_matrix_vector_13.cc new file mode 100644 index 000000000000..e13c99656c5a --- /dev/null +++ b/tests/trilinos/sparse_matrix_vector_13.cc @@ -0,0 +1,125 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2013 - 2017 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. +// +// --------------------------------------------------------------------- + + + +// check SparseMatrix::Tvmult, Tvmult_add with +// LinearAlgebra::EpetraWrappers::Vector + +#include + +#include +#include +#include + +#include +#include + +#include "../tests.h" + + +void +test(LinearAlgebra::EpetraWrappers::Vector &v, + LinearAlgebra::EpetraWrappers::Vector &w) +{ + LinearAlgebra::ReadWriteVector read_write_v(v.size()); + LinearAlgebra::ReadWriteVector read_write_w(w.size()); + + TrilinosWrappers::SparseMatrix m(v.size(), w.size(), w.size()); + for (unsigned int i = 0; i < m.m(); ++i) + for (unsigned int j = 0; j < m.n(); ++j) + m.set(i, j, i + 2 * j); + + for (unsigned int i = 0; i < v.size(); ++i) + read_write_v(i) = i; + + m.compress(VectorOperation::insert); + v.import(read_write_v, VectorOperation::insert); + + // w:=Mv + m.Tvmult(w, v); + + // make sure we get the expected result + read_write_w.import(w, VectorOperation::insert); + for (unsigned int i = 0; i < m.n(); ++i) + { + double result = 0; + for (unsigned int j = 0; j < m.m(); ++j) + result += (j + 2 * i) * j; + AssertThrow(read_write_w(i) == result, ExcInternalError()); + } + + m.Tvmult_add(w, v); + // make sure we get the expected result + read_write_w.import(w, VectorOperation::insert); + for (unsigned int i = 0; i < m.n(); ++i) + { + double result = 0; + for (unsigned int j = 0; j < m.m(); ++j) + result += (j + 2 * i) * j; + AssertThrow(read_write_w(i) == result + result, ExcInternalError()); + } + + deallog << "OK" << std::endl; +} + + + +int +main(int argc, char **argv) +{ + initlog(); + + Utilities::MPI::MPI_InitFinalize mpi_initialization( + argc, argv, testing_max_num_threads()); + + + try + { + { + LinearAlgebra::EpetraWrappers::Vector v(complete_index_set(95), + MPI_COMM_SELF); + LinearAlgebra::EpetraWrappers::Vector w(complete_index_set(100), + MPI_COMM_SELF); + test(v, w); + } + } + 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; + }; +} diff --git a/tests/trilinos/sparse_matrix_vector_13.output b/tests/trilinos/sparse_matrix_vector_13.output new file mode 100644 index 000000000000..0fd8fc12f0b4 --- /dev/null +++ b/tests/trilinos/sparse_matrix_vector_13.output @@ -0,0 +1,2 @@ + +DEAL::OK diff --git a/tests/trilinos/sparse_matrix_vector_14.cc b/tests/trilinos/sparse_matrix_vector_14.cc new file mode 100644 index 000000000000..fed0ac1c8594 --- /dev/null +++ b/tests/trilinos/sparse_matrix_vector_14.cc @@ -0,0 +1,126 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2013 - 2017 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. +// +// --------------------------------------------------------------------- + + + +// check SparseMatrix::vmult, vmult_add with +// LinearAlgebra::TpetraWrappers::Vector + +#include + +#include +#include +#include + +#include +#include + +#include "../tests.h" + + +void +test(LinearAlgebra::TpetraWrappers::Vector &v, + LinearAlgebra::TpetraWrappers::Vector &w) +{ + LinearAlgebra::ReadWriteVector read_write_v(v.size()); + LinearAlgebra::ReadWriteVector read_write_w(w.size()); + + TrilinosWrappers::SparseMatrix m(w.size(), v.size(), v.size()); + for (unsigned int i = 0; i < m.m(); ++i) + for (unsigned int j = 0; j < m.n(); ++j) + m.set(i, j, i + 2 * j); + + for (unsigned int i = 0; i < v.size(); ++i) + read_write_v(i) = i; + + m.compress(VectorOperation::insert); + v.import(read_write_v, VectorOperation::insert); + + // w:=Mv + m.vmult(w, v); + + // make sure we get the expected result + read_write_w.import(w, VectorOperation::insert); + for (unsigned int i = 0; i < m.m(); ++i) + { + double result = 0; + for (unsigned int j = 0; j < m.n(); ++j) + result += (i + 2 * j) * j; + AssertThrow(read_write_w(i) == result, ExcInternalError()); + } + + m.vmult_add(w, v); + + // make sure we get the expected result + read_write_w.import(w, VectorOperation::insert); + for (unsigned int i = 0; i < m.m(); ++i) + { + double result = 0; + for (unsigned int j = 0; j < m.n(); ++j) + result += (i + 2 * j) * j; + AssertThrow(read_write_w(i) == result + result, ExcInternalError()); + } + + deallog << "OK" << std::endl; +} + + + +int +main(int argc, char **argv) +{ + initlog(); + + Utilities::MPI::MPI_InitFinalize mpi_initialization( + argc, argv, testing_max_num_threads()); + + + try + { + { + LinearAlgebra::TpetraWrappers::Vector v(complete_index_set(100), + MPI_COMM_SELF); + LinearAlgebra::TpetraWrappers::Vector w(complete_index_set(95), + MPI_COMM_SELF); + test(v, w); + } + } + 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; + }; +} diff --git a/tests/trilinos/sparse_matrix_vector_14.output b/tests/trilinos/sparse_matrix_vector_14.output new file mode 100644 index 000000000000..0fd8fc12f0b4 --- /dev/null +++ b/tests/trilinos/sparse_matrix_vector_14.output @@ -0,0 +1,2 @@ + +DEAL::OK diff --git a/tests/trilinos/sparse_matrix_vector_15.cc b/tests/trilinos/sparse_matrix_vector_15.cc new file mode 100644 index 000000000000..870712bbe8a9 --- /dev/null +++ b/tests/trilinos/sparse_matrix_vector_15.cc @@ -0,0 +1,125 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2013 - 2017 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. +// +// --------------------------------------------------------------------- + + + +// check SparseMatrix::Tvmult, Tvmult_add with +// LinearAlgebra::TpetraWrappers::Vector + +#include + +#include +#include +#include + +#include +#include + +#include "../tests.h" + + +void +test(LinearAlgebra::TpetraWrappers::Vector &v, + LinearAlgebra::TpetraWrappers::Vector &w) +{ + LinearAlgebra::ReadWriteVector read_write_v(v.size()); + LinearAlgebra::ReadWriteVector read_write_w(w.size()); + + TrilinosWrappers::SparseMatrix m(v.size(), w.size(), w.size()); + for (unsigned int i = 0; i < m.m(); ++i) + for (unsigned int j = 0; j < m.n(); ++j) + m.set(i, j, i + 2 * j); + + for (unsigned int i = 0; i < v.size(); ++i) + read_write_v(i) = i; + + m.compress(VectorOperation::insert); + v.import(read_write_v, VectorOperation::insert); + + // w:=Mv + m.Tvmult(w, v); + + // make sure we get the expected result + read_write_w.import(w, VectorOperation::insert); + for (unsigned int i = 0; i < m.n(); ++i) + { + double result = 0; + for (unsigned int j = 0; j < m.m(); ++j) + result += (j + 2 * i) * j; + AssertThrow(read_write_w(i) == result, ExcInternalError()); + } + + m.Tvmult_add(w, v); + // make sure we get the expected result + read_write_w.import(w, VectorOperation::insert); + for (unsigned int i = 0; i < m.n(); ++i) + { + double result = 0; + for (unsigned int j = 0; j < m.m(); ++j) + result += (j + 2 * i) * j; + AssertThrow(read_write_w(i) == result + result, ExcInternalError()); + } + + deallog << "OK" << std::endl; +} + + + +int +main(int argc, char **argv) +{ + initlog(); + + Utilities::MPI::MPI_InitFinalize mpi_initialization( + argc, argv, testing_max_num_threads()); + + + try + { + { + LinearAlgebra::TpetraWrappers::Vector v(complete_index_set(95), + MPI_COMM_SELF); + LinearAlgebra::TpetraWrappers::Vector w(complete_index_set(100), + MPI_COMM_SELF); + test(v, w); + } + } + 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; + }; +} diff --git a/tests/trilinos/sparse_matrix_vector_15.output b/tests/trilinos/sparse_matrix_vector_15.output new file mode 100644 index 000000000000..0fd8fc12f0b4 --- /dev/null +++ b/tests/trilinos/sparse_matrix_vector_15.output @@ -0,0 +1,2 @@ + +DEAL::OK From eab549f6c93135c761dc8e0dd772ec9542a3fd1f Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 20 Feb 2019 15:53:31 +0100 Subject: [PATCH 170/507] Fix linear operator --- include/deal.II/lac/linear_operator.h | 2 +- include/deal.II/lac/read_write_vector.templates.h | 4 ++-- source/base/utilities.cc | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/deal.II/lac/linear_operator.h b/include/deal.II/lac/linear_operator.h index b8e118fe112c..2947a092d400 100644 --- a/include/deal.II/lac/linear_operator.h +++ b/include/deal.II/lac/linear_operator.h @@ -856,7 +856,7 @@ template < LinearOperator identity_operator(const std::function &reinit_vector) { - LinearOperator return_op((Payload())); + LinearOperator return_op{Payload()}; return_op.reinit_range_vector = reinit_vector; return_op.reinit_domain_vector = reinit_vector; diff --git a/include/deal.II/lac/read_write_vector.templates.h b/include/deal.II/lac/read_write_vector.templates.h index cfbbc7db890b..c2854d9af276 100644 --- a/include/deal.II/lac/read_write_vector.templates.h +++ b/include/deal.II/lac/read_write_vector.templates.h @@ -874,7 +874,7 @@ namespace LinearAlgebra for (unsigned int i = 0; i < n_elements; ++i) { Assert( - std::imag(new_values[i]) == 0., + std::imag(tmp[i]) == 0., ExcMessage( "VectorOperation::min is not defined if there is an imaginary part!)")); Assert( @@ -898,7 +898,7 @@ namespace LinearAlgebra for (unsigned int i = 0; i < n_elements; ++i) { Assert( - std::imag(new_values[i]) == 0., + std::imag(tmp[i]) == 0., ExcMessage( "VectorOperation::max is not defined if there is an imaginary part!)")); Assert( diff --git a/source/base/utilities.cc b/source/base/utilities.cc index d5f120192bf6..c09874105d4e 100644 --- a/source/base/utilities.cc +++ b/source/base/utilities.cc @@ -60,6 +60,7 @@ # include # include +# include # endif # include # include From cb435e24a1f9c72adc9759363d4e845ec0b23970 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Fri, 15 Feb 2019 11:52:49 +0100 Subject: [PATCH 171/507] AD Helpers: Add helper for scalar functions (QP-level) --- .../changes/major/20190220Jean-PaulPelteret | 9 + .../deal.II/differentiation/ad/ad_helpers.h | 447 ++++++++++++++++++ source/differentiation/ad/ad_helpers.cc | 329 +++++++++++++ source/differentiation/ad/ad_helpers.inst1.in | 16 + source/differentiation/ad/ad_helpers.inst2.in | 28 ++ 5 files changed, 829 insertions(+) create mode 100644 doc/news/changes/major/20190220Jean-PaulPelteret diff --git a/doc/news/changes/major/20190220Jean-PaulPelteret b/doc/news/changes/major/20190220Jean-PaulPelteret new file mode 100644 index 000000000000..c9df4e7cb7ca --- /dev/null +++ b/doc/news/changes/major/20190220Jean-PaulPelteret @@ -0,0 +1,9 @@ +New: A new class Differentiation::AD::ADHelperScalarFunction 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/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index 4f36c1dbfe11..f884ee469481 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -2934,6 +2934,352 @@ namespace Differentiation }; // class ADHelperPointLevelFunctionsBase + + /** + * A helper class that facilitates the evaluation of a scalar function, + * its first derivatives (gradient), and its second derivatives (Hessian). + * This class would typically be used to compute the first and second + * derivatives of a stored energy function defined at a quadrature + * point. It can also be used to compute derivatives of any other scalar + * field so long as all its dependencies on the independent variables are + * explicit (that is to say, no independent variables may have some implicit + * dependence on one another). + * + * An example of its usage in the case of a multi-field constitutive law + * might be as follows: + * @code + * // Define some extractors that will help us set independent variables + * // and later get the computed values related to the dependent + * // variables. Each of these extractors is related to the gradient of a + * // component of the solution field (in this case, displacement and + * // magnetic scalar potential). Here "C" is the right Cauchy-Green + * // tensor and "H" is the magnetic field. + * const FEValuesExtractors::SymmetricTensor<2> C_dofs (0); + * const FEValuesExtractors::Vector H_dofs + * (dealii::SymmetricTensor<2,dim>::n_independent_components); + * const unsigned int n_independent_variables = + * SymmetricTensor<2,dim>::n_independent_components + + * Tensor<1,dim>::n_independent_components; + * + * // Define the helper that we will use in the AD computations for our + * // scalar energy function. Note that we expect it to return values of + * // type double. + * ADHelperScalarFunction ad_helper (n_independent_variables); + * using ADNumberType = typename ADHelper::ad_type; + * + * // Compute the fields that provide the independent values. + * // When the tape is being replayed, these should be set to something + * // meaningful. + * const Tensor<1,dim> H = ...; + * const SymmetricTensor<2,dim> C = ...; + * + * // If using a taped AD number, then at this point we would initiate + * // taping of the expression for the material stored energy function + * // for this particular set of material parameters: + * + * // Select a tape number to record to + * const typename Types::tape_index tape_index = ...; + * + * // Indicate that we are about to start tracing the operations for + * // function evaluation on the tape. If this tape has already been + * // used (i.e., the operations are already recorded) then we + * // (optionally) load the tape and reuse this data. + * const bool is_recording + * = ad_helper.start_recording_operations(tape_index); + * + * // The steps that follow in the recording phase are required for + * // tapeless methods as well. + * if (is_recording == true) + * { + * // This is the "recording" phase of the operations. + * + * // First, we set the values for all fields. + * // These could happily be set to anything, unless the function will + * // be evaluated along a branch not otherwise traversed during later + * // use. For this reason, in this example instead of using some dummy + * // values, we'll actually map out the function at the same point + * // around which we'll later linearize it. + * ad_helper.register_independent_variable(H, H_dofs); + * ad_helper.register_independent_variable(C, C_dofs); + * + * // NOTE: We have to extract the sensitivities in the order we wish to + * // introduce them. So this means we have to do it by logical order + * // of the extractors that we've created. + * const SymmetricTensor<2,dim,ADNumberType> C_AD = + * ad_helper.get_sensitive_variables(C_dofs); const + * const Tensor<1,dim,ADNumberType> H_AD = + * ad_helper.get_sensitive_variables(H_dofs); + * + * // Here we define the material stored energy function. + * // This example is sufficiently complex to warrant the use of AD to, + * // at the very least, verify an unassisted implementation. + * const double mu_e = 10; // Shear modulus + * const double lambda_e = 15; // Lame parameter + * const double mu_0 = 4*M_PI*1e-7; // Magnetic permeability constant + * const double mu_r = 5; // Relative magnetic permeability + * + * const ADNumberType J = std::sqrt(determinant(C_AD)); + * const SymmetricTensor<2,dim,ADNumberType> C_inv_AD = invert(C_AD); + * const ADNumberType psi = + * 0.5*mu_e*(1.0+std::tanh((H_AD*H_AD)/100.0))* + * (trace(C_AD) - dim - 2*std::log(J)) + + * lambda_e*std::log(J)*std::log(J) - + * 0.5*mu_0*mu_r*J*H_AD*C_inv_AD*H_AD; + * + * // Register the definition of the total stored energy + * ad_helper.register_dependent_variable(psi_CH); + * + * // Indicate that we have completed tracing the operations onto + * // the tape. + * ad_helper.stop_recording_operations(false); // write_tapes_to_file + * } + * else + * { + * // This is the "tape reuse" phase of the operations. + * // Here we will leverage the already traced operations that reside + * // on a tape, and simply re-evaluate the tape at a different point + * // to get the function values and their derivatives. + * + * // Load the existing tape to be reused + * ad_helper.activate_recorded_tape(tape_index); + * + * // Set the new values of the independent variables where the + * // recorded dependent functions are to be evaluated (and + * // differentiated around). + * ad_helper.set_independent_variable(C, C_dofs); + * ad_helper.set_independent_variable(H, H_dofs); + * } + * + * // Play the tape and store the output function value, its gradient and + * // linearization. These are expensive to compute, so we'll do this once + * // and extract the desired values from these intermediate outputs. + * Vector Dpsi (ad_helper.n_dependent_variables()); + * FullMatrix D2psi (ad_helper.n_dependent_variables(), + * ad_helper.n_dependent_variables()); + * const double psi = ad_helper.compute_value(); + * ad_helper.compute_gradient(Dpsi); + * ad_helper.compute_hessian(D2psi); + * + * // Extract the desired components of the gradient vector and Hessian + * // matrix. In this example, we use them to compute the Piola-Kirchhoff + * // stress tensor and its associated tangent, defined by thermodynamic + * // arguments as S = 2*dpsi/dC and HH = 2*dS/dC... + * const SymmetricTensor<2,dim> S = + * 2.0*ad_helper.extract_gradient_component(Dpsi,C_dofs); + * const SymmetricTensor<4,dim> HH = + * 4.0*ad_helper.extract_hessian_component(D2psi,C_dofs,C_dofs); + * + * // ... the magnetic induction and its associated tangent defined + * // as B = -dpsi/dH and BB = dB/dH... + * const Tensor<1,dim> B = + * -ad_helper.extract_gradient_component(Dpsi,H_dofs); + * const SymmetricTensor<2,dim> BB = + * -symmetrize(ad_helper.extract_hessian_component(D2psi,H_dofs,H_dofs)); + * + * // ... and finally the magnetoelastic coupling tangent, defined + * // as PP = -dS/dH = -d/dH(2*dpsi/dC). Here the order of the extractor + * // arguments is especially important, as it dictates the order in which + * // the directional derivatives are taken. + * const Tensor<3,dim,double> PP = + * -2.0*ad_helper.extract_hessian_component(D2psi,C_dofs,H_dofs) + * @endcode + * + * @warning ADOL-C does not support the standard threading models used by + * deal.II, so this class should @b not be embedded within a multithreaded + * function when using ADOL-C number types. It is, however, suitable for use + * in both serial and MPI routines. + * + * @author Jean-Paul Pelteret, 2016, 2017, 2018 + */ + template + class ADHelperScalarFunction + : public ADHelperPointLevelFunctionsBase + { + public: + /** + * Type definition for the floating point number type that is used in, + * and results from, all computations. + */ + using scalar_type = + typename ADHelperBase::scalar_type; + + /** + * Type definition for the auto-differentiation number type that is used + * in all computations. + */ + using ad_type = + typename ADHelperBase::ad_type; + + /** + * @name Constructor / destructor + */ + //@{ + + /** + * The constructor for the class. + * + * @param[in] n_independent_variables The number of independent variables + * that will be used in the definition of the functions that it is + * desired to compute the sensitivities of. In the computation of + * $\mathbf{f}(\mathbf{X})$, this will be the number of inputs + * $\mathbf{X}$, i.e., the dimension of the domain space. + */ + ADHelperScalarFunction(const unsigned int n_independent_variables); + + /** + * Destructor. + */ + virtual ~ADHelperScalarFunction() = default; + + //@} + + /** + * @name Dependent variables + */ + //@{ + + /** + * Register the definition of the scalar field $\Psi(\mathbf{X})$. + * + * @param[in] func The recorded function that defines a dependent + * variable. + * + * @note For this class that expects only one dependent variable, this + * function must only be called once per tape. + * + * @note For taped AD numbers, this operation is only valid in recording mode. + */ + void + register_dependent_variable(const ad_type &func); + + /** + * Compute the value of the scalar field $\Psi(\mathbf{X})$ using the + * tape as opposed to executing the source code. + * + * @return A scalar object with the value for the scalar field evaluated + * at the point defined by the independent variable values. + */ + scalar_type + compute_value() const; + + /** + * Compute the gradient (first derivative) of the scalar field with + * respect to all independent variables, i.e. + * @f[ + * \frac{\partial\Psi(\mathbf{X})}{\partial\mathbf{X}} + * @f] + * + * @param[out] gradient A Vector with the values for the scalar field + * gradient (first derivatives) evaluated at the point defined by the + * independent variable values. + */ + void + compute_gradient(Vector &gradient) const; + + /** + * Compute the Hessian (second derivative) of the scalar field with + * respect to all independent variables, i.e. + * @f[ + * \frac{\partial^{2}\Psi(\mathbf{X})}{\partial\mathbf{X} \otimes + * \partial\mathbf{X}} + * @f] + * + * @param[out] hessian A FullMatrix with the values for the scalar field + * Hessian (second derivatives) evaluated at the point defined by the + * independent variable values. + */ + void + compute_hessian(FullMatrix &hessian) const; + + /** + * Extract the function gradient for a subset of independent variables + * $\mathbf{A} \subset \mathbf{X}$, i.e. + * @f[ + * \frac{\partial\Psi(\mathbf{X})}{\partial\mathbf{A}} + * @f] + * + * @param[in] gradient The gradient of the scalar function with respect to + * all independent variables, i.e. that returned by compute_gradient(). + * @param[in] extractor_row An extractor associated with the input field + * variables. This effectively defines which components of the global set + * of independent variables this field is associated with. + */ + template + typename internal::ScalarFieldGradient::type + extract_gradient_component(const Vector &gradient, + const ExtractorType_Row &extractor_row) const; + + /** + * Extract the function Hessian for a subset of independent variables + * $\mathbf{A},\mathbf{B} \subset \mathbf{X}$, i.e. + * @f[ + * \frac{}{\partial\mathbf{B}} \left[ + * \frac{\partial\Psi(\mathbf{X})}{\partial\mathbf{A}} \right] = + * \frac{\partial^{2}\Psi(\mathbf{X})}{\partial\mathbf{B} \otimes + * \partial\mathbf{A}} + * @f] + * + * @param[in] hessian The Hessian of the scalar function with respect to + * all independent variables, i.e. that returned by compute_hessian(). + * @param[in] extractor_row An extractor associated with the input field + * variables for which the first index of the Hessian is extracted. + * @param[in] extractor_col An extractor associated with the input field + * variables for which the second index of the Hessian is extracted. + */ + template + typename internal::ScalarFieldHessian::type + extract_hessian_component(const FullMatrix &hessian, + const ExtractorType_Row & extractor_row, + const ExtractorType_Col &extractor_col) const; + + /** + * Extract the function Hessian for a subset of independent variables + * $\mathbf{A},\mathbf{B} \subset \mathbf{X}$, i.e. + * @f[ + * \frac{}{\partial\mathbf{B}} \left[ + * \frac{\partial\Psi(\mathbf{X})}{\partial\mathbf{A}} \right] + * @f] + * + * This function is a specialization of the above for rank-0 tensors + * (scalars) + */ + Tensor<0, dim, scalar_type> + extract_hessian_component( + const FullMatrix & hessian, + const FEValuesExtractors::Scalar &extractor_row, + const FEValuesExtractors::Scalar &extractor_col) const; + + /** + * Extract the function Hessian for a subset of independent variables + * $\mathbf{A},\mathbf{B} \subset \mathbf{X}$, i.e. + * @f[ + * \frac{}{\partial\mathbf{B}} \left[ + * \frac{\partial\Psi(\mathbf{X})}{\partial\mathbf{A}} \right] + * @f] + * + * This function is a specialization of the above for rank-4 symmetric + * tensors + */ + SymmetricTensor<4, dim, scalar_type> + extract_hessian_component( + const FullMatrix & hessian, + const FEValuesExtractors::SymmetricTensor<2> &extractor_row, + const FEValuesExtractors::SymmetricTensor<2> &extractor_col) const; + + //@} + + }; // class ADHelperScalarFunction + + } // namespace AD } // namespace Differentiation @@ -3099,6 +3445,107 @@ namespace Differentiation } + + /* ----------------- ADHelperScalarFunction ----------------- */ + + + + template + template + typename internal::ScalarFieldGradient< + dim, + typename ADHelperScalarFunction:: + scalar_type, + ExtractorType_Row>::type + ADHelperScalarFunction:: + extract_gradient_component(const Vector &gradient, + const ExtractorType_Row & extractor_row) const + { + // NOTE: The order of components must be consistently defined throughout + // this class. + typename internal:: + ScalarFieldGradient::type out; + + // Get indexsets for the subblock from which we wish to extract the + // gradient values + const std::vector row_index_set( + internal::extract_field_component_indices(extractor_row)); + Assert(out.n_independent_components == row_index_set.size(), + ExcMessage("Not all tensor components have been extracted!")); + for (unsigned int r = 0; r < row_index_set.size(); ++r) + internal::set_tensor_entry(out, r, gradient[row_index_set[r]]); + + return out; + } + + + + template + template + typename internal::ScalarFieldHessian< + dim, + typename ADHelperScalarFunction:: + scalar_type, + ExtractorType_Row, + ExtractorType_Col>::type + ADHelperScalarFunction:: + extract_hessian_component(const FullMatrix &hessian, + const ExtractorType_Row & extractor_row, + const ExtractorType_Col &extractor_col) const + { + using InternalHessian = internal::ScalarFieldHessian; + using InternalExtractorRow = internal::Extractor; + using InternalExtractorCol = internal::Extractor; + using HessianType = typename InternalHessian::type; + + // NOTE: The order of components must be consistently defined throughout + // this class. + HessianType out; + + // Get indexsets for the subblocks from which we wish to extract the + // Hessian values + // NOTE: Here we have to do some clever accounting when the + // one extractor is a symmetric Tensor and the other is not, e.g. + // . In this scenario the return type is a + // non-symmetric Tensor<3,dim> but we have to fetch information from a + // SymmTensor row/column that has too few entries to fill the output + // tensor. So we must duplicate the relevant entries in the row/column + // indexset to fetch off-diagonal components that are Otherwise + // non-existent in a SymmTensor. + const std::vector row_index_set( + internal::extract_field_component_indices( + extractor_row, false /*ignore_symmetries*/)); + const std::vector col_index_set( + internal::extract_field_component_indices( + extractor_col, false /*ignore_symmetries*/)); + + for (unsigned int index = 0; + index < HessianType::n_independent_components; + ++index) + { + const TableIndices ti_out = + HessianType::unrolled_to_component_indices(index); + const unsigned int r = + InternalExtractorRow::local_component(ti_out, 0); + const unsigned int c = + InternalExtractorCol::local_component(ti_out, + InternalExtractorRow::rank); + + internal::set_tensor_entry( + out, index, hessian[row_index_set[r]][col_index_set[c]]); + } + + return out; + } + + } // namespace AD } // namespace Differentiation diff --git a/source/differentiation/ad/ad_helpers.cc b/source/differentiation/ad/ad_helpers.cc index 7789a475430b..a1e0809b5bfd 100644 --- a/source/differentiation/ad/ad_helpers.cc +++ b/source/differentiation/ad/ad_helpers.cc @@ -1312,6 +1312,335 @@ namespace Differentiation } + + /* -------------------- ADHelperScalarFunction -------------------- */ + + + + template + ADHelperScalarFunction:: + ADHelperScalarFunction(const unsigned int n_independent_variables) + : ADHelperPointLevelFunctionsBase( + n_independent_variables, + 1) + {} + + + + template + void + ADHelperScalarFunction:: + register_dependent_variable(const ad_type &func) + { + Assert(this->n_dependent_variables() == 1, ExcInternalError()); + ADHelperBase::register_dependent_variable( + 0, func); + } + + + + template + typename ADHelperScalarFunction:: + scalar_type + ADHelperScalarFunction::compute_value() + const + { + if ((ADNumberTraits::is_taped == true && + this->taped_driver.keep_independent_values() == false) || + ADNumberTraits::is_tapeless == true) + { + Assert( + this->n_registered_independent_variables() == + this->n_independent_variables(), + ExcMessage( + "Not all values of sensitivities have been registered or subsequently set!")); + } + Assert(this->n_registered_dependent_variables() == + this->n_dependent_variables(), + ExcMessage("Not all dependent variables have been registered.")); + + Assert( + this->n_dependent_variables() == 1, + ExcMessage( + "The ADHelperScalarFunction class expects there to be only one dependent variable.")); + + if (ADNumberTraits::is_taped == true) + { + Assert(this->active_tape_index() != + Numbers::invalid_tape_index, + ExcMessage("Invalid tape index")); + Assert(this->is_recording() == false, + ExcMessage( + "Cannot compute values while tape is being recorded.")); + Assert(this->independent_variable_values.size() == + this->n_independent_variables(), + ExcDimensionMismatch(this->independent_variable_values.size(), + this->n_independent_variables())); + + return this->taped_driver.value(this->active_tape_index(), + this->independent_variable_values); + } + else + { + Assert(ADNumberTraits::is_tapeless == true, + ExcInternalError()); + return this->tapeless_driver.value(this->dependent_variables); + } + } + + + template + void + ADHelperScalarFunction::compute_gradient( + Vector &gradient) const + { + if ((ADNumberTraits::is_taped == true && + this->taped_driver.keep_independent_values() == false) || + ADNumberTraits::is_tapeless == true) + { + Assert( + this->n_registered_independent_variables() == + this->n_independent_variables(), + ExcMessage( + "Not all values of sensitivities have been registered or subsequently set!")); + } + Assert(this->n_registered_dependent_variables() == + this->n_dependent_variables(), + ExcMessage("Not all dependent variables have been registered.")); + + Assert( + this->n_dependent_variables() == 1, + ExcMessage( + "The ADHelperScalarFunction class expects there to be only one dependent variable.")); + + // We can neglect correctly initializing the entries as + // we'll be overwriting them immediately in the succeeding call to + // Drivers::gradient(). + if (gradient.size() != this->n_independent_variables()) + gradient.reinit(this->n_independent_variables(), + true /*omit_zeroing_entries*/); + + if (ADNumberTraits::is_taped == true) + { + Assert(this->active_tape_index() != + Numbers::invalid_tape_index, + ExcMessage("Invalid tape index")); + Assert(this->is_recording() == false, + ExcMessage( + "Cannot compute gradient while tape is being recorded.")); + Assert(this->independent_variable_values.size() == + this->n_independent_variables(), + ExcDimensionMismatch(this->independent_variable_values.size(), + this->n_independent_variables())); + + this->taped_driver.gradient(this->active_tape_index(), + this->independent_variable_values, + gradient); + } + else + { + Assert(ADNumberTraits::is_tapeless == true, + ExcInternalError()); + Assert(this->independent_variables.size() == + this->n_independent_variables(), + ExcDimensionMismatch(this->independent_variables.size(), + this->n_independent_variables())); + + this->tapeless_driver.gradient(this->independent_variables, + this->dependent_variables, + gradient); + } + + // Account for symmetries of tensor components + for (unsigned int i = 0; i < this->n_independent_variables(); i++) + { + if (this->is_symmetric_independent_variable(i) == true) + gradient[i] *= 0.5; + } + } + + + + template + void + ADHelperScalarFunction::compute_hessian( + FullMatrix &hessian) const + { + Assert(AD::ADNumberTraits::n_supported_derivative_levels >= 2, + ExcMessage( + "Cannot computed function Hessian: AD number type does" + "not support the calculation of second order derivatives.")); + + if ((ADNumberTraits::is_taped == true && + this->taped_driver.keep_independent_values() == false)) + { + Assert( + this->n_registered_independent_variables() == + this->n_independent_variables(), + ExcMessage( + "Not all values of sensitivities have been registered or subsequently set!")); + } + Assert(this->n_registered_dependent_variables() == + this->n_dependent_variables(), + ExcMessage("Not all dependent variables have been registered.")); + + Assert( + this->n_dependent_variables() == 1, + ExcMessage( + "The ADHelperScalarFunction class expects there to be only one dependent variable.")); + + // We can neglect correctly initializing the entries as + // we'll be overwriting them immediately in the succeeding call to + // Drivers::hessian(). + if (hessian.m() != this->n_independent_variables() || + hessian.n() != this->n_independent_variables()) + hessian.reinit({this->n_independent_variables(), + this->n_independent_variables()}, + true /*omit_default_initialization*/); + + if (ADNumberTraits::is_taped == true) + { + Assert(this->active_tape_index() != + Numbers::invalid_tape_index, + ExcMessage("Invalid tape index")); + Assert(this->is_recording() == false, + ExcMessage( + "Cannot compute Hessian while tape is being recorded.")); + Assert(this->independent_variable_values.size() == + this->n_independent_variables(), + ExcDimensionMismatch(this->independent_variable_values.size(), + this->n_independent_variables())); + + this->taped_driver.hessian(this->active_tape_index(), + this->independent_variable_values, + hessian); + } + else + { + Assert(ADNumberTraits::is_tapeless == true, + ExcInternalError()); + Assert(this->independent_variables.size() == + this->n_independent_variables(), + ExcDimensionMismatch(this->independent_variables.size(), + this->n_independent_variables())); + + this->tapeless_driver.hessian(this->independent_variables, + this->dependent_variables, + hessian); + } + + // Account for symmetries of tensor components + for (unsigned int i = 0; i < this->n_independent_variables(); i++) + for (unsigned int j = 0; j < i + 1; j++) + { + if (this->is_symmetric_independent_variable(i) == true && + this->is_symmetric_independent_variable(j) == true) + { + hessian[i][j] *= 0.25; + if (i != j) + hessian[j][i] *= 0.25; + } + else if ((this->is_symmetric_independent_variable(i) == true && + this->is_symmetric_independent_variable(j) == false) || + (this->is_symmetric_independent_variable(j) == true && + this->is_symmetric_independent_variable(i) == false)) + { + hessian[i][j] *= 0.5; + if (i != j) + hessian[j][i] *= 0.5; + } + } + } + + + + template + Tensor<0, + dim, + typename ADHelperScalarFunction:: + scalar_type> + ADHelperScalarFunction:: + extract_hessian_component( + const FullMatrix & hessian, + const FEValuesExtractors::Scalar &extractor_row, + const FEValuesExtractors::Scalar &extractor_col) const + { + // NOTE: It is necessary to make special provision for the case when the + // HessianType is scalar. Unfortunately Tensor<0,dim> does not provide + // the function unrolled_to_component_indices! + // NOTE: The order of components must be consistently defined throughout + // this class. + Tensor<0, dim, scalar_type> out; + + // Get indexsets for the subblocks from which we wish to extract the + // matrix values + const std::vector row_index_set( + internal::extract_field_component_indices(extractor_row)); + const std::vector col_index_set( + internal::extract_field_component_indices(extractor_col)); + Assert(row_index_set.size() == 1, ExcInternalError()); + Assert(col_index_set.size() == 1, ExcInternalError()); + + internal::set_tensor_entry(out, + 0, + hessian[row_index_set[0]][col_index_set[0]]); + + return out; + } + + + + template + SymmetricTensor<4, + dim, + typename ADHelperScalarFunction::scalar_type> + ADHelperScalarFunction:: + extract_hessian_component( + const FullMatrix & hessian, + const FEValuesExtractors::SymmetricTensor<2> &extractor_row, + const FEValuesExtractors::SymmetricTensor<2> &extractor_col) const + { + // NOTE: The order of components must be consistently defined throughout + // this class. NOTE: We require a specialisation for rank-4 symmetric + // tensors because they + // do not define their rank, and setting data using TableIndices is + // somewhat specialised as well. + SymmetricTensor<4, dim, scalar_type> out; + + // Get indexsets for the subblocks from which we wish to extract the + // matrix values + const std::vector row_index_set( + internal::extract_field_component_indices(extractor_row)); + const std::vector col_index_set( + internal::extract_field_component_indices(extractor_col)); + + for (unsigned int r = 0; r < row_index_set.size(); ++r) + for (unsigned int c = 0; c < col_index_set.size(); ++c) + { + internal::set_tensor_entry( + out, r, c, hessian[row_index_set[r]][col_index_set[c]]); + } + + return out; + } + + } // namespace AD } // namespace Differentiation diff --git a/source/differentiation/ad/ad_helpers.inst1.in b/source/differentiation/ad/ad_helpers.inst1.in index ef44c9398496..a5c9b87da3bf 100644 --- a/source/differentiation/ad/ad_helpers.inst1.in +++ b/source/differentiation/ad/ad_helpers.inst1.in @@ -117,6 +117,14 @@ for (deal_II_dimension : DIMENSIONS ; number : REAL_SCALARS) template class ADHelperPointLevelFunctionsBase; + // -------------------------- ADHelperScalarFunction ---------------------- + + template + class ADHelperScalarFunction; + + template + class ADHelperScalarFunction; + \} \} } @@ -137,6 +145,14 @@ for (deal_II_dimension : DIMENSIONS) template class ADHelperPointLevelFunctionsBase::ad_type>; + // -------------------------- ADHelperScalarFunction ---------------------- + + template + class ADHelperScalarFunction::ad_type>; + + template + class ADHelperScalarFunction::ad_type>; + \} \} } diff --git a/source/differentiation/ad/ad_helpers.inst2.in b/source/differentiation/ad/ad_helpers.inst2.in index 5fa4b2511e37..e886a8575ad0 100644 --- a/source/differentiation/ad/ad_helpers.inst2.in +++ b/source/differentiation/ad/ad_helpers.inst2.in @@ -172,6 +172,20 @@ for (deal_II_dimension : DIMENSIONS ; number : REAL_SCALARS) template class ADHelperPointLevelFunctionsBase; + // -------------------------- ADHelperScalarFunction ---------------------- + + template + class ADHelperScalarFunction; + + template + class ADHelperScalarFunction; + + template + class ADHelperScalarFunction; + + template + class ADHelperScalarFunction; + \} \} } @@ -198,6 +212,20 @@ for (deal_II_dimension : DIMENSIONS) template class ADHelperPointLevelFunctionsBase::ad_type>; + // -------------------------- ADHelperScalarFunction ---------------------- + + template + class ADHelperScalarFunction::ad_type>; + + template + class ADHelperScalarFunction::ad_type>; + + template + class ADHelperScalarFunction::ad_type>; + + template + class ADHelperScalarFunction::ad_type>; + \} \} } From 5efd5ed821dac8fdb5839ae0f5008b0e8f219de4 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Wed, 20 Feb 2019 12:22:22 +0100 Subject: [PATCH 172/507] Small grammatical fixes to documentation of ADHelpers. --- .../deal.II/differentiation/ad/ad_helpers.h | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index f884ee469481..bc00902024cc 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -115,8 +115,8 @@ namespace Differentiation * * // Indicate that we are about to start tracing the operations for * // function evaluation on the tape. If this tape has already been used - * // (i.e. the operations are already recorded) then we (optionally) load - * // the tape and reuse this data. + * // (i.e. the operations are already recorded) then we (optionally) + * // load the tape and reuse this data. * const bool is_recording * = ad_helper.start_recording_operations(tape_index); * if (is_recording == true) @@ -198,11 +198,11 @@ namespace Differentiation * that will be used in the definition of the functions that it is * desired to compute the sensitivities of. In the computation of * $\mathbf{f}(\mathbf{X})$, this will be the number of inputs - * $\mathbf{X}$, i.e. the dimension of the domain space. + * $\mathbf{X}$, i.e., the dimension of the domain space. * @param[in] n_dependent_variables The number of scalar functions to be * defined that will have a sensitivity to the given independent * variables. In the computation of $\mathbf{f}(\mathbf{X})$, this will - * be the number of outputs $\mathbf{f}$, i.e. the dimension of the + * be the number of outputs $\mathbf{f}$, i.e., the dimension of the * image space. */ ADHelperBase(const unsigned int n_independent_variables, @@ -324,11 +324,11 @@ namespace Differentiation * that will be used in the definition of the functions that it is * desired to compute the sensitivities of. In the computation of * $\mathbf{f}(\mathbf{X})$, this will be the number of inputs - * $\mathbf{X}$, i.e. the dimension of the domain space. + * $\mathbf{X}$, i.e., the dimension of the domain space. * @param[in] n_dependent_variables The number of scalar functions to be * defined that will have a sensitivity to the given independent * variables. In the computation of $\mathbf{f}(\mathbf{X})$, this will - * be the number of outputs $\mathbf{f}$, i.e. the dimension of the + * be the number of outputs $\mathbf{f}$, i.e., the dimension of the * image space. * @param[in] clear_registered_tapes A flag that indicates the that * list of @p registered_tapes must be cleared. @@ -867,11 +867,11 @@ namespace Differentiation * that will be used in the definition of the functions that it is * desired to compute the sensitivities of. In the computation of * $\mathbf{f}(\mathbf{X})$, this will be the number of inputs - * $\mathbf{X}$, i.e. the dimension of the domain space. + * $\mathbf{X}$, i.e., the dimension of the domain space. * @param[in] n_dependent_variables The number of scalar functions to be * defined that will have a sensitivity to the given independent * variables. In the computation of $\mathbf{f}(\mathbf{X})$, this will - * be the number of outputs $\mathbf{f}$, i.e. the dimension of the + * be the number of outputs $\mathbf{f}$, i.e., the dimension of the * image space. */ ADHelperCellLevelBase(const unsigned int n_independent_variables, @@ -964,7 +964,7 @@ namespace Differentiation //@{ /** - * Set the values for the independent variables $\mathbf{X}$, i.e. the + * Set the values for the independent variables $\mathbf{X}$, i.e., the * linearization point. * * @param[in] dof_values A vector field associated with local @@ -986,7 +986,7 @@ namespace Differentiation set_dof_values(const std::vector &dof_values); /** - * Set the values for the independent variables $\mathbf{X}$, i.e. the + * Set the values for the independent variables $\mathbf{X}$, i.e., the * linearization point. * * @param[in] values A vector field from which the values of all @@ -1252,7 +1252,7 @@ namespace Differentiation * that will be used in the definition of the functions that it is * desired to compute the sensitivities of. In the computation of * $\Psi(\mathbf{X})$, this will be the number of inputs - * $\mathbf{X}$, i.e. the dimension of the domain space. + * $\mathbf{X}$, i.e., the dimension of the domain space. * * @note There is only one dependent variable associated with the total * energy attributed to the local finite element. That is to say, this @@ -1568,11 +1568,11 @@ namespace Differentiation * that will be used in the definition of the functions that it is * desired to compute the sensitivities of. In the computation of * $\mathbf{r}(\mathbf{X})$, this will be the number of inputs - * $\mathbf{X}$, i.e. the dimension of the domain space. + * $\mathbf{X}$, i.e., the dimension of the domain space. * @param[in] n_dependent_variables The number of scalar functions to be * defined that will have a sensitivity to the given independent * variables. In the computation of $\mathbf{r}(\mathbf{X})$, this will - * be the number of outputs $\mathbf{r}$, i.e. the dimension of the + * be the number of outputs $\mathbf{r}$, i.e., the dimension of the * image space. */ ADHelperResidualLinearization(const unsigned int n_independent_variables, @@ -2682,11 +2682,11 @@ namespace Differentiation * that will be used in the definition of the functions that it is * desired to compute the sensitivities of. In the computation of * $\mathbf{f}(\mathbf{X})$, this will be the number of inputs - * $\mathbf{X}$, i.e. the dimension of the domain space. + * $\mathbf{X}$, i.e., the dimension of the domain space. * @param[in] n_dependent_variables The number of scalar functions to be * defined that will have a sensitivity to the given independent * variables. In the computation of $\mathbf{f}(\mathbf{X})$, this will - * be the number of outputs $\mathbf{f}$, i.e. the dimension of the + * be the number of outputs $\mathbf{f}$, i.e., the dimension of the * image space. */ ADHelperPointLevelFunctionsBase( @@ -2982,7 +2982,7 @@ namespace Differentiation * * // Indicate that we are about to start tracing the operations for * // function evaluation on the tape. If this tape has already been - * // used (i.e., the operations are already recorded) then we + * // used (i.e. the operations are already recorded) then we * // (optionally) load the tape and reuse this data. * const bool is_recording * = ad_helper.start_recording_operations(tape_index); @@ -3203,7 +3203,7 @@ namespace Differentiation * @f] * * @param[in] gradient The gradient of the scalar function with respect to - * all independent variables, i.e. that returned by compute_gradient(). + * all independent variables, i.e., that returned by compute_gradient(). * @param[in] extractor_row An extractor associated with the input field * variables. This effectively defines which components of the global set * of independent variables this field is associated with. @@ -3226,7 +3226,7 @@ namespace Differentiation * @f] * * @param[in] hessian The Hessian of the scalar function with respect to - * all independent variables, i.e. that returned by compute_hessian(). + * all independent variables, i.e., that returned by compute_hessian(). * @param[in] extractor_row An extractor associated with the input field * variables for which the first index of the Hessian is extracted. * @param[in] extractor_col An extractor associated with the input field From ca393d5ddd463c7d716176f5b7c44ca3d70abd2b Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 20 Feb 2019 18:20:23 +0100 Subject: [PATCH 173/507] Detect Tpetra support correctly if Trilinos is compiled with CUDA support --- cmake/configure/configure_2_trilinos.cmake | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmake/configure/configure_2_trilinos.cmake b/cmake/configure/configure_2_trilinos.cmake index 9b3c86139577..187fed907170 100644 --- a/cmake/configure/configure_2_trilinos.cmake +++ b/cmake/configure/configure_2_trilinos.cmake @@ -163,7 +163,15 @@ MACRO(FEATURE_TRILINOS_FIND_EXTERNAL var) # 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( " From b9c22bc392a715a64bed4b69e607e093b35aa87d Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Wed, 20 Feb 2019 23:03:16 +0100 Subject: [PATCH 174/507] add type traits to be used internally with FEEValuation --- include/deal.II/matrix_free/fe_evaluation.h | 29 +++++++++++++ .../matrix_free/fe_evaluation_type_traits.cc | 43 +++++++++++++++++++ ...tion_type_traits.with_trilinos=true.output | 5 +++ 3 files changed, 77 insertions(+) create mode 100644 tests/matrix_free/fe_evaluation_type_traits.cc create mode 100644 tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index e0143f51f754..8c3cc1d3bd76 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3409,6 +3409,35 @@ FEEvaluationBase::read_cell_data( namespace internal { + // a helper type-trait that leverage SFINAE to figure out if type T has + // ... T::local_element() const + template + struct has_local_element + { + private: + // this will work always. + // we let it be void as we know T::local_element() (if exists) should + // certainly return something + static void + detect(...); + + // this detecter will work only if we have "... T::local_element() const" + // and its return type will be the same as local_element(), + // that we expect to be T::value_type + template + static decltype(std::declval().local_element(0)) + detect(const U &); + + public: + // finally here we check if our detector has return type same as + // T::value_type. This will happen if compiler can use second detector, + // otherwise SFINAE let it work with the more general first one that is void + static constexpr bool value = + std::is_same()))>::value; + }; + + // access to generic vectors that have operator (). template inline typename VectorType::value_type & diff --git a/tests/matrix_free/fe_evaluation_type_traits.cc b/tests/matrix_free/fe_evaluation_type_traits.cc new file mode 100644 index 000000000000..68c837d5e168 --- /dev/null +++ b/tests/matrix_free/fe_evaluation_type_traits.cc @@ -0,0 +1,43 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2014 - 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. +// +// --------------------------------------------------------------------- + + + +// test internal typetraits used in FEEvaluation + +#include +#include + +#include + +#include "../tests.h" + + +int +main() +{ + initlog(); + + deallog << "has_local_element:" << std::endl + << "LinearAlgebra::distributed::Vector = " + << internal::has_local_element< + LinearAlgebra::distributed::Vector>::value + << std::endl + << "TrilinosWrappers::MPI::Vector = " + << internal::has_local_element::value + << std::endl; + + deallog << "OK" << std::endl; +} diff --git a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output new file mode 100644 index 000000000000..b62ca9b86d2d --- /dev/null +++ b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output @@ -0,0 +1,5 @@ + +DEAL::has_local_element: +DEAL::LinearAlgebra::distributed::Vector = 1 +DEAL::TrilinosWrappers::MPI::Vector = 0 +DEAL::OK From 0dafc63e077a52c40d65b8b52a99da3b307aedf8 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Thu, 21 Feb 2019 12:24:21 +0100 Subject: [PATCH 175/507] Fix face orientation in FEFaceEvaluation --- include/deal.II/matrix_free/fe_evaluation.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index e0143f51f754..ac0e9be18f9d 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -8562,10 +8562,10 @@ FEFaceEvaluation:: { if (integrate) for (unsigned int q = 0; q < n_q_points; ++q) - tmp_values[orientations[q]] = this->values_quad[c][q]; + tmp_values[q] = this->values_quad[c][orientations[q]]; else for (unsigned int q = 0; q < n_q_points; ++q) - tmp_values[q] = this->values_quad[c][orientations[q]]; + tmp_values[orientations[q]] = this->values_quad[c][q]; for (unsigned int q = 0; q < n_q_points; ++q) this->values_quad[c][q] = tmp_values[q]; } @@ -8574,10 +8574,10 @@ FEFaceEvaluation:: { if (integrate) for (unsigned int q = 0; q < n_q_points; ++q) - tmp_values[orientations[q]] = this->gradients_quad[c][d][q]; + tmp_values[q] = this->gradients_quad[c][d][orientations[q]]; else for (unsigned int q = 0; q < n_q_points; ++q) - tmp_values[q] = this->gradients_quad[c][d][orientations[q]]; + tmp_values[orientations[q]] = this->gradients_quad[c][d][q]; for (unsigned int q = 0; q < n_q_points; ++q) this->gradients_quad[c][d][q] = tmp_values[q]; } From a5fc6ff9cd04fd39c88217167322b46037cb9389 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Thu, 21 Feb 2019 12:26:56 +0100 Subject: [PATCH 176/507] Add test case for face orientation in FEFaceEvaluation --- tests/matrix_free/matrix_vector_faces_25.cc | 109 +++++++++++++++++ .../matrix_free/matrix_vector_faces_25.output | 113 ++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 tests/matrix_free/matrix_vector_faces_25.cc create mode 100644 tests/matrix_free/matrix_vector_faces_25.output diff --git a/tests/matrix_free/matrix_vector_faces_25.cc b/tests/matrix_free/matrix_vector_faces_25.cc new file mode 100644 index 000000000000..ef0f427ded98 --- /dev/null +++ b/tests/matrix_free/matrix_vector_faces_25.cc @@ -0,0 +1,109 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + + +// tests matrix-free face evaluation, matrix-vector products as compared to +// the same implementation with MeshWorker. Similar to matrix_vector_faces_04 +// but using a mesh with all sorts of different orientations, using a mesh +// somewhat related to the one in tests/grid/grid_tools_06.cc but with the +// cubes patched together appropriately + +#include + +#include + +#include "../tests.h" + +std::ofstream logfile("output"); + +#include "matrix_vector_faces_common.h" + + + +void generate_grid(Triangulation<3> &triangulation, int orientation) +{ + Point<3> vertices_1[] = {Point<3>(-1., -1., -3.), + Point<3>(+1., -1., -3.), + Point<3>(-1., +1., -3.), + Point<3>(+1., +1., -3.), + Point<3>(-1., -1., -1.), + Point<3>(+1., -1., -1.), + Point<3>(-1., +1., -1.), + Point<3>(+1., +1., -1.), + Point<3>(-1., -1., +1.), + Point<3>(+1., -1., +1.), + Point<3>(-1., +1., +1.), + Point<3>(+1., +1., +1.)}; + std::vector> vertices(&vertices_1[0], &vertices_1[12]); + + std::vector> cells(2, CellData<3>()); + + /* cell 0 */ + int cell_vertices_0[GeometryInfo<3>::vertices_per_cell] = { + 0, 1, 2, 3, 4, 5, 6, 7}; + + /* cell 1 */ + int cell_vertices_1[8][GeometryInfo<3>::vertices_per_cell] = { + {4, 5, 6, 7, 8, 9, 10, 11}, + {5, 7, 4, 6, 9, 11, 8, 10}, + {7, 6, 5, 4, 11, 10, 9, 8}, + {6, 4, 7, 5, 10, 8, 11, 9}, + {9, 8, 11, 10, 5, 4, 7, 6}, + {8, 10, 9, 11, 4, 6, 5, 7}, + {10, 11, 8, 9, 6, 7, 4, 5}, + {11, 9, 10, 8, 7, 5, 6, 4}}; + + for (unsigned int j = 0; j < GeometryInfo<3>::vertices_per_cell; ++j) + { + cells[0].vertices[j] = cell_vertices_0[j]; + cells[1].vertices[j] = cell_vertices_1[orientation][j]; + } + cells[0].material_id = 0; + cells[1].material_id = 0; + + + triangulation.create_triangulation(vertices, cells, SubCellData()); +} + + + +template +void +test() +{ + if (dim == 2) + return; + + Triangulation<3> tria; + for (unsigned int orientation = 0; orientation < 8; ++orientation) + { + deallog << "Testing orientation case " << orientation << std::endl; + tria.clear(); + generate_grid(tria, orientation); + + FE_DGQ<3> fe(fe_degree); + DoFHandler<3> dof(tria); + dof.distribute_dofs(fe); + AffineConstraints constraints; + constraints.close(); + + do_test<3, fe_degree, fe_degree + 1, double>(dof, constraints, false); + + tria.refine_global(1); + dof.distribute_dofs(fe); + do_test<3, fe_degree, fe_degree + 1, double>(dof, constraints, false); + } +} diff --git a/tests/matrix_free/matrix_vector_faces_25.output b/tests/matrix_free/matrix_vector_faces_25.output new file mode 100644 index 000000000000..c44d20e8fb3b --- /dev/null +++ b/tests/matrix_free/matrix_vector_faces_25.output @@ -0,0 +1,113 @@ + +DEAL:3d::Testing orientation case 0 +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 4.93e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 8.94e-16 +DEAL:3d:: +DEAL:3d::Testing orientation case 1 +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 4.85e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 8.94e-16 +DEAL:3d:: +DEAL:3d::Testing orientation case 2 +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 3.24e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 8.94e-16 +DEAL:3d:: +DEAL:3d::Testing orientation case 3 +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 3.26e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 8.94e-16 +DEAL:3d:: +DEAL:3d::Testing orientation case 4 +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 2.45e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 8.55e-16 +DEAL:3d:: +DEAL:3d::Testing orientation case 5 +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 6.52e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 8.55e-16 +DEAL:3d:: +DEAL:3d::Testing orientation case 6 +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 4.86e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 8.55e-16 +DEAL:3d:: +DEAL:3d::Testing orientation case 7 +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 4.84e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(1) +DEAL:3d::Norm of difference: 8.55e-16 +DEAL:3d:: +DEAL:3d::Testing orientation case 0 +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 6.75e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 4.04e-15 +DEAL:3d:: +DEAL:3d::Testing orientation case 1 +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 6.75e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 3.97e-15 +DEAL:3d:: +DEAL:3d::Testing orientation case 2 +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 5.40e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 3.98e-15 +DEAL:3d:: +DEAL:3d::Testing orientation case 3 +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 6.08e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 3.95e-15 +DEAL:3d:: +DEAL:3d::Testing orientation case 4 +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 4.99e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 3.68e-15 +DEAL:3d:: +DEAL:3d::Testing orientation case 5 +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 5.32e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 3.68e-15 +DEAL:3d:: +DEAL:3d::Testing orientation case 6 +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 5.32e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 3.68e-15 +DEAL:3d:: +DEAL:3d::Testing orientation case 7 +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 5.32e-16 +DEAL:3d:: +DEAL:3d::Testing FE_DGQ<3>(2) +DEAL:3d::Norm of difference: 3.68e-15 +DEAL:3d:: From b2979f78e051bff2c6e1f0e766701551a847c126 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Thu, 21 Feb 2019 12:27:09 +0100 Subject: [PATCH 177/507] Add changelog entry --- doc/news/changes/minor/20190221MartinKronbichler | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/news/changes/minor/20190221MartinKronbichler 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) From bf6a24cc20ed8f3cdcf276abfc7b8a6d08b68417 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Thu, 21 Feb 2019 19:09:04 +0100 Subject: [PATCH 178/507] FEEvaluation: switch between internal::vector_access() via SFINAE --- include/deal.II/matrix_free/fe_evaluation.h | 24 ++++-- .../matrix_free/fe_evaluation_type_traits.cc | 79 +++++++++++++++++++ ...tion_type_traits.with_trilinos=true.output | 5 ++ 3 files changed, 100 insertions(+), 8 deletions(-) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index 8c3cc1d3bd76..dc97327d0797 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3439,7 +3439,10 @@ namespace internal // access to generic vectors that have operator (). - template + // FIXME: this is wrong for Trilinos/Petsc MPI vectors + template ::value, + VectorType>::type * = nullptr> inline typename VectorType::value_type & vector_access(VectorType &vec, const unsigned int entry) { @@ -3451,19 +3454,20 @@ namespace internal // access to distributed MPI vectors that have a local_element(uint) // method to access data in local index space, which is what we use in // DoFInfo and hence in read_dof_values etc. - template - inline Number & - vector_access(LinearAlgebra::distributed::Vector &vec, - const unsigned int entry) + template ::value, + VectorType>::type * = nullptr> + inline typename VectorType::value_type & + vector_access(VectorType &vec, const unsigned int entry) { return vec.local_element(entry); } - // this is to make sure that the parallel partitioning in the - // LinearAlgebra::distributed::Vector is really the same as stored in - // MatrixFree + // this is to make sure that the parallel partitioning in VectorType + // is really the same as stored in MatrixFree + // FIXME: this is incorrect for PETSc/Trilinos MPI vectors template inline void check_vector_compatibility( @@ -3476,6 +3480,10 @@ namespace internal AssertDimension(vec.size(), dof_info.vector_partitioner->size()); } + + // this is to make sure that the parallel partitioning in the + // LinearAlgebra::distributed::Vector is really the same as stored in + // MatrixFree template inline void check_vector_compatibility( diff --git a/tests/matrix_free/fe_evaluation_type_traits.cc b/tests/matrix_free/fe_evaluation_type_traits.cc index 68c837d5e168..458a625e8ada 100644 --- a/tests/matrix_free/fe_evaluation_type_traits.cc +++ b/tests/matrix_free/fe_evaluation_type_traits.cc @@ -24,12 +24,80 @@ #include "../tests.h" +// dummy class we use to check typetraits and internal function. +// this one mimics LA::d::Vec +template +class Dummy +{ +public: + using value_type = Number; + + Number + local_element(const unsigned int) const + { + deallog << "Dummy::local_element() const" << std::endl; + return Number(); + } + + Number & + local_element(const unsigned int) + { + deallog << "Dummy::local_element()" << std::endl; + return dummy; + } + + Number + operator()(const unsigned int) const + { + deallog << "Dummy::operator() const" << std::endl; + return Number(); + } + + Number & + operator()(const unsigned int) + { + deallog << "Dummy::operator()" << std::endl; + return dummy; + } + +private: + Number dummy; +}; + + +template +class Dummy2 +{ +public: + using value_type = Number; + + Number + operator()(const unsigned int) const + { + deallog << "Dummy2::operator() const" << std::endl; + return Number(); + } + + Number & + operator()(const unsigned int) + { + deallog << "Dummy2::operator()" << std::endl; + return dummy; + } + +private: + Number dummy; +}; + int main() { initlog(); + Dummy dummy; + Dummy2 dummy2; + deallog << "has_local_element:" << std::endl << "LinearAlgebra::distributed::Vector = " << internal::has_local_element< @@ -37,7 +105,18 @@ main() << std::endl << "TrilinosWrappers::MPI::Vector = " << internal::has_local_element::value + << std::endl + << "Dummy = " << internal::has_local_element>::value + << std::endl + << "Dummy2 = " << internal::has_local_element>::value << std::endl; + // now check internal::vector_access wrapper + // we expect local_element() to be called + deallog << "internal::vector_access:" << std::endl; + internal::vector_access(dummy, 0); + internal::vector_access(dummy2, 0); + + deallog << "OK" << std::endl; } diff --git a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output index b62ca9b86d2d..78f076543419 100644 --- a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output +++ b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output @@ -2,4 +2,9 @@ DEAL::has_local_element: DEAL::LinearAlgebra::distributed::Vector = 1 DEAL::TrilinosWrappers::MPI::Vector = 0 +DEAL::Dummy = 1 +DEAL::Dummy2 = 0 +DEAL::internal::vector_access: +DEAL::Dummy::local_element() +DEAL::Dummy2::operator() DEAL::OK From 071f982eddcacb5d3efcb8fa7d0b1491273e7625 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Thu, 21 Feb 2019 23:20:50 +0100 Subject: [PATCH 179/507] add internal::has_partitioners_are_compatible<> --- include/deal.II/matrix_free/fe_evaluation.h | 21 +++++++++++++++++++ .../matrix_free/fe_evaluation_type_traits.cc | 11 ++++++++++ ...tion_type_traits.with_trilinos=true.output | 3 +++ 3 files changed, 35 insertions(+) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index dc97327d0797..c7c2d8b8903c 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3438,6 +3438,27 @@ namespace internal }; + // same as above to check + // bool T::partitioners_are_compatible(const Utilities::MPI::Partitioner &) + // const + template + struct has_partitioners_are_compatible + { + private: + static void + detect(...); + + template + static decltype(std::declval().partitioners_are_compatible( + std::declval())) + detect(const U &); + + public: + static constexpr bool value = + std::is_same()))>::value; + }; + + // access to generic vectors that have operator (). // FIXME: this is wrong for Trilinos/Petsc MPI vectors template Date: Thu, 21 Feb 2019 23:32:31 +0100 Subject: [PATCH 180/507] use has_partitioners_are_compatible in internal::check_vector_compatibility --- include/deal.II/matrix_free/fe_evaluation.h | 30 +++++++++------------ 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index c7c2d8b8903c..8da043d70bee 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -40,15 +40,6 @@ DEAL_II_NAMESPACE_OPEN -// forward declarations -namespace LinearAlgebra -{ - namespace distributed - { - template - class Vector; - } -} // namespace LinearAlgebra namespace internal { DeclException0(ExcAccessToUninitializedField); @@ -3487,9 +3478,13 @@ namespace internal // this is to make sure that the parallel partitioning in VectorType - // is really the same as stored in MatrixFree + // is really the same as stored in MatrixFree. + // version below is when has_partitioners_are_compatible == false // FIXME: this is incorrect for PETSc/Trilinos MPI vectors - template + template < + typename VectorType, + typename std::enable_if::value, + VectorType>::type * = nullptr> inline void check_vector_compatibility( const VectorType & vec, @@ -3502,14 +3497,15 @@ namespace internal } - // this is to make sure that the parallel partitioning in the - // LinearAlgebra::distributed::Vector is really the same as stored in - // MatrixFree - template + // same as above for has_partitioners_are_compatible == true + template < + typename VectorType, + typename std::enable_if::value, + VectorType>::type * = nullptr> inline void check_vector_compatibility( - const LinearAlgebra::distributed::Vector &vec, - const internal::MatrixFreeFunctions::DoFInfo & dof_info) + const VectorType & vec, + const internal::MatrixFreeFunctions::DoFInfo &dof_info) { (void)vec; (void)dof_info; From 891c6d8115aeb0c577661f88c1336a8c73a8cf8b Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 22 Feb 2019 14:40:23 +0100 Subject: [PATCH 181/507] Remove redundant output files --- ...> sparse_matrix_vector_14.with_trilinos_with_tpetra=on.output} | 0 ...> sparse_matrix_vector_15.with_trilinos_with_tpetra=on.output} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/trilinos/{sparse_matrix_vector_14.output => sparse_matrix_vector_14.with_trilinos_with_tpetra=on.output} (100%) rename tests/trilinos/{sparse_matrix_vector_15.output => sparse_matrix_vector_15.with_trilinos_with_tpetra=on.output} (100%) diff --git a/tests/trilinos/sparse_matrix_vector_14.output b/tests/trilinos/sparse_matrix_vector_14.with_trilinos_with_tpetra=on.output similarity index 100% rename from tests/trilinos/sparse_matrix_vector_14.output rename to tests/trilinos/sparse_matrix_vector_14.with_trilinos_with_tpetra=on.output diff --git a/tests/trilinos/sparse_matrix_vector_15.output b/tests/trilinos/sparse_matrix_vector_15.with_trilinos_with_tpetra=on.output similarity index 100% rename from tests/trilinos/sparse_matrix_vector_15.output rename to tests/trilinos/sparse_matrix_vector_15.with_trilinos_with_tpetra=on.output From 40a874a6b150c863b5be5577b19da5d06af66e4c Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 22 Feb 2019 15:04:18 +0100 Subject: [PATCH 182/507] Move implementation to templates file --- .../lac/trilinos_tpetra_vector.templates.h | 681 ++++++++++++++++++ source/lac/trilinos_tpetra_vector.cc | 646 +---------------- 2 files changed, 682 insertions(+), 645 deletions(-) create mode 100644 include/deal.II/lac/trilinos_tpetra_vector.templates.h diff --git a/include/deal.II/lac/trilinos_tpetra_vector.templates.h b/include/deal.II/lac/trilinos_tpetra_vector.templates.h new file mode 100644 index 000000000000..b102775201e3 --- /dev/null +++ b/include/deal.II/lac/trilinos_tpetra_vector.templates.h @@ -0,0 +1,681 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii__trilinos_tpetra_vector_templates_h +#define dealii__trilinos_tpetra_vector_templates_h + +#include + +#include + +#ifdef DEAL_II_TRILINOS_WITH_TPETRA + +# ifdef DEAL_II_WITH_MPI + +# include + +# include + +# include + +# include +# include +# include + +# include + + +DEAL_II_NAMESPACE_OPEN + +namespace LinearAlgebra +{ + namespace TpetraWrappers + { + template + Vector::Vector() + : Subscriptor() + , vector(new Tpetra::Vector( + Teuchos::RCP>( + new Tpetra::Map( + 0, + 0, + Utilities::Trilinos::tpetra_comm_self())))) + {} + + + + template + Vector::Vector(const Vector &V) + : Subscriptor() + , vector(new Tpetra::Vector( + V.trilinos_vector(), + Teuchos::Copy)) + {} + + + + template + Vector::Vector(const IndexSet ¶llel_partitioner, + const MPI_Comm &communicator) + : Subscriptor() + , vector(new Tpetra::Vector( + Teuchos::rcp(new Tpetra::Map( + parallel_partitioner.make_tpetra_map(communicator, false))))) + {} + + + + template + void + Vector::reinit(const IndexSet ¶llel_partitioner, + const MPI_Comm &communicator, + const bool omit_zeroing_entries) + { + Tpetra::Map input_map = + parallel_partitioner.make_tpetra_map(communicator, false); + if (vector->getMap()->isSameAs(input_map) == false) + vector = std_cxx14::make_unique< + Tpetra::Vector>(Teuchos::rcp( + new Tpetra::Map(input_map))); + else if (omit_zeroing_entries == false) + { + vector->putScalar(0.); + } + } + + + + template + void + Vector::reinit(const VectorSpaceVector &V, + const bool omit_zeroing_entries) + { + // Check that casting will work. + Assert(dynamic_cast *>(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast &>(V); + + reinit(down_V.locally_owned_elements(), + down_V.get_mpi_communicator(), + omit_zeroing_entries); + } + + + + template + Vector & + Vector::operator=(const Vector &V) + { + // Distinguish three cases: + // - First case: both vectors have the same layout. + // - Second case: both vectors have the same size but different layout. + // - Third case: the vectors have different size. + if (vector->getMap()->isSameAs(*(V.trilinos_vector().getMap()))) + *vector = V.trilinos_vector(); + else + { + if (size() == V.size()) + { + Tpetra::Import data_exchange( + vector->getMap(), V.trilinos_vector().getMap()); + + vector->doImport(V.trilinos_vector(), + data_exchange, + Tpetra::REPLACE); + } + else + vector = std_cxx14::make_unique< + Tpetra::Vector>( + V.trilinos_vector()); + } + + return *this; + } + + + + template + Vector & + Vector::operator=(const Number s) + { + Assert(s == Number(0.), + ExcMessage("Only 0 can be assigned to a vector.")); + + vector->putScalar(s); + + return *this; + } + + + + template + void + Vector::import( + const ReadWriteVector & V, + VectorOperation::values operation, + std::shared_ptr communication_pattern) + { + // If no communication pattern is given, create one. Otherwsie, use the + // one given. + if (communication_pattern == nullptr) + { + // The first time import is called, a communication pattern is + // created. Check if the communication pattern already exists and if + // it can be reused. + if ((source_stored_elements.size() != + V.get_stored_elements().size()) || + (source_stored_elements != V.get_stored_elements())) + { + const Teuchos::MpiComm *mpi_comm = + dynamic_cast *>( + vector->getMap()->getComm().get()); + Assert(mpi_comm != nullptr, ExcInternalError()); + create_tpetra_comm_pattern(V.get_stored_elements(), + *(mpi_comm->getRawMpiComm())()); + } + } + else + { + tpetra_comm_pattern = std::dynamic_pointer_cast< + const TpetraWrappers::CommunicationPattern>(communication_pattern); + AssertThrow( + tpetra_comm_pattern != nullptr, + ExcMessage( + std::string("The communication pattern is not of type ") + + "LinearAlgebra::TpetraWrappers::CommunicationPattern.")); + } + + Tpetra::Export tpetra_export( + tpetra_comm_pattern->get_tpetra_export()); + Tpetra::Vector source_vector( + tpetra_export.getSourceMap()); + + source_vector.template sync(); + auto x_2d = source_vector.template getLocalView(); + auto x_1d = Kokkos::subview(x_2d, Kokkos::ALL(), 0); + source_vector.template modify(); + const size_t localLength = source_vector.getLocalLength(); + auto values_it = V.begin(); + for (size_t k = 0; k < localLength; ++k) + x_1d(k) = *values_it++; + source_vector.template sync< + typename Tpetra::Vector:: + device_type::memory_space>(); + if (operation == VectorOperation::insert) + vector->doExport(source_vector, tpetra_export, Tpetra::REPLACE); + else if (operation == VectorOperation::add) + vector->doExport(source_vector, tpetra_export, Tpetra::ADD); + else + AssertThrow(false, ExcNotImplemented()); + } + + + + template + Vector & + Vector::operator*=(const Number factor) + { + AssertIsFinite(factor); + vector->scale(factor); + + return *this; + } + + + + template + Vector & + Vector::operator/=(const Number factor) + { + AssertIsFinite(factor); + Assert(factor != Number(0.), ExcZero()); + *this *= Number(1.) / factor; + + return *this; + } + + + + template + Vector & + Vector::operator+=(const VectorSpaceVector &V) + { + // Check that casting will work. + Assert(dynamic_cast *>(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast &>(V); + // If the maps are the same we can update right away. + if (vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap()))) + { + vector->update(1., down_V.trilinos_vector(), 1.); + } + else + { + Assert(this->size() == down_V.size(), + ExcDimensionMismatch(this->size(), down_V.size())); + + // TODO: Tpetra doesn't have a combine mode that also updates local + // elements, maybe there is a better workaround. + Tpetra::Vector dummy( + vector->getMap(), false); + Tpetra::Import data_exchange( + down_V.trilinos_vector().getMap(), dummy.getMap()); + + dummy.doImport(down_V.trilinos_vector(), + data_exchange, + Tpetra::INSERT); + + vector->update(1.0, dummy, 1.0); + } + + return *this; + } + + + + template + Vector & + Vector::operator-=(const VectorSpaceVector &V) + { + this->add(-1., V); + + return *this; + } + + + + template + Number Vector::operator*(const VectorSpaceVector &V) const + { + // Check that casting will work. + Assert(dynamic_cast *>(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast &>(V); + Assert(this->size() == down_V.size(), + ExcDimensionMismatch(this->size(), down_V.size())); + Assert(vector->getMap()->isSameAs(*down_V.trilinos_vector().getMap()), + ExcDifferentParallelPartitioning()); + + return vector->dot(down_V.trilinos_vector()); + } + + + + template + void + Vector::add(const Number a) + { + AssertIsFinite(a); + + vector->template sync(); + auto vector_2d = vector->template getLocalView(); + auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); + vector->template modify(); + const size_t localLength = vector->getLocalLength(); + for (size_t k = 0; k < localLength; ++k) + { + vector_1d(k) += a; + } + vector->template sync< + typename Tpetra::Vector:: + device_type::memory_space>(); + } + + + + template + void + Vector::add(const Number a, const VectorSpaceVector &V) + { + // Check that casting will work. + Assert(dynamic_cast *>(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast &>(V); + AssertIsFinite(a); + Assert(vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap())), + ExcDifferentParallelPartitioning()); + + vector->update(a, down_V.trilinos_vector(), 1.); + } + + + + template + void + Vector::add(const Number a, + const VectorSpaceVector &V, + const Number b, + const VectorSpaceVector &W) + { + // Check that casting will work. + Assert(dynamic_cast *>(&V) != nullptr, + ExcVectorTypeNotCompatible()); + // Check that casting will work. + Assert(dynamic_cast *>(&W) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast &>(V); + // Downcast W. If fails, throws an exception. + const Vector &down_W = dynamic_cast &>(W); + Assert(vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap())), + ExcDifferentParallelPartitioning()); + Assert(vector->getMap()->isSameAs(*(down_W.trilinos_vector().getMap())), + ExcDifferentParallelPartitioning()); + AssertIsFinite(a); + AssertIsFinite(b); + + vector->update( + a, down_V.trilinos_vector(), b, down_W.trilinos_vector(), 1.); + } + + + + template + void + Vector::sadd(const Number s, + const Number a, + const VectorSpaceVector &V) + { + // Check that casting will work. + Assert(dynamic_cast *>(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + *this *= s; + // Downcast V. It fails, throws an exception. + const Vector &down_V = dynamic_cast &>(V); + Vector tmp(down_V); + tmp *= a; + *this += tmp; + } + + + + template + void + Vector::scale(const VectorSpaceVector &scaling_factors) + { + // Check that casting will work. + Assert(dynamic_cast *>(&scaling_factors) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast scaling_factors. If fails, throws an exception. + const Vector &down_scaling_factors = + dynamic_cast &>(scaling_factors); + Assert(vector->getMap()->isSameAs( + *(down_scaling_factors.trilinos_vector().getMap())), + ExcDifferentParallelPartitioning()); + + vector->elementWiseMultiply(1., + *down_scaling_factors.vector, + *vector, + 0.); + } + + + + template + void + Vector::equ(const Number a, const VectorSpaceVector &V) + { + // Check that casting will work. + Assert(dynamic_cast *>(&V) != nullptr, + ExcVectorTypeNotCompatible()); + + // Downcast V. If fails, throws an exception. + const Vector &down_V = dynamic_cast &>(V); + // If we don't have the same map, copy. + if (vector->getMap()->isSameAs(*down_V.trilinos_vector().getMap()) == + false) + this->sadd(0., a, V); + else + { + // Otherwise, just update + vector->update(a, down_V.trilinos_vector(), 0.); + } + } + + + + template + bool + Vector::all_zero() const + { + // get a representation of the vector and + // loop over all the elements + Number * start_ptr = vector->getDataNonConst().get(); + const Number *ptr = start_ptr, + *eptr = start_ptr + vector->getLocalLength(); + unsigned int flag = 0; + while (ptr != eptr) + { + if (*ptr != Number(0)) + { + flag = 1; + break; + } + ++ptr; + } + + // Check that the vector is zero on _all_ processors. + const Teuchos::MpiComm *mpi_comm = + dynamic_cast *>( + vector->getMap()->getComm().get()); + Assert(mpi_comm != nullptr, ExcInternalError()); + unsigned int num_nonzero = + Utilities::MPI::sum(flag, *(mpi_comm->getRawMpiComm())()); + + return num_nonzero == 0; + } + + + + template + Number + Vector::mean_value() const + { + return vector->meanValue(); + } + + + + template + typename LinearAlgebra::VectorSpaceVector::real_type + Vector::l1_norm() const + { + return vector->norm1(); + } + + + + template + typename LinearAlgebra::VectorSpaceVector::real_type + Vector::l2_norm() const + { + return vector->norm2(); + } + + + + template + typename LinearAlgebra::VectorSpaceVector::real_type + Vector::linfty_norm() const + { + return vector->normInf(); + } + + + + template + Number + Vector::add_and_dot(const Number a, + const VectorSpaceVector &V, + const VectorSpaceVector &W) + { + this->add(a, V); + + return *this * W; + } + + + + template + typename Vector::size_type + Vector::size() const + { + return vector->getGlobalLength(); + } + + + + template + MPI_Comm + Vector::get_mpi_communicator() const + { + const auto tpetra_comm = dynamic_cast *>( + vector->getMap()->getComm().get()); + Assert(tpetra_comm != nullptr, ExcInternalError()); + return *(tpetra_comm->getRawMpiComm())(); + } + + + + template + ::dealii::IndexSet + Vector::locally_owned_elements() const + { + IndexSet is(size()); + + // easy case: local range is contiguous + if (vector->getMap()->isContiguous()) + { + is.add_range(vector->getMap()->getMinGlobalIndex(), + vector->getMap()->getMaxGlobalIndex() + 1); + } + else if (vector->getLocalLength() > 0) + { + const size_type n_indices = vector->getLocalLength(); + std::vector vector_indices; + vector_indices.reserve(n_indices); + for (unsigned int i = 0; i < n_indices; ++i) + vector_indices.push_back(vector->getMap()->getGlobalElement(i)); + + is.add_indices(vector_indices.data(), + vector_indices.data() + n_indices); + } + is.compress(); + + return is; + } + + + + template + const Tpetra::Vector & + Vector::trilinos_vector() const + { + return *vector; + } + + + + template + Tpetra::Vector & + Vector::trilinos_vector() + { + return *vector; + } + + + + template + void + Vector::print(std::ostream & out, + const unsigned int precision, + const bool scientific, + const bool across) const + { + AssertThrow(out, ExcIO()); + boost::io::ios_flags_saver restore_flags(out); + + // Get a representation of the vector and loop over all + // the elements + const auto val = vector->get1dView(); + + out.precision(precision); + if (scientific) + out.setf(std::ios::scientific, std::ios::floatfield); + else + out.setf(std::ios::fixed, std::ios::floatfield); + + vector->template sync(); + auto vector_2d = vector->template getLocalView(); + auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); + const size_t local_length = vector->getLocalLength(); + + if (across) + for (unsigned int i = 0; i < local_length; ++i) + out << vector_1d(i) << ' '; + else + for (unsigned int i = 0; i < local_length; ++i) + out << vector_1d(i) << std::endl; + out << std::endl; + + // restore the representation + // of the vector + AssertThrow(out, ExcIO()); + } + + + + template + std::size_t + Vector::memory_consumption() const + { + return sizeof(*this) + + vector->getLocalLength() * + (sizeof(Number) + sizeof(TrilinosWrappers::types::int_type)); + } + + + + template + void + Vector::create_tpetra_comm_pattern(const IndexSet &source_index_set, + const MPI_Comm &mpi_comm) + { + source_stored_elements = source_index_set; + tpetra_comm_pattern = + std::make_shared( + locally_owned_elements(), source_index_set, mpi_comm); + } + } // namespace TpetraWrappers +} // namespace LinearAlgebra + +DEAL_II_NAMESPACE_CLOSE + +# endif + +#endif + +#endif diff --git a/source/lac/trilinos_tpetra_vector.cc b/source/lac/trilinos_tpetra_vector.cc index ea218f8309f8..b269bdabcf88 100644 --- a/source/lac/trilinos_tpetra_vector.cc +++ b/source/lac/trilinos_tpetra_vector.cc @@ -13,660 +13,17 @@ // // --------------------------------------------------------------------- -#include - -#include +#include #ifdef DEAL_II_TRILINOS_WITH_TPETRA - # ifdef DEAL_II_WITH_MPI -# include - -# include - -# include - -# include -# include -# include - -# include - - DEAL_II_NAMESPACE_OPEN namespace LinearAlgebra { namespace TpetraWrappers { - template - Vector::Vector() - : Subscriptor() - , vector(new Tpetra::Vector( - Teuchos::RCP>( - new Tpetra::Map( - 0, - 0, - Utilities::Trilinos::tpetra_comm_self())))) - {} - - - - template - Vector::Vector(const Vector &V) - : Subscriptor() - , vector(new Tpetra::Vector( - V.trilinos_vector(), - Teuchos::Copy)) - {} - - - - template - Vector::Vector(const IndexSet ¶llel_partitioner, - const MPI_Comm &communicator) - : Subscriptor() - , vector(new Tpetra::Vector( - Teuchos::rcp(new Tpetra::Map( - parallel_partitioner.make_tpetra_map(communicator, false))))) - {} - - - - template - void - Vector::reinit(const IndexSet ¶llel_partitioner, - const MPI_Comm &communicator, - const bool omit_zeroing_entries) - { - Tpetra::Map input_map = - parallel_partitioner.make_tpetra_map(communicator, false); - if (vector->getMap()->isSameAs(input_map) == false) - vector = std_cxx14::make_unique< - Tpetra::Vector>(Teuchos::rcp( - new Tpetra::Map(input_map))); - else if (omit_zeroing_entries == false) - { - vector->putScalar(0.); - } - } - - - - template - void - Vector::reinit(const VectorSpaceVector &V, - const bool omit_zeroing_entries) - { - // Check that casting will work. - Assert(dynamic_cast *>(&V) != nullptr, - ExcVectorTypeNotCompatible()); - - // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast &>(V); - - reinit(down_V.locally_owned_elements(), - down_V.get_mpi_communicator(), - omit_zeroing_entries); - } - - - - template - Vector & - Vector::operator=(const Vector &V) - { - // Distinguish three cases: - // - First case: both vectors have the same layout. - // - Second case: both vectors have the same size but different layout. - // - Third case: the vectors have different size. - if (vector->getMap()->isSameAs(*(V.trilinos_vector().getMap()))) - *vector = V.trilinos_vector(); - else - { - if (size() == V.size()) - { - Tpetra::Import data_exchange( - vector->getMap(), V.trilinos_vector().getMap()); - - vector->doImport(V.trilinos_vector(), - data_exchange, - Tpetra::REPLACE); - } - else - vector = std_cxx14::make_unique< - Tpetra::Vector>( - V.trilinos_vector()); - } - - return *this; - } - - - - template - Vector & - Vector::operator=(const Number s) - { - Assert(s == Number(0.), - ExcMessage("Only 0 can be assigned to a vector.")); - - vector->putScalar(s); - - return *this; - } - - - - template - void - Vector::import( - const ReadWriteVector & V, - VectorOperation::values operation, - std::shared_ptr communication_pattern) - { - // If no communication pattern is given, create one. Otherwsie, use the - // one given. - if (communication_pattern == nullptr) - { - // The first time import is called, a communication pattern is - // created. Check if the communication pattern already exists and if - // it can be reused. - if ((source_stored_elements.size() != - V.get_stored_elements().size()) || - (source_stored_elements != V.get_stored_elements())) - { - const Teuchos::MpiComm *mpi_comm = - dynamic_cast *>( - vector->getMap()->getComm().get()); - Assert(mpi_comm != nullptr, ExcInternalError()); - create_tpetra_comm_pattern(V.get_stored_elements(), - *(mpi_comm->getRawMpiComm())()); - } - } - else - { - tpetra_comm_pattern = std::dynamic_pointer_cast< - const TpetraWrappers::CommunicationPattern>(communication_pattern); - AssertThrow( - tpetra_comm_pattern != nullptr, - ExcMessage( - std::string("The communication pattern is not of type ") + - "LinearAlgebra::TpetraWrappers::CommunicationPattern.")); - } - - Tpetra::Export tpetra_export( - tpetra_comm_pattern->get_tpetra_export()); - Tpetra::Vector source_vector( - tpetra_export.getSourceMap()); - - source_vector.template sync(); - auto x_2d = source_vector.template getLocalView(); - auto x_1d = Kokkos::subview(x_2d, Kokkos::ALL(), 0); - source_vector.template modify(); - const size_t localLength = source_vector.getLocalLength(); - auto values_it = V.begin(); - for (size_t k = 0; k < localLength; ++k) - x_1d(k) = *values_it++; - source_vector.template sync< - typename Tpetra::Vector:: - device_type::memory_space>(); - if (operation == VectorOperation::insert) - vector->doExport(source_vector, tpetra_export, Tpetra::REPLACE); - else if (operation == VectorOperation::add) - vector->doExport(source_vector, tpetra_export, Tpetra::ADD); - else - AssertThrow(false, ExcNotImplemented()); - } - - - - template - Vector & - Vector::operator*=(const Number factor) - { - AssertIsFinite(factor); - vector->scale(factor); - - return *this; - } - - - - template - Vector & - Vector::operator/=(const Number factor) - { - AssertIsFinite(factor); - Assert(factor != Number(0.), ExcZero()); - *this *= Number(1.) / factor; - - return *this; - } - - - - template - Vector & - Vector::operator+=(const VectorSpaceVector &V) - { - // Check that casting will work. - Assert(dynamic_cast *>(&V) != nullptr, - ExcVectorTypeNotCompatible()); - - // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast &>(V); - // If the maps are the same we can update right away. - if (vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap()))) - { - vector->update(1., down_V.trilinos_vector(), 1.); - } - else - { - Assert(this->size() == down_V.size(), - ExcDimensionMismatch(this->size(), down_V.size())); - - // TODO: Tpetra doesn't have a combine mode that also updates local - // elements, maybe there is a better workaround. - Tpetra::Vector dummy( - vector->getMap(), false); - Tpetra::Import data_exchange( - down_V.trilinos_vector().getMap(), dummy.getMap()); - - dummy.doImport(down_V.trilinos_vector(), - data_exchange, - Tpetra::INSERT); - - vector->update(1.0, dummy, 1.0); - } - - return *this; - } - - - - template - Vector & - Vector::operator-=(const VectorSpaceVector &V) - { - this->add(-1., V); - - return *this; - } - - - - template - Number Vector::operator*(const VectorSpaceVector &V) const - { - // Check that casting will work. - Assert(dynamic_cast *>(&V) != nullptr, - ExcVectorTypeNotCompatible()); - - // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast &>(V); - Assert(this->size() == down_V.size(), - ExcDimensionMismatch(this->size(), down_V.size())); - Assert(vector->getMap()->isSameAs(*down_V.trilinos_vector().getMap()), - ExcDifferentParallelPartitioning()); - - return vector->dot(down_V.trilinos_vector()); - } - - - - template - void - Vector::add(const Number a) - { - AssertIsFinite(a); - - vector->template sync(); - auto vector_2d = vector->template getLocalView(); - auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); - vector->template modify(); - const size_t localLength = vector->getLocalLength(); - for (size_t k = 0; k < localLength; ++k) - { - vector_1d(k) += a; - } - vector->template sync< - typename Tpetra::Vector:: - device_type::memory_space>(); - } - - - - template - void - Vector::add(const Number a, const VectorSpaceVector &V) - { - // Check that casting will work. - Assert(dynamic_cast *>(&V) != nullptr, - ExcVectorTypeNotCompatible()); - - // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast &>(V); - AssertIsFinite(a); - Assert(vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap())), - ExcDifferentParallelPartitioning()); - - vector->update(a, down_V.trilinos_vector(), 1.); - } - - - - template - void - Vector::add(const Number a, - const VectorSpaceVector &V, - const Number b, - const VectorSpaceVector &W) - { - // Check that casting will work. - Assert(dynamic_cast *>(&V) != nullptr, - ExcVectorTypeNotCompatible()); - // Check that casting will work. - Assert(dynamic_cast *>(&W) != nullptr, - ExcVectorTypeNotCompatible()); - - // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast &>(V); - // Downcast W. If fails, throws an exception. - const Vector &down_W = dynamic_cast &>(W); - Assert(vector->getMap()->isSameAs(*(down_V.trilinos_vector().getMap())), - ExcDifferentParallelPartitioning()); - Assert(vector->getMap()->isSameAs(*(down_W.trilinos_vector().getMap())), - ExcDifferentParallelPartitioning()); - AssertIsFinite(a); - AssertIsFinite(b); - - vector->update( - a, down_V.trilinos_vector(), b, down_W.trilinos_vector(), 1.); - } - - - - template - void - Vector::sadd(const Number s, - const Number a, - const VectorSpaceVector &V) - { - // Check that casting will work. - Assert(dynamic_cast *>(&V) != nullptr, - ExcVectorTypeNotCompatible()); - - *this *= s; - // Downcast V. It fails, throws an exception. - const Vector &down_V = dynamic_cast &>(V); - Vector tmp(down_V); - tmp *= a; - *this += tmp; - } - - - - template - void - Vector::scale(const VectorSpaceVector &scaling_factors) - { - // Check that casting will work. - Assert(dynamic_cast *>(&scaling_factors) != nullptr, - ExcVectorTypeNotCompatible()); - - // Downcast scaling_factors. If fails, throws an exception. - const Vector &down_scaling_factors = - dynamic_cast &>(scaling_factors); - Assert(vector->getMap()->isSameAs( - *(down_scaling_factors.trilinos_vector().getMap())), - ExcDifferentParallelPartitioning()); - - vector->elementWiseMultiply(1., - *down_scaling_factors.vector, - *vector, - 0.); - } - - - - template - void - Vector::equ(const Number a, const VectorSpaceVector &V) - { - // Check that casting will work. - Assert(dynamic_cast *>(&V) != nullptr, - ExcVectorTypeNotCompatible()); - - // Downcast V. If fails, throws an exception. - const Vector &down_V = dynamic_cast &>(V); - // If we don't have the same map, copy. - if (vector->getMap()->isSameAs(*down_V.trilinos_vector().getMap()) == - false) - this->sadd(0., a, V); - else - { - // Otherwise, just update - vector->update(a, down_V.trilinos_vector(), 0.); - } - } - - - - template - bool - Vector::all_zero() const - { - // get a representation of the vector and - // loop over all the elements - Number * start_ptr = vector->getDataNonConst().get(); - const Number *ptr = start_ptr, - *eptr = start_ptr + vector->getLocalLength(); - unsigned int flag = 0; - while (ptr != eptr) - { - if (*ptr != Number(0)) - { - flag = 1; - break; - } - ++ptr; - } - - // Check that the vector is zero on _all_ processors. - const Teuchos::MpiComm *mpi_comm = - dynamic_cast *>( - vector->getMap()->getComm().get()); - Assert(mpi_comm != nullptr, ExcInternalError()); - unsigned int num_nonzero = - Utilities::MPI::sum(flag, *(mpi_comm->getRawMpiComm())()); - - return num_nonzero == 0; - } - - - - template - Number - Vector::mean_value() const - { - return vector->meanValue(); - } - - - - template - typename LinearAlgebra::VectorSpaceVector::real_type - Vector::l1_norm() const - { - return vector->norm1(); - } - - - - template - typename LinearAlgebra::VectorSpaceVector::real_type - Vector::l2_norm() const - { - return vector->norm2(); - } - - - - template - typename LinearAlgebra::VectorSpaceVector::real_type - Vector::linfty_norm() const - { - return vector->normInf(); - } - - - - template - Number - Vector::add_and_dot(const Number a, - const VectorSpaceVector &V, - const VectorSpaceVector &W) - { - this->add(a, V); - - return *this * W; - } - - - - template - typename Vector::size_type - Vector::size() const - { - return vector->getGlobalLength(); - } - - - - template - MPI_Comm - Vector::get_mpi_communicator() const - { - const auto tpetra_comm = dynamic_cast *>( - vector->getMap()->getComm().get()); - Assert(tpetra_comm != nullptr, ExcInternalError()); - return *(tpetra_comm->getRawMpiComm())(); - } - - - - template - ::dealii::IndexSet - Vector::locally_owned_elements() const - { - IndexSet is(size()); - - // easy case: local range is contiguous - if (vector->getMap()->isContiguous()) - { - is.add_range(vector->getMap()->getMinGlobalIndex(), - vector->getMap()->getMaxGlobalIndex() + 1); - } - else if (vector->getLocalLength() > 0) - { - const size_type n_indices = vector->getLocalLength(); - std::vector vector_indices; - vector_indices.reserve(n_indices); - for (unsigned int i = 0; i < n_indices; ++i) - vector_indices.push_back(vector->getMap()->getGlobalElement(i)); - - is.add_indices(vector_indices.data(), - vector_indices.data() + n_indices); - } - is.compress(); - - return is; - } - - - - template - const Tpetra::Vector & - Vector::trilinos_vector() const - { - return *vector; - } - - - - template - Tpetra::Vector & - Vector::trilinos_vector() - { - return *vector; - } - - - - template - void - Vector::print(std::ostream & out, - const unsigned int precision, - const bool scientific, - const bool across) const - { - AssertThrow(out, ExcIO()); - boost::io::ios_flags_saver restore_flags(out); - - // Get a representation of the vector and loop over all - // the elements - const auto val = vector->get1dView(); - - out.precision(precision); - if (scientific) - out.setf(std::ios::scientific, std::ios::floatfield); - else - out.setf(std::ios::fixed, std::ios::floatfield); - - vector->template sync(); - auto vector_2d = vector->template getLocalView(); - auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0); - const size_t local_length = vector->getLocalLength(); - - if (across) - for (unsigned int i = 0; i < local_length; ++i) - out << vector_1d(i) << ' '; - else - for (unsigned int i = 0; i < local_length; ++i) - out << vector_1d(i) << std::endl; - out << std::endl; - - // restore the representation - // of the vector - AssertThrow(out, ExcIO()); - } - - - - template - std::size_t - Vector::memory_consumption() const - { - return sizeof(*this) + - vector->getLocalLength() * - (sizeof(Number) + sizeof(TrilinosWrappers::types::int_type)); - } - - - - template - void - Vector::create_tpetra_comm_pattern(const IndexSet &source_index_set, - const MPI_Comm &mpi_comm) - { - source_stored_elements = source_index_set; - tpetra_comm_pattern = - std::make_shared( - locally_owned_elements(), source_index_set, mpi_comm); - } - template class Vector; template class Vector; # ifdef DEAL_II_WITH_COMPLEX_VALUES @@ -679,5 +36,4 @@ namespace LinearAlgebra DEAL_II_NAMESPACE_CLOSE # endif - #endif From a5dc36e301666fce055f39b3c3996520f7de3eb0 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 22 Feb 2019 15:04:35 +0100 Subject: [PATCH 183/507] Mark Tpetra as optional --- doc/external-libs/trilinos.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/external-libs/trilinos.html b/doc/external-libs/trilinos.html index 4e3a51552298..09e13e35a04e 100644 --- a/doc/external-libs/trilinos.html +++ b/doc/external-libs/trilinos.html @@ -67,7 +67,7 @@
    Installing Trilinos
  • ROL (optional),
  • Sacado (optional),
  • Teuchos, -
  • Tpetra, +
  • Tpetra (optional),
  • Zoltan (optional). From 12f2084c6ce0670a7b470aa1157bab02de31c294 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Sat, 23 Feb 2019 18:09:57 +0100 Subject: [PATCH 184/507] add has_begin detector --- include/deal.II/matrix_free/fe_evaluation.h | 21 +++++++++++++++++++ .../matrix_free/fe_evaluation_type_traits.cc | 9 ++++++++ ...tion_type_traits.with_trilinos=true.output | 3 +++ 3 files changed, 33 insertions(+) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index 8da043d70bee..4b088f977d17 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3450,6 +3450,27 @@ namespace internal }; + + // same as above to check + // T::const_iterator T::begin() const + template + struct has_begin + { + private: + static void + detect(...); + + template + static decltype(std::declval().begin()) + detect(const U &); + + public: + static constexpr bool value = + std::is_same()))>::value; + }; + + // access to generic vectors that have operator (). // FIXME: this is wrong for Trilinos/Petsc MPI vectors template ::value << std::endl; + // check has_begin(): + deallog + << "has_begin:" << std::endl + << "LinearAlgebra::distributed::Vector = " + << internal::has_begin>::value + << std::endl + << "TrilinosWrappers::MPI::Vector = " + << internal::has_begin::value << std::endl; + deallog << "OK" << std::endl; } diff --git a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output index 4e82d5220255..71bac87207dc 100644 --- a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output +++ b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output @@ -10,4 +10,7 @@ DEAL::Dummy2::operator() DEAL::has_partitioners_are_compatible: DEAL::LinearAlgebra::distributed::Vector = 1 DEAL::TrilinosWrappers::MPI::Vector = 0 +DEAL::has_begin: +DEAL::LinearAlgebra::distributed::Vector = 1 +DEAL::TrilinosWrappers::MPI::Vector = 1 DEAL::OK From 271769536678200e40d90d454d7dbd9bfad55326 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Sat, 23 Feb 2019 19:26:36 +0100 Subject: [PATCH 185/507] add vectorizable type trait --- include/deal.II/matrix_free/fe_evaluation.h | 16 ++++++++++++++++ tests/matrix_free/fe_evaluation_type_traits.cc | 16 +++++++++++++++- ...luation_type_traits.with_trilinos=true.output | 4 ++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index 4b088f977d17..3b498f167a64 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3471,8 +3471,24 @@ namespace internal }; + // type trait for vector T and Number to see if + // we can do vectorized load/save. + // for VectorReader and VectorDistributorLocalToGlobal we assume that + // if both begin() and local_element() + // exist, then begin() + offset == local_element(offset) + template + struct vectorizable + { + static constexpr bool value = + has_begin::value && has_local_element::value && + std::is_same::value; + }; + + + // access to generic vectors that have operator (). // FIXME: this is wrong for Trilinos/Petsc MPI vectors + // where we should first do Partitioner::local_to_global() template ::value, VectorType>::type * = nullptr> diff --git a/tests/matrix_free/fe_evaluation_type_traits.cc b/tests/matrix_free/fe_evaluation_type_traits.cc index d3363649aa18..3655a18f2fad 100644 --- a/tests/matrix_free/fe_evaluation_type_traits.cc +++ b/tests/matrix_free/fe_evaluation_type_traits.cc @@ -129,7 +129,7 @@ main() TrilinosWrappers::MPI::Vector>::value << std::endl; - // check has_begin(): + // check has_begin: deallog << "has_begin:" << std::endl << "LinearAlgebra::distributed::Vector = " @@ -137,6 +137,20 @@ main() << std::endl << "TrilinosWrappers::MPI::Vector = " << internal::has_begin::value << std::endl; + // check vectorizable: + deallog + << "vectorizable:" << std::endl + << "LinearAlgebra::distributed::Vector && double = " + << internal::vectorizable, + double>::value + << std::endl + << "LinearAlgebra::distributed::Vector && float = " + << internal::vectorizable, + float>::value + << std::endl + << "TrilinosWrappers::MPI::Vector && double = " + << internal::vectorizable::value + << std::endl; deallog << "OK" << std::endl; } diff --git a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output index 71bac87207dc..d514ab7eea06 100644 --- a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output +++ b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output @@ -13,4 +13,8 @@ DEAL::TrilinosWrappers::MPI::Vector = 0 DEAL::has_begin: DEAL::LinearAlgebra::distributed::Vector = 1 DEAL::TrilinosWrappers::MPI::Vector = 1 +DEAL::vectorizable: +DEAL::LinearAlgebra::distributed::Vector && double = 1 +DEAL::LinearAlgebra::distributed::Vector && float = 0 +DEAL::TrilinosWrappers::MPI::Vector && double = 0 DEAL::OK From 61585e1c8b826c9f2a8729e646e59fd84691145b Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Sat, 23 Feb 2019 20:14:04 +0100 Subject: [PATCH 186/507] use is_vectorizable type trait in FEEvaluation classes --- include/deal.II/matrix_free/fe_evaluation.h | 44 +++++++------------ .../matrix_free/fe_evaluation_type_traits.cc | 14 +++--- ...tion_type_traits.with_trilinos=true.output | 2 +- 3 files changed, 25 insertions(+), 35 deletions(-) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index 3b498f167a64..56b5a6b2b261 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3477,7 +3477,7 @@ namespace internal // if both begin() and local_element() // exist, then begin() + offset == local_element(offset) template - struct vectorizable + struct is_vectorizable { static constexpr bool value = has_begin::value && has_local_element::value && @@ -4084,6 +4084,10 @@ FEEvaluationBase::read_write_operation( ExcNotImplemented("Masking currently not implemented for " "non-contiguous DoF storage")); + std::integral_constant::value> + vector_selector; + const unsigned int dofs_per_component = this->data->dofs_per_component_on_cell; if (dof_info->index_storage_variants @@ -4102,28 +4106,17 @@ FEEvaluationBase::read_write_operation( for (unsigned int i = 0; i < dofs_per_component; ++i, dof_indices += n_vectorization) for (unsigned int comp = 0; comp < n_components; ++comp) - operation.process_dof_gather( - dof_indices, - *src[comp], - 0, - values_dofs[comp][i], - std::integral_constant< - bool, - std::is_same::value>()); + operation.process_dof_gather(dof_indices, + *src[comp], + 0, + values_dofs[comp][i], + vector_selector); else for (unsigned int comp = 0; comp < n_components; ++comp) for (unsigned int i = 0; i < dofs_per_component; ++i, dof_indices += n_vectorization) operation.process_dof_gather( - dof_indices, - *src[0], - 0, - values_dofs[comp][i], - std::integral_constant< - bool, - std::is_same::value>()); + dof_indices, *src[0], 0, values_dofs[comp][i], vector_selector); return; } @@ -4498,9 +4491,8 @@ FEEvaluationBase:: // a vector and puts the data into the local data field or write local data // into the vector. Certain operations are no-ops for the given use case. - std::integral_constant< - bool, - std::is_same::value> + std::integral_constant::value> vector_selector; const internal::MatrixFreeFunctions::DoFInfo::DoFAccessIndex ind = is_face ? dof_access_index : @@ -7628,9 +7620,8 @@ FEFaceEvaluation:: temp1 = this->scratch_data; internal::VectorReader reader; - std::integral_constant< - bool, - std::is_same::value> + std::integral_constant::value> vector_selector; // case 1: contiguous and interleaved indices @@ -8188,9 +8179,8 @@ FEFaceEvaluation:: # endif internal::VectorDistributorLocalToGlobal writer; - std::integral_constant< - bool, - std::is_same::value> + std::integral_constant::value> vector_selector; // case 1: contiguous and interleaved indices diff --git a/tests/matrix_free/fe_evaluation_type_traits.cc b/tests/matrix_free/fe_evaluation_type_traits.cc index 3655a18f2fad..a57403844271 100644 --- a/tests/matrix_free/fe_evaluation_type_traits.cc +++ b/tests/matrix_free/fe_evaluation_type_traits.cc @@ -137,19 +137,19 @@ main() << std::endl << "TrilinosWrappers::MPI::Vector = " << internal::has_begin::value << std::endl; - // check vectorizable: + // check is_vectorizable: deallog - << "vectorizable:" << std::endl + << "is_vectorizable:" << std::endl << "LinearAlgebra::distributed::Vector && double = " - << internal::vectorizable, - double>::value + << internal::is_vectorizable, + double>::value << std::endl << "LinearAlgebra::distributed::Vector && float = " - << internal::vectorizable, - float>::value + << internal::is_vectorizable, + float>::value << std::endl << "TrilinosWrappers::MPI::Vector && double = " - << internal::vectorizable::value + << internal::is_vectorizable::value << std::endl; deallog << "OK" << std::endl; diff --git a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output index d514ab7eea06..d6140df34255 100644 --- a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output +++ b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output @@ -13,7 +13,7 @@ DEAL::TrilinosWrappers::MPI::Vector = 0 DEAL::has_begin: DEAL::LinearAlgebra::distributed::Vector = 1 DEAL::TrilinosWrappers::MPI::Vector = 1 -DEAL::vectorizable: +DEAL::is_vectorizable: DEAL::LinearAlgebra::distributed::Vector && double = 1 DEAL::LinearAlgebra::distributed::Vector && float = 0 DEAL::TrilinosWrappers::MPI::Vector && double = 0 From 218e6b9eeb120f08bf75e77ddae8e55a0fbd8ca2 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 24 Feb 2019 16:40:19 +0100 Subject: [PATCH 187/507] Check SUNDIALS version when configuring --- cmake/configure/configure_sundials.cmake | 28 +++++++++++ cmake/modules/FindSUNDIALS.cmake | 60 ++++++++++++++++++++++-- include/deal.II/base/config.h.in | 41 ++++++++-------- 3 files changed, 104 insertions(+), 25 deletions(-) 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/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/include/deal.II/base/config.h.in b/include/deal.II/base/config.h.in index 23690507599d..65c5efa5bc3b 100644 --- a/include/deal.II/base/config.h.in +++ b/include/deal.II/base/config.h.in @@ -245,30 +245,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: From 7ed7ae86f90f4ffd21a575002f63980c840439e2 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Sun, 24 Feb 2019 18:06:17 +0100 Subject: [PATCH 188/507] change is_vectorizable to work with serial vectors --- include/deal.II/matrix_free/fe_evaluation.h | 3 ++- tests/matrix_free/fe_evaluation_type_traits.cc | 10 +++++++++- ...fe_evaluation_type_traits.with_trilinos=true.output | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index 56b5a6b2b261..f8b4975bf9c6 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3480,7 +3480,8 @@ namespace internal struct is_vectorizable { static constexpr bool value = - has_begin::value && has_local_element::value && + has_begin::value && + (has_local_element::value || is_serial_vector::value) && std::is_same::value; }; diff --git a/tests/matrix_free/fe_evaluation_type_traits.cc b/tests/matrix_free/fe_evaluation_type_traits.cc index a57403844271..762da8b50d08 100644 --- a/tests/matrix_free/fe_evaluation_type_traits.cc +++ b/tests/matrix_free/fe_evaluation_type_traits.cc @@ -109,6 +109,8 @@ main() << "Dummy = " << internal::has_local_element>::value << std::endl << "Dummy2 = " << internal::has_local_element>::value + << std::endl + << "Vector = " << internal::has_local_element>::value << std::endl; // now check internal::vector_access wrapper @@ -127,6 +129,9 @@ main() << "TrilinosWrappers::MPI::Vector = " << internal::has_partitioners_are_compatible< TrilinosWrappers::MPI::Vector>::value + << std::endl + << "Vector = " + << internal::has_partitioners_are_compatible>::value << std::endl; // check has_begin: @@ -136,7 +141,8 @@ main() << internal::has_begin>::value << std::endl << "TrilinosWrappers::MPI::Vector = " - << internal::has_begin::value << std::endl; + << internal::has_begin::value << std::endl + << "Vector = " << internal::has_begin>::value << std::endl; // check is_vectorizable: deallog << "is_vectorizable:" << std::endl @@ -150,6 +156,8 @@ main() << std::endl << "TrilinosWrappers::MPI::Vector && double = " << internal::is_vectorizable::value + << std::endl + << "Vector = " << internal::is_vectorizable, double>::value << std::endl; deallog << "OK" << std::endl; diff --git a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output index d6140df34255..801cf4191e20 100644 --- a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output +++ b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output @@ -4,17 +4,21 @@ DEAL::LinearAlgebra::distributed::Vector = 1 DEAL::TrilinosWrappers::MPI::Vector = 0 DEAL::Dummy = 1 DEAL::Dummy2 = 0 +DEAL::Vector = 0 DEAL::internal::vector_access: DEAL::Dummy::local_element() DEAL::Dummy2::operator() DEAL::has_partitioners_are_compatible: DEAL::LinearAlgebra::distributed::Vector = 1 DEAL::TrilinosWrappers::MPI::Vector = 0 +DEAL::Vector = 0 DEAL::has_begin: DEAL::LinearAlgebra::distributed::Vector = 1 DEAL::TrilinosWrappers::MPI::Vector = 1 +DEAL::Vector = 1 DEAL::is_vectorizable: DEAL::LinearAlgebra::distributed::Vector && double = 1 DEAL::LinearAlgebra::distributed::Vector && float = 0 DEAL::TrilinosWrappers::MPI::Vector && double = 0 +DEAL::Vector = 1 DEAL::OK From 5c6688aff794bf38d76eb621d04b22de7eb5bd1c Mon Sep 17 00:00:00 2001 From: Giovanni Alzetta Date: Mon, 25 Feb 2019 12:40:27 +0100 Subject: [PATCH 189/507] Guess point owner uses std::move to return tuple --- source/grid/grid_tools.cc | 13 +++---------- ...t_owner_1.cc => grid_tools_guess_pt_owner_01.cc} | 0 ...1.output => grid_tools_guess_pt_owner_01.output} | 0 3 files changed, 3 insertions(+), 10 deletions(-) rename tests/grid/{grid_tools_guess_pt_owner_1.cc => grid_tools_guess_pt_owner_01.cc} (100%) rename tests/grid/{grid_tools_guess_pt_owner_1.output => grid_tools_guess_pt_owner_01.output} (100%) diff --git a/source/grid/grid_tools.cc b/source/grid/grid_tools.cc index 58d12d3a94fc..44d49753d166 100644 --- a/source/grid/grid_tools.cc +++ b/source/grid/grid_tools.cc @@ -2091,16 +2091,9 @@ namespace GridTools map_owners_guessed[pt] = owners_found; } - std::tuple>, - std::map, - std::map>> - output_tuple; - - std::get<0>(output_tuple) = point_owners; - std::get<1>(output_tuple) = map_owners_found; - std::get<2>(output_tuple) = map_owners_guessed; - - return output_tuple; + return std::make_tuple(std::move(point_owners), + std::move(map_owners_found), + std::move(map_owners_guessed)); } diff --git a/tests/grid/grid_tools_guess_pt_owner_1.cc b/tests/grid/grid_tools_guess_pt_owner_01.cc similarity index 100% rename from tests/grid/grid_tools_guess_pt_owner_1.cc rename to tests/grid/grid_tools_guess_pt_owner_01.cc diff --git a/tests/grid/grid_tools_guess_pt_owner_1.output b/tests/grid/grid_tools_guess_pt_owner_01.output similarity index 100% rename from tests/grid/grid_tools_guess_pt_owner_1.output rename to tests/grid/grid_tools_guess_pt_owner_01.output From 34ea16872f1aac75e54ad630c9d70554bab77c42 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 24 Feb 2019 00:50:41 +0100 Subject: [PATCH 190/507] Work around nvcc_wrapper std::complex problem --- include/deal.II/base/tensor.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/deal.II/base/tensor.h b/include/deal.II/base/tensor.h index b299ed09a756..7b0531ff9312 100644 --- a/include/deal.II/base/tensor.h +++ b/include/deal.II/base/tensor.h @@ -924,6 +924,35 @@ Tensor<0, dim, Number>::operator-=(const Tensor<0, dim, OtherNumber> &p) } + +#ifdef __CUDA_ARCH__ +namespace internal +{ + template + DEAL_II_CUDA_HOST_DEV void + multiply_assign_scalar(Number &tensor, const OtherNumber &s) + { + tensor *= s; + } + + template + DEAL_II_CUDA_HOST_DEV void + multiply_assign_scalar(std::complex &, const OtherNumber &) + { + printf("This function is not implemented for std::complex!\n"); + assert(false); + } +} // namespace internal + +template +template +inline DEAL_II_CUDA_HOST_DEV Tensor<0, dim, Number> & +Tensor<0, dim, Number>::operator*=(const OtherNumber &s) +{ + internal::multiply_assign_scalar(value, s); + return *this; +} +#else template template inline DEAL_II_CUDA_HOST_DEV Tensor<0, dim, Number> & @@ -932,6 +961,8 @@ Tensor<0, dim, Number>::operator*=(const OtherNumber &s) value *= s; return *this; } +#endif + template From daf8bbc987881f83d7d194224bef6077091a8fd6 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 24 Feb 2019 11:28:20 +0100 Subject: [PATCH 191/507] Fix vector_access --- include/deal.II/matrix_free/fe_evaluation.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index f8b4975bf9c6..7bdd4e15a620 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3471,6 +3471,7 @@ namespace internal }; + // type trait for vector T and Number to see if // we can do vectorized load/save. // for VectorReader and VectorDistributorLocalToGlobal we assume that @@ -3487,7 +3488,21 @@ namespace internal - // access to generic vectors that have operator (). + // access to generic const vectors that have operator (). + // FIXME: this is wrong for Trilinos/Petsc MPI vectors + // where we should first do Partitioner::local_to_global() + template ::value, + VectorType>::type * = nullptr> + inline typename VectorType::value_type + vector_access(const VectorType &vec, const unsigned int entry) + { + return vec(entry); + } + + + + // access to generic non-const vectors that have operator (). // FIXME: this is wrong for Trilinos/Petsc MPI vectors // where we should first do Partitioner::local_to_global() template Date: Tue, 26 Feb 2019 06:34:05 +0100 Subject: [PATCH 192/507] fix internal::has_begin type trait used in FEEvaluation --- include/deal.II/matrix_free/fe_evaluation.h | 3 +-- tests/matrix_free/fe_evaluation_type_traits.cc | 3 ++- .../fe_evaluation_type_traits.with_trilinos=true.output | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index 20b8249e0313..77e6975cff6d 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3466,8 +3466,7 @@ namespace internal public: static constexpr bool value = - std::is_same()))>::value; + !std::is_same()))>::value; }; diff --git a/tests/matrix_free/fe_evaluation_type_traits.cc b/tests/matrix_free/fe_evaluation_type_traits.cc index 762da8b50d08..ffa65526980c 100644 --- a/tests/matrix_free/fe_evaluation_type_traits.cc +++ b/tests/matrix_free/fe_evaluation_type_traits.cc @@ -142,7 +142,8 @@ main() << std::endl << "TrilinosWrappers::MPI::Vector = " << internal::has_begin::value << std::endl - << "Vector = " << internal::has_begin>::value << std::endl; + << "Vector = " << internal::has_begin>::value << std::endl + << "Dummy = " << internal::has_begin>::value << std::endl; // check is_vectorizable: deallog << "is_vectorizable:" << std::endl diff --git a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output index 801cf4191e20..b7e821fc996f 100644 --- a/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output +++ b/tests/matrix_free/fe_evaluation_type_traits.with_trilinos=true.output @@ -16,6 +16,7 @@ DEAL::has_begin: DEAL::LinearAlgebra::distributed::Vector = 1 DEAL::TrilinosWrappers::MPI::Vector = 1 DEAL::Vector = 1 +DEAL::Dummy = 0 DEAL::is_vectorizable: DEAL::LinearAlgebra::distributed::Vector && double = 1 DEAL::LinearAlgebra::distributed::Vector && float = 0 From 244aa95d7f04e61318825d5fa3215ad9964c485b Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 26 Feb 2019 11:29:02 +0100 Subject: [PATCH 193/507] Define GridTools::Cache::get_covering_rtree also without nanoflann support --- source/grid/grid_tools_cache.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/grid/grid_tools_cache.cc b/source/grid/grid_tools_cache.cc index 739ea04bda38..52f664b01aec 100644 --- a/source/grid/grid_tools_cache.cc +++ b/source/grid/grid_tools_cache.cc @@ -140,6 +140,8 @@ namespace GridTools return cell_bounding_boxes_rtree; } + + #ifdef DEAL_II_WITH_NANOFLANN template const KDTree & @@ -152,6 +154,7 @@ namespace GridTools } return vertex_kdtree; } +#endif @@ -187,7 +190,6 @@ namespace GridTools return covering_rtree; } -#endif #include "grid_tools_cache.inst" From 915f1a2149255096acb297e705e32d2499b017c7 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 26 Feb 2019 11:58:15 +0100 Subject: [PATCH 194/507] Have another namespace inclosing the workaround --- include/deal.II/base/tensor.h | 43 ++++++++++++++++------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/include/deal.II/base/tensor.h b/include/deal.II/base/tensor.h index 7b0531ff9312..97fa8d608e07 100644 --- a/include/deal.II/base/tensor.h +++ b/include/deal.II/base/tensor.h @@ -925,43 +925,38 @@ Tensor<0, dim, Number>::operator-=(const Tensor<0, dim, OtherNumber> &p) -#ifdef __CUDA_ARCH__ namespace internal { - template - DEAL_II_CUDA_HOST_DEV void - multiply_assign_scalar(Number &tensor, const OtherNumber &s) + namespace ComplexWorkaround { - tensor *= s; - } + template + inline DEAL_II_CUDA_HOST_DEV void + multiply_assign_scalar(Number &val, const OtherNumber &s) + { + val *= s; + } - template - DEAL_II_CUDA_HOST_DEV void - multiply_assign_scalar(std::complex &, const OtherNumber &) - { - printf("This function is not implemented for std::complex!\n"); - assert(false); - } +#ifdef __CUDA_ARCH__ + template + inline DEAL_II_CUDA_HOST_DEV void + multiply_assign_scalar(std::complex &, const OtherNumber &) + { + printf("This function is not implemented for std::complex!\n"); + assert(false); + } +#endif + } // namespace ComplexWorkaround } // namespace internal + template template inline DEAL_II_CUDA_HOST_DEV Tensor<0, dim, Number> & Tensor<0, dim, Number>::operator*=(const OtherNumber &s) { - internal::multiply_assign_scalar(value, s); - return *this; -} -#else -template -template -inline DEAL_II_CUDA_HOST_DEV Tensor<0, dim, Number> & -Tensor<0, dim, Number>::operator*=(const OtherNumber &s) -{ - value *= s; + internal::ComplexWorkaround::multiply_assign_scalar(value, s); return *this; } -#endif From 911cedfa9169e8e9a971ea0efb4bc8e120079894 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Tue, 26 Feb 2019 17:12:21 +0100 Subject: [PATCH 195/507] consistently for non-void in internal::has_local_element --- include/deal.II/matrix_free/fe_evaluation.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index 77e6975cff6d..ac87eea988cd 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3420,12 +3420,11 @@ namespace internal detect(const U &); public: - // finally here we check if our detector has return type same as + // finally here we check if our detector has non-void return type // T::value_type. This will happen if compiler can use second detector, // otherwise SFINAE let it work with the more general first one that is void static constexpr bool value = - std::is_same()))>::value; + !std::is_same()))>::value; }; @@ -3452,7 +3451,7 @@ namespace internal // same as above to check - // T::const_iterator T::begin() const + // ... T::begin() const template struct has_begin { From cdb24ff2c120c83517b0e458b1d31aec5000d686 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Tue, 26 Feb 2019 18:32:37 +0100 Subject: [PATCH 196/507] make old compilers happy --- include/deal.II/matrix_free/fe_evaluation.h | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index ac87eea988cd..337846d4bd28 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3423,10 +3423,13 @@ namespace internal // finally here we check if our detector has non-void return type // T::value_type. This will happen if compiler can use second detector, // otherwise SFINAE let it work with the more general first one that is void - static constexpr bool value = + static const bool value = !std::is_same()))>::value; }; + // We need to have a separate declaration for static const members + template + const bool has_local_element::value; // same as above to check // bool T::partitioners_are_compatible(const Utilities::MPI::Partitioner &) @@ -3444,10 +3447,13 @@ namespace internal detect(const U &); public: - static constexpr bool value = + static const bool value = std::is_same()))>::value; }; + // We need to have a separate declaration for static const members + template + const bool has_partitioners_are_compatible::value; // same as above to check @@ -3464,10 +3470,13 @@ namespace internal detect(const U &); public: - static constexpr bool value = + static const bool value = !std::is_same()))>::value; }; + // We need to have a separate declaration for static const members + template + const bool has_begin::value; // type trait for vector T and Number to see if @@ -3478,12 +3487,15 @@ namespace internal template struct is_vectorizable { - static constexpr bool value = + static const bool value = has_begin::value && (has_local_element::value || is_serial_vector::value) && std::is_same::value; }; + // We need to have a separate declaration for static const members + template + const bool is_vectorizable::value; // access to generic const vectors that have operator (). From 34f9c07b2d0cad24d0d355d3a9ca3e1c8dbfaebe Mon Sep 17 00:00:00 2001 From: notxor Date: Wed, 27 Feb 2019 09:11:42 +0100 Subject: [PATCH 197/507] adapt pvtu output for tensors --- .../changes/minor/20190227DanielJodlbauer | 3 + source/base/data_out_base.cc | 41 ++-- tests/data_out/data_out_13.cc | 200 ++++++++++++++++++ tests/data_out/data_out_13.output | 101 +++++++++ 4 files changed, 330 insertions(+), 15 deletions(-) create mode 100644 doc/news/changes/minor/20190227DanielJodlbauer create mode 100644 tests/data_out/data_out_13.cc create mode 100644 tests/data_out/data_out_13.output 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/source/base/data_out_base.cc b/source/base/data_out_base.cc index 65336ef19154..939c0c905042 100644 --- a/source/base/data_out_base.cc +++ b/source/base/data_out_base.cc @@ -5990,20 +5990,30 @@ namespace DataOutBase std::vector data_set_written(n_data_sets, false); for (const auto &nonscalar_data_range : nonscalar_data_ranges) { - AssertThrow(std::get<1>(nonscalar_data_range) >= - std::get<0>(nonscalar_data_range), - ExcLowerRange(std::get<1>(nonscalar_data_range), - std::get<0>(nonscalar_data_range))); - AssertThrow(std::get<1>(nonscalar_data_range) < n_data_sets, - ExcIndexRange(std::get<1>(nonscalar_data_range), - 0, - n_data_sets)); - AssertThrow(std::get<1>(nonscalar_data_range) + 1 - - std::get<0>(nonscalar_data_range) <= - 3, - ExcMessage( - "Can't declare a vector with more than 3 components " - "in VTK")); + const auto first_component = std::get<0>(nonscalar_data_range); + const auto last_component = std::get<1>(nonscalar_data_range); + const bool is_tensor = + (std::get<3>(nonscalar_data_range) == + DataComponentInterpretation::component_is_part_of_tensor); + const unsigned int n_components = (is_tensor ? 9 : 3); + AssertThrow(last_component >= first_component, + ExcLowerRange(last_component, first_component)); + AssertThrow(last_component < n_data_sets, + ExcIndexRange(last_component, 0, n_data_sets)); + if (is_tensor) + { + AssertThrow((last_component + 1 - first_component <= 9), + ExcMessage( + "Can't declare a tensor with more than 9 components " + "in VTK")); + } + else + { + Assert((last_component + 1 - first_component <= 3), + ExcMessage( + "Can't declare a vector with more than 3 components " + "in VTK")); + } // mark these components as already written: for (unsigned int i = std::get<0>(nonscalar_data_range); @@ -6026,7 +6036,8 @@ namespace DataOutBase out << data_names[std::get<1>(nonscalar_data_range)]; } - out << "\" NumberOfComponents=\"3\" format=\"ascii\"/>\n"; + out << "\" NumberOfComponents=\"" << n_components + << "\" format=\"ascii\"/>\n"; } for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set) diff --git a/tests/data_out/data_out_13.cc b/tests/data_out/data_out_13.cc new file mode 100644 index 000000000000..582285c0d218 --- /dev/null +++ b/tests/data_out/data_out_13.cc @@ -0,0 +1,200 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Output tensor-valued data in pvtu + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include "../tests.h" + + + +template +void +check() +{ + Triangulation tria; + GridGenerator::hyper_cube(tria, 0., 1.); + + FESystem fe(FE_Q(1), + dim, // vector valued + FE_Q(1), + dim * dim); // tensor valued + + DoFHandler dof_handler(tria); + dof_handler.distribute_dofs(fe); + + Vector v(dof_handler.n_dofs()); + + + // 1 cell is enough to test: + const unsigned int dofs_per_cell = v.size(); + + // take 8 tensors from tensors.vtk file inside + // http://paraview.org/Wiki/images/8/81/TensorGlyph_v_1_0_3.zip or + // http://paraview.org/Wiki/images/3/39/SuperquadricTensorGlyph_v3.zip + const std::vector>> tensors_3d = { + {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, + {{-2, 0, 0}, {0, -2, 0}, {0, 0, 3}}, + {{1, 0, 0}, {0, 1, 0}, {0, 0, .001}}, + {{2, 1, 1}, {1, 2, 1}, {1, 1, 3}}, + {{0.247186415568, 0.490995206139, 0.131324884836}, + {0.490995206139, -0.371055707211, 0.719071682671}, + {0.131324884836, 0.719071682671, -0.156008182087}}, + {{0.280587657181, 0.467438945439, 0.934953136331}, + {0.467438945439, 0.0600321140579, -0.211376327727}, + {0.934953136331, -0.211376327727, 0.962975830149}}, + {{0.0628609549443, -0.0117908465212, -0.667617347633}, + {-0.0117908465212, -0.390601011028, -0.95780533241}, + {-0.667617347633, -0.95780533241, -0.193319773383}}, + {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}}; + + // coords: + const std::vector> coords_3d = {{0, 0, 0}, + {1, 0, 0}, + {0, 1, 0}, + {1, 1, 0}, + {0, 0, 1}, + {1, 0, 1}, + {0, 1, 1}, + {1, 1, 1}}; + + const std::vector>> tensors_2d = { + {{1, 0}, {0, 1}}, {{3, 0}, {0, 1}}, {{1, 0}, {0, 3}}, {{3, 1}, {1, 2}}}; + + // coords: + const std::vector> coords_2d = {{0, 0}, + {1, 0}, + {0, 1}, + {1, 1}}; + + const std::vector>> &tensors = + (dim == 2 ? tensors_2d : tensors_3d); + const std::vector> &coords = + (dim == 2 ? coords_2d : coords_3d); + + const Quadrature support_quadrature(fe.get_unit_support_points()); + FEValues fe_values(fe, support_quadrature, update_quadrature_points); + for (const auto cell : dof_handler.active_cell_iterators()) + { + fe_values.reinit(cell); + const auto &qp = fe_values.get_quadrature_points(); + + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + const auto & this_qp = qp[i]; + const unsigned int i_group = fe.system_to_base_index(i).first.first; + const unsigned int i_comp = fe.system_to_component_index(i).first; + if (i_group == 0) + // vector + { + if (i_comp == 0) + v(i) = 1; + else if (i_comp == 1) + v(i) = this_qp[1]; + else + v(i) = 0.; + } + else + // tensor + { + // find matching location + unsigned int p = 0; + for (const auto c : coords) + { + Point point; + for (unsigned int d = 0; d < dim; ++d) + point[d] = c[d]; + + const auto diff = point - this_qp; + if (diff.norm() < 1e-10) + break; + + ++p; + } + + const unsigned int tens_comp = i_comp - dim; + const unsigned int ii = + Tensor<2, dim>::unrolled_to_component_indices(tens_comp)[0]; + const unsigned int jj = + Tensor<2, dim>::unrolled_to_component_indices(tens_comp)[1]; + v(i) = tensors[p][ii][jj]; + } + } + } + + std::vector + data_component_interpretation( + dim + dim * dim, + DataComponentInterpretation::component_is_part_of_tensor); + std::fill(data_component_interpretation.begin(), + data_component_interpretation.begin() + dim, + DataComponentInterpretation::component_is_part_of_vector); + + std::vector component_name(dim + dim * dim, "tensor"); + std::fill(component_name.begin(), component_name.begin() + dim, "vector"); + + DataOut data_out; + data_out.attach_dof_handler(dof_handler); + data_out.add_data_vector(v, + component_name, + DataOut::type_dof_data, + data_component_interpretation); + data_out.build_patches(); + + std::vector filenames; + filenames.push_back("output_" + Utilities::int_to_string(dim) + "d.vtu"); + + /* + std::ofstream master_output("output_" + Utilities::int_to_string(dim) + + "d.pvtu"); data_out.write_pvtu_record(master_output, filenames); + + std::ofstream out(filenames[0]); + data_out.write_vtu(out); + */ + + data_out.write_vtu(deallog.get_file_stream()); + data_out.write_pvtu_record(deallog.get_file_stream(), filenames); +} + + + +int +main() +{ + initlog(); + check<2>(); + check<3>(); +} diff --git a/tests/data_out/data_out_13.output b/tests/data_out/data_out_13.output new file mode 100644 index 000000000000..f410ee99e097 --- /dev/null +++ b/tests/data_out/data_out_13.output @@ -0,0 +1,101 @@ + + + + + + + + +AQAAADAAAAAwAAAAFAAAAA==eNpjYEAGDfYMWPkgGsIGADHwAv0= + + + + + +AQAAABAAAAAQAAAAEwAAAA==eNpjYGBgYARiZiBmAmIAADwABw== + + +AQAAAAQAAAAEAAAADAAAAA==eNpjYWBgAAAAFAAF + + +AQAAAAEAAAABAAAACQAAAA==eNrjBAAACgAK + + + + +AQAAADAAAAAwAAAAFAAAAA==eNpjYGiwZ4ADdDaMj2ADAGQuBHs= + +AQAAAJAAAACQAAAAIgAAAA==eNpjYGiwZ0AB6HwQcHAgrAZdDF0PTAymDkxjqAEAycUGOw== + + + + + + + + + + + + + + + + + + + + + + + + + +AQAAAGAAAABgAAAAGgAAAA==eNpjYEAGDfYMWPkgGpscsjyyGAIDAC3jCPU= + + + + + +AQAAACAAAAAgAAAAHQAAAA==eNpjYGBgYARiZiBmAmIWIGYFYnYgZgNiAAF4AB0= + + +AQAAAAQAAAAEAAAADAAAAA==eNrjYGBgAAAAJAAJ + + +AQAAAAEAAAABAAAACQAAAA==eNrjAQAADQAN + + + + +AQAAAGAAAABgAAAAFgAAAA==eNpjYGiwZ4ADdDaMj84mXj0An0sI9Q== + +AQAAACABAAAgAQAAhAAAAA==eNpjYGiwZ0ABWPkHUMXQ+Q4ODATMyRdqtgIphIjDMDrfwaFArtZuZ/JvO44qNjDN/HvvPlFRC3sQH0TPOSC/T39lv51GyHs78ch8exBt86TUlrM4Yh+ID6KntZbZ2+9tsE3Vc9zz44XWfhB9+8/xfbuNSveD+CB63lfXfQxEAACmEDx/ + + + + + + + + + + + + + + + + + + From 87f64afa940cb2706589058daac90b3a135607c6 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 27 Feb 2019 11:45:57 +0100 Subject: [PATCH 198/507] Fix compiling with Sacado and CUDA --- include/deal.II/base/numbers.h | 52 +++++++++++++++++-- .../differentiation/ad/sacado_number_types.h | 11 ++++ source/base/tensor.cc | 1 + 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/include/deal.II/base/numbers.h b/include/deal.II/base/numbers.h index 68bf74bef411..fca6430fd267 100644 --- a/include/deal.II/base/numbers.h +++ b/include/deal.II/base/numbers.h @@ -165,6 +165,15 @@ namespace numbers */ static const double SQRT1_2 = 0.70710678118654752440; + /** + * Check whether the given type can be used in CUDA device code. + * If not, DEAL_II_CUDA_HOST_DEV needs to be disabled for functions + * that use this type. + */ + template + struct is_cuda_compatible : std::true_type + {}; + /** * Check whether a value is not a number. * @@ -361,10 +370,21 @@ namespace numbers * general template is chosen for types not equal to std::complex, this * function simply returns the square of the given number. * - * @note This function can also be used in CUDA device code. + * @note If the template type can be used in CUDA device code, the same holds true + * for this function. */ - static DEAL_II_CUDA_HOST_DEV real_type - abs_square(const number &x); + template + static DEAL_II_CUDA_HOST_DEV + typename std::enable_if::value && + is_cuda_compatible::value, + real_type>::type + abs_square(const number &x); + + template + static typename std::enable_if::value && + !is_cuda_compatible::value, + real_type>::type + abs_square(const number &x); /** * Return the absolute value of a number. @@ -423,12 +443,20 @@ namespace numbers // --------------- inline and template functions ---------------- // + template + struct is_cuda_compatible, void> : std::false_type + {}; + + + inline bool is_nan(const double x) { return std::isnan(x); } + + inline bool is_finite(const double x) { @@ -475,7 +503,23 @@ namespace numbers template - DEAL_II_CUDA_HOST_DEV typename NumberTraits::real_type + template + DEAL_II_CUDA_HOST_DEV + typename std::enable_if::value && + is_cuda_compatible::value, + typename NumberTraits::real_type>::type + NumberTraits::abs_square(const number &x) + { + return x * x; + } + + + + template + template + typename std::enable_if::value && + !is_cuda_compatible::value, + typename NumberTraits::real_type>::type NumberTraits::abs_square(const number &x) { return x * x; diff --git a/include/deal.II/differentiation/ad/sacado_number_types.h b/include/deal.II/differentiation/ad/sacado_number_types.h index 8781865c5f40..907e830e1f01 100644 --- a/include/deal.II/differentiation/ad/sacado_number_types.h +++ b/include/deal.II/differentiation/ad/sacado_number_types.h @@ -926,6 +926,17 @@ namespace Differentiation } // namespace AD } // namespace Differentiation + +namespace numbers +{ + template + struct is_cuda_compatible< + NumberType, + typename std::enable_if::value>::type> : std::false_type + {}; +} // namespace numbers + # endif // DOXYGEN diff --git a/source/base/tensor.cc b/source/base/tensor.cc index 15cb6f3b5dfe..43dabdad75c1 100644 --- a/source/base/tensor.cc +++ b/source/base/tensor.cc @@ -19,6 +19,7 @@ #include #include +#include #include DEAL_II_NAMESPACE_OPEN From 6f384148dff2b9b2f4dbae1408793821f6d00ea1 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 27 Feb 2019 23:54:21 +0100 Subject: [PATCH 199/507] Move specialization --- include/deal.II/base/numbers.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/deal.II/base/numbers.h b/include/deal.II/base/numbers.h index fca6430fd267..60396a2af539 100644 --- a/include/deal.II/base/numbers.h +++ b/include/deal.II/base/numbers.h @@ -174,6 +174,13 @@ namespace numbers struct is_cuda_compatible : std::true_type {}; + /** + * std::complex cannot be used in CUDA device code. + */ + template + struct is_cuda_compatible, void> : std::false_type + {}; + /** * Check whether a value is not a number. * @@ -443,12 +450,6 @@ namespace numbers // --------------- inline and template functions ---------------- // - template - struct is_cuda_compatible, void> : std::false_type - {}; - - - inline bool is_nan(const double x) { From cba82d94d72867fab082b8a755f8950579c5c174 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 28 Feb 2019 02:12:22 +0100 Subject: [PATCH 200/507] Detect CUDA compute capability --- .../cuda_compute_capability.cu | 30 ++++++++++++++++ cmake/configure/configure_1_cuda.cmake | 34 +++++++++++++++++++ doc/external-libs/cuda.html | 4 +-- 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 cmake/configure/CUDAComputeCapability/cuda_compute_capability.cu 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..9001a9416586 100644 --- a/cmake/configure/configure_1_cuda.cmake +++ b/cmake/configure/configure_1_cuda.cmake @@ -85,6 +85,40 @@ 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." + ) + SET(${var} FALSE) + ENDIF() ELSE() # # Assume a cuda compute capability of 35 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"
    
    From 86732c59c78c476084642ab6686e7d0c4931de43 Mon Sep 17 00:00:00 2001
    From: Lei Qiao 
    Date: Thu, 28 Feb 2019 16:55:20 +0800
    Subject: [PATCH 201/507] minor fix on documentation to enum
     Triangulation::MeshSmoothing
    
    ---
     include/deal.II/grid/tria.h | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/include/deal.II/grid/tria.h b/include/deal.II/grid/tria.h
    index 45e90441ff56..70e06728e490 100644
    --- a/include/deal.II/grid/tria.h
    +++ b/include/deal.II/grid/tria.h
    @@ -1327,7 +1327,7 @@ class Triangulation : public Subscriptor
          *
          * If the smoothing indicator given to the constructor contains the bit
          * for #limit_level_difference_at_vertices, situations as the above one
    -     * are eliminated by also marking the lower left cell for refinement.
    +     * are eliminated by also marking the upper right cell for refinement.
          *
          * In case of anisotropic refinement, the level of a cell is not linked to
          * the refinement of a cell as directly as in case of isotropic
    
    From f9b59e0792b7fa73c93341712e3033156c57b458 Mon Sep 17 00:00:00 2001
    From: Marc Fehling 
    Date: Thu, 28 Feb 2019 13:24:55 +0100
    Subject: [PATCH 202/507] Complete signals for distributed_save|load.
    
    ---
     include/deal.II/grid/tria.h | 15 +++++++++++++++
     source/distributed/tria.cc  |  5 +++++
     2 files changed, 20 insertions(+)
    
    diff --git a/include/deal.II/grid/tria.h b/include/deal.II/grid/tria.h
    index 45e90441ff56..b47941a4ea0d 100644
    --- a/include/deal.II/grid/tria.h
    +++ b/include/deal.II/grid/tria.h
    @@ -2335,6 +2335,21 @@ class Triangulation : public Subscriptor
          */
         boost::signals2::signal pre_distributed_save;
     
    +    /**
    +     * This signal is triggered at the end of execution of the
    +     * parallel::distributed::Triangulation::save()
    +     * function when the triangulation has reached its final state.
    +     */
    +    boost::signals2::signal post_distributed_save;
    +
    +    /**
    +     * This signal is triggered at the beginning of execution of the
    +     * parallel::distributed::Triangulation::load()
    +     * function. At the time this signal is triggered, the triangulation
    +     * is still unchanged.
    +     */
    +    boost::signals2::signal pre_distributed_load;
    +
         /**
          * This signal is triggered at the end of execution of the
          * parallel::distributed::Triangulation::load()
    diff --git a/source/distributed/tria.cc b/source/distributed/tria.cc
    index 5fe3afb1c834..9da8894cd146 100644
    --- a/source/distributed/tria.cc
    +++ b/source/distributed/tria.cc
    @@ -2753,6 +2753,9 @@ namespace parallel
             tria->cell_attached_data.pack_callbacks_fixed.clear();
             tria->cell_attached_data.pack_callbacks_variable.clear();
           }
    +
    +      // signal that serialization has finished
    +      this->signals.post_distributed_save();
         }
     
     
    @@ -2771,6 +2774,8 @@ namespace parallel
             ExcMessage(
               "Triangulation may only contain coarse cells when calling load()."));
     
    +      // signal that de-serialization is going to happen
    +      this->signals.pre_distributed_load();
     
           if (parallel_ghost != nullptr)
             {
    
    From 81a482d591b55add052681b5503aadd326a6fd94 Mon Sep 17 00:00:00 2001
    From: Marc Fehling 
    Date: Thu, 28 Feb 2019 13:25:13 +0100
    Subject: [PATCH 203/507] hp::DoFHandler: Moved containers with temporary
     content into a dedicated structure.
    
    ---
     include/deal.II/hp/dof_handler.h |  79 ++++++++----
     source/hp/dof_handler.cc         | 204 +++++++++++++++++++++----------
     2 files changed, 195 insertions(+), 88 deletions(-)
    
    diff --git a/include/deal.II/hp/dof_handler.h b/include/deal.II/hp/dof_handler.h
    index 29a3746ec89a..fca0cac75579 100644
    --- a/include/deal.II/hp/dof_handler.h
    +++ b/include/deal.II/hp/dof_handler.h
    @@ -1155,6 +1155,17 @@ namespace hp
         void
         post_distributed_active_fe_index_transfer();
     
    +    /**
    +     * A function that will be triggered through a triangulation
    +     * signal just after the associated parallel::distributed::Triangulation has
    +     * been saved.
    +     *
    +     * The function frees all memory related to the transfer of
    +     * active_fe_indices.
    +     */
    +    void
    +    post_distributed_serialization_of_active_fe_indices();
    +
         /**
          * Space to store the DoF numbers for the different levels. Analogous to
          * the levels[] tree of the Triangulation objects.
    @@ -1213,33 +1224,49 @@ namespace hp
         std::vector vertex_dof_offsets;
     
         /**
    -     * Container to temporarily store the iterator and active FE index of
    -     * cells that will be refined.
    -     */
    -    std::map refined_cells_fe_index;
    -
    -    /**
    -     * Container to temporarily store the iterator and active FE index of
    -     * parent cells that will remain after coarsening.
    -     */
    -    std::map coarsened_cells_fe_index;
    -
    -    /**
    -     * Container to temporarily store the active_fe_index of every locally
    -     * owned cell for transfer across parallel::distributed::Triangulation
    -     * objects.
    +     * Whenever the underlying triangulation changes by either
    +     * refinement/coarsening and serialization, the active_fe_index of cells
    +     * needs to be transferred. This structure stores all temporary information
    +     * required during that process.
          */
    -    std::vector active_fe_indices;
    -
    -    /**
    -     * Helper object to transfer all active_fe_indices on
    -     * parallel::distributed::Triangulation objects during refinement/coarsening
    -     * and serialization.
    -     */
    -    std::unique_ptr<
    -      parallel::distributed::
    -        CellDataTransfer>>
    -      cell_data_transfer;
    +    struct ActiveFEIndexTransfer
    +    {
    +      /**
    +       * Container to temporarily store the iterator and active FE index of
    +       * cells that will be refined.
    +       */
    +      std::map refined_cells_fe_index;
    +
    +      /**
    +       * Container to temporarily store the iterator and active FE index of
    +       * parent cells that will remain after coarsening.
    +       */
    +      std::map
    +        coarsened_cells_fe_index;
    +
    +      /**
    +       * Container to temporarily store the active_fe_index of every locally
    +       * owned cell for transfer across parallel::distributed::Triangulation
    +       * objects.
    +       */
    +      std::vector active_fe_indices;
    +
    +      /**
    +       * Helper object to transfer all active_fe_indices on
    +       * parallel::distributed::Triangulation objects during
    +       * refinement/coarsening and serialization.
    +       */
    +      std::unique_ptr<
    +        parallel::distributed::
    +          CellDataTransfer>>
    +        cell_data_transfer;
    +    };
    +
    +    /**
    +     * We embed our data structure into a pointer to control that
    +     * all transfer related data only exists during the actual transfer process.
    +     */
    +    std::unique_ptr active_fe_index_transfer;
     
         /**
          * A list of connections with which this object connects to the
    diff --git a/source/hp/dof_handler.cc b/source/hp/dof_handler.cc
    index 01900459d885..ad53874b5bd5 100644
    --- a/source/hp/dof_handler.cc
    +++ b/source/hp/dof_handler.cc
    @@ -1523,38 +1523,29 @@ namespace hp
         // decide whether we need a sequential or a parallel shared/distributed
         // policy and attach corresponding callback functions dealing with the
         // transfer of active_fe_indices
    -    if (const auto *distributed_tria = dynamic_cast<
    -          const parallel::distributed::Triangulation *>(
    -          &this->get_triangulation()))
    +    if (dynamic_cast
    +                       *>(&this->get_triangulation()))
           {
             policy = std_cxx14::make_unique<
               internal::DoFHandlerImplementation::Policy::ParallelDistributed<
                 DoFHandler>>(*this);
     
    -#ifdef DEAL_II_WITH_P4EST
    -        cell_data_transfer = std_cxx14::make_unique<
    -          parallel::distributed::
    -            CellDataTransfer>>(
    -          *distributed_tria,
    -          /*transfer_variable_size_data=*/false,
    -          ¶llel::distributed::CellDataTransfer<
    -            dim,
    -            spacedim,
    -            std::vector>::CoarseningStrategies::check_equality);
    -#endif
    -
             tria_listeners.push_back(
    -          distributed_tria->signals.pre_distributed_refinement.connect(
    -            std::bind(
    -              &DoFHandler::pre_distributed_active_fe_index_transfer,
    -              std::ref(*this))));
    +          this->tria->signals.pre_distributed_refinement.connect(std::bind(
    +            &DoFHandler::pre_distributed_active_fe_index_transfer,
    +            std::ref(*this))));
             tria_listeners.push_back(
    -          distributed_tria->signals.post_distributed_refinement.connect(
    -            std::bind(
    -              &DoFHandler::post_distributed_active_fe_index_transfer,
    -              std::ref(*this))));
    +          this->tria->signals.post_distributed_refinement.connect(std::bind(
    +            &DoFHandler::post_distributed_active_fe_index_transfer,
    +            std::ref(*this))));
    +
    +        tria_listeners.push_back(
    +          this->tria->signals.post_distributed_save.connect(
    +            std::bind(&DoFHandler::
    +                        post_distributed_serialization_of_active_fe_indices,
    +                      std::ref(*this))));
           }
         else if (dynamic_cast
                                 *>(&this->get_triangulation()) != nullptr)
    @@ -1791,8 +1782,10 @@ namespace hp
         // distribute_dofs() first to make this functionality available.
         if (fe_collection.size() > 0)
           {
    -        Assert(refined_cells_fe_index.empty(), ExcInternalError());
    -        Assert(coarsened_cells_fe_index.empty(), ExcInternalError());
    +        Assert(active_fe_index_transfer == nullptr, ExcInternalError());
    +
    +        active_fe_index_transfer =
    +          std_cxx14::make_unique();
     
             // Store active_fe_index information for all cells that will be
             // affected by refinement/coarsening.
    @@ -1803,7 +1796,7 @@ namespace hp
                     {
                       // Store the active_fe_index of each cell that will be refined
                       // to and distribute it later on its children.
    -                  refined_cells_fe_index.insert(
    +                  active_fe_index_transfer->refined_cells_fe_index.insert(
                         {cell, cell->active_fe_index()});
                     }
                   else if (cell->coarsen_flag_set())
    @@ -1816,8 +1809,9 @@ namespace hp
                       const auto &parent = cell->parent();
                       // Check if the active_fe_index for the current cell has been
                       // determined already.
    -                  if (coarsened_cells_fe_index.find(parent) ==
    -                      coarsened_cells_fe_index.end())
    +                  if (active_fe_index_transfer->coarsened_cells_fe_index.find(
    +                        parent) ==
    +                      active_fe_index_transfer->coarsened_cells_fe_index.end())
                         {
                           std::set fe_indices_children;
                           for (unsigned int child_index = 0;
    @@ -1842,7 +1836,8 @@ namespace hp
                               "that dominates all children of a cell you are trying "
                               "to coarsen!"));
     
    -                      coarsened_cells_fe_index.insert({parent, fe_index});
    +                      active_fe_index_transfer->coarsened_cells_fe_index.insert(
    +                        {parent, fe_index});
                         }
                     }
                 }
    @@ -1862,6 +1857,8 @@ namespace hp
         // distribute_dofs() first to make this functionality available.
         if (fe_collection.size() > 0)
           {
    +        Assert(active_fe_index_transfer == nullptr, ExcInternalError());
    +
             // If the underlying shared::Tria allows artificial cells,
             // then save the current set of subdomain ids, and set
             // subdomain ids to the "true" owner of each cell. We later
    @@ -1922,6 +1919,8 @@ namespace hp
         // distribute_dofs() first to make this functionality available.
         if (fe_collection.size() > 0)
           {
    +        Assert(active_fe_index_transfer == nullptr, ExcInternalError());
    +
             // First, do what we would do in the sequential case.
             pre_active_fe_index_transfer();
     
    @@ -1932,24 +1931,37 @@ namespace hp
             // the active_fe_indices on the new mesh.
     
             // Gather all current active_fe_indices.
    -        get_active_fe_indices(active_fe_indices);
    +        get_active_fe_indices(active_fe_index_transfer->active_fe_indices);
     
             // Overwrite values of cells that will be coarsened with the
             // active_fe_index determined beforehand for their parent.
    -        for (const auto &pair : coarsened_cells_fe_index)
    +        for (const auto &pair :
    +             active_fe_index_transfer->coarsened_cells_fe_index)
               for (unsigned int child_index = 0;
                    child_index < pair.first->n_children();
                    ++child_index)
    -            active_fe_indices[pair.first->child(child_index)
    -                                ->active_cell_index()] = pair.second;
    +            active_fe_index_transfer
    +              ->active_fe_indices[pair.first->child(child_index)
    +                                    ->active_cell_index()] = pair.second;
     
    -        // Attach to transfer object.
    -        cell_data_transfer->prepare_for_coarsening_and_refinement(
    -          active_fe_indices);
    +        // Create transfer object and attach to it.
    +        const auto *distributed_tria = dynamic_cast<
    +          const parallel::distributed::Triangulation *>(
    +          &this->get_triangulation());
    +
    +        active_fe_index_transfer->cell_data_transfer = std_cxx14::make_unique<
    +          parallel::distributed::
    +            CellDataTransfer>>(
    +          *distributed_tria,
    +          /*transfer_variable_size_data=*/false,
    +          ¶llel::distributed::CellDataTransfer<
    +            dim,
    +            spacedim,
    +            std::vector>::CoarseningStrategies::check_equality);
     
    -        // Free some memory.
    -        refined_cells_fe_index.clear();
    -        coarsened_cells_fe_index.clear();
    +        active_fe_index_transfer->cell_data_transfer
    +          ->prepare_for_coarsening_and_refinement(
    +            active_fe_index_transfer->active_fe_indices);
           }
     #endif
       }
    @@ -1964,6 +1976,8 @@ namespace hp
         // distribute_dofs() first to make this functionality available.
         if (fe_collection.size() > 0)
           {
    +        Assert(active_fe_index_transfer != nullptr, ExcInternalError());
    +
             // For Triangulation and p::s::Triangulation, the old cell iterators
             // are still valid. There is no need to transfer data in this case,
             // and we can re-use our previously gathered information from the
    @@ -1971,7 +1985,8 @@ namespace hp
     
             // Distribute active_fe_indices from all refined cells on their
             // respective children.
    -        for (const auto &pair : refined_cells_fe_index)
    +        for (const auto &pair :
    +             active_fe_index_transfer->refined_cells_fe_index)
               {
                 const cell_iterator &parent = pair.first;
     
    @@ -1991,7 +2006,8 @@ namespace hp
     
             // Set active_fe_indices on coarsened cells that have been determined
             // before the actual coarsening happened.
    -        for (const auto &pair : coarsened_cells_fe_index)
    +        for (const auto &pair :
    +             active_fe_index_transfer->coarsened_cells_fe_index)
               {
                 const cell_iterator &cell = pair.first;
     
    @@ -2002,9 +2018,8 @@ namespace hp
                   }
               }
     
    -        // Clear stored active_fe_indices.
    -        refined_cells_fe_index.clear();
    -        coarsened_cells_fe_index.clear();
    +        // Free memory.
    +        active_fe_index_transfer.reset();
           }
       }
     
    @@ -2021,6 +2036,8 @@ namespace hp
         // distribute_dofs() first to make this functionality available.
         if (fe_collection.size() > 0)
           {
    +        Assert(active_fe_index_transfer != nullptr, ExcInternalError());
    +
             // Do what we normally do in the sequential case.
             post_active_fe_index_transfer();
     
    @@ -2046,17 +2063,19 @@ namespace hp
         // distribute_dofs() first to make this functionality available.
         if (fe_collection.size() > 0)
           {
    +        Assert(active_fe_index_transfer != nullptr, ExcInternalError());
    +
             // Unpack active_fe_indices.
    -        active_fe_indices.resize(tria->n_active_cells(),
    -                                 numbers::invalid_unsigned_int);
    -        cell_data_transfer->unpack(active_fe_indices);
    +        active_fe_index_transfer->active_fe_indices.resize(
    +          tria->n_active_cells(), numbers::invalid_unsigned_int);
    +        active_fe_index_transfer->cell_data_transfer->unpack(
    +          active_fe_index_transfer->active_fe_indices);
     
             // Update all locally owned active_fe_indices.
    -        set_active_fe_indices(active_fe_indices);
    +        set_active_fe_indices(active_fe_index_transfer->active_fe_indices);
     
    -        // Free some memory.
    -        active_fe_indices.clear();
    -        active_fe_indices.shrink_to_fit();
    +        // Free memory.
    +        active_fe_index_transfer.reset();
           }
     #endif
       }
    @@ -2084,19 +2103,60 @@ namespace hp
         // distribute_dofs() first to make this functionality available.
         if (fe_collection.size() > 0)
           {
    +        Assert(active_fe_index_transfer == nullptr, ExcInternalError());
    +
    +        active_fe_index_transfer =
    +          std_cxx14::make_unique();
    +
    +        // Create transfer object and attach to it.
    +        const auto *distributed_tria = dynamic_cast<
    +          const parallel::distributed::Triangulation *>(
    +          &this->get_triangulation());
    +
    +        active_fe_index_transfer->cell_data_transfer = std_cxx14::make_unique<
    +          parallel::distributed::
    +            CellDataTransfer>>(
    +          *distributed_tria,
    +          /*transfer_variable_size_data=*/false,
    +          ¶llel::distributed::CellDataTransfer<
    +            dim,
    +            spacedim,
    +            std::vector>::CoarseningStrategies::check_equality);
    +
             // If we work on a p::d::Triangulation, we have to transfer all
             // active fe indices since ownership of cells may change.
     
             // Gather all current active_fe_indices
    -        get_active_fe_indices(active_fe_indices);
    +        get_active_fe_indices(active_fe_index_transfer->active_fe_indices);
     
             // Attach to transfer object
    -        cell_data_transfer->prepare_for_serialization(active_fe_indices);
    +        active_fe_index_transfer->cell_data_transfer->prepare_for_serialization(
    +          active_fe_index_transfer->active_fe_indices);
           }
     #endif
       }
     
     
    +  template 
    +  void
    +  DoFHandler::post_distributed_serialization_of_active_fe_indices()
    +  {
    +#ifndef DEAL_II_WITH_P4EST
    +    Assert(false,
    +           ExcMessage(
    +             "You are attempting to use a functionality that is only available "
    +             "if deal.II was configured to use p4est, but cmake did not find a "
    +             "valid p4est library."));
    +#else
    +    Assert(active_fe_index_transfer != nullptr, ExcInternalError());
    +
    +    // Free memory.
    +    active_fe_index_transfer.reset();
    +#endif
    +  }
    +
    +
     
       template 
       void
    @@ -2119,17 +2179,37 @@ namespace hp
         // distribute_dofs() first to make this functionality available.
         if (fe_collection.size() > 0)
           {
    +        Assert(active_fe_index_transfer == nullptr, ExcInternalError());
    +
    +        active_fe_index_transfer =
    +          std_cxx14::make_unique();
    +
    +        // Create transfer object and attach to it.
    +        const auto *distributed_tria = dynamic_cast<
    +          const parallel::distributed::Triangulation *>(
    +          &this->get_triangulation());
    +
    +        active_fe_index_transfer->cell_data_transfer = std_cxx14::make_unique<
    +          parallel::distributed::
    +            CellDataTransfer>>(
    +          *distributed_tria,
    +          /*transfer_variable_size_data=*/false,
    +          ¶llel::distributed::CellDataTransfer<
    +            dim,
    +            spacedim,
    +            std::vector>::CoarseningStrategies::check_equality);
    +
             // Unpack active_fe_indices.
    -        active_fe_indices.resize(tria->n_active_cells(),
    -                                 numbers::invalid_unsigned_int);
    -        cell_data_transfer->deserialize(active_fe_indices);
    +        active_fe_index_transfer->active_fe_indices.resize(
    +          tria->n_active_cells(), numbers::invalid_unsigned_int);
    +        active_fe_index_transfer->cell_data_transfer->deserialize(
    +          active_fe_index_transfer->active_fe_indices);
     
             // Update all locally owned active_fe_indices.
    -        set_active_fe_indices(active_fe_indices);
    +        set_active_fe_indices(active_fe_index_transfer->active_fe_indices);
     
    -        // Free some memory.
    -        active_fe_indices.clear();
    -        active_fe_indices.shrink_to_fit();
    +        // Free memory.
    +        active_fe_index_transfer.reset();
           }
     #endif
       }
    
    From 052b9b1b3cbd27520a63daf7b085b2bd84fecc2a Mon Sep 17 00:00:00 2001
    From: Marc Fehling 
    Date: Sun, 3 Feb 2019 01:24:43 +0100
    Subject: [PATCH 204/507] Added 'set_fe' functionality to DoFHandlers.
    
    ---
     doc/news/changes/minor/20190210MarcFehling    |  6 ++
     .../deal.II/distributed/solution_transfer.h   |  2 +-
     include/deal.II/dofs/dof_handler.h            | 32 ++++++---
     include/deal.II/hp/dof_handler.h              | 13 ++++
     source/dofs/dof_handler.cc                    | 18 +++--
     source/hp/dof_handler.cc                      | 71 +++++++++----------
     tests/mpi/hp_active_fe_indices_transfer_01.cc |  3 +-
     tests/mpi/hp_active_fe_indices_transfer_02.cc |  8 +--
     tests/mpi/hp_cell_weights_01.cc               | 11 ++-
     tests/mpi/hp_cell_weights_02.cc               | 11 ++-
     tests/mpi/hp_cell_weights_03.cc               | 11 ++-
     tests/mpi/p4est_save_06.cc                    |  2 +-
     12 files changed, 107 insertions(+), 81 deletions(-)
     create mode 100644 doc/news/changes/minor/20190210MarcFehling
    
    diff --git a/doc/news/changes/minor/20190210MarcFehling b/doc/news/changes/minor/20190210MarcFehling
    new file mode 100644
    index 000000000000..9a3e1e9f4751
    --- /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.
    +
    +(2019/02/10, Marc Fehling) diff --git a/include/deal.II/distributed/solution_transfer.h b/include/deal.II/distributed/solution_transfer.h index 558ebeed2966..9d61878b2770 100644 --- a/include/deal.II/distributed/solution_transfer.h +++ b/include/deal.II/distributed/solution_transfer.h @@ -203,7 +203,7 @@ namespace parallel * hp::DoFHandler hp_dof_handler(triangulation); * // We need to introduce our dof_handler to the fe_collection * // before setting all active_fe_indices. - * hp_dof_handler.distribute_dofs(fe_collection); + * hp_dof_handler.set_fe(fe_collection); * hp_dof_handler.deserialize_active_fe_indices(); * hp_dof_handler.distribute_dofs(fe_collection); * diff --git a/include/deal.II/dofs/dof_handler.h b/include/deal.II/dofs/dof_handler.h index 638e98b535ee..1da5931739ac 100644 --- a/include/deal.II/dofs/dof_handler.h +++ b/include/deal.II/dofs/dof_handler.h @@ -472,6 +472,25 @@ class DoFHandler : public Subscriptor initialize(const Triangulation &tria, const FiniteElement &fe); + /** + * Assign a FiniteElement @p fe to this object. + * + * @note This function makes a copy of the finite element given as + * argument, and stores it as a member variable. Consequently, it is + * possible to write code such as + * @code + * dof_handler.set_fe(FE_Q(2)); + * @endcode + * You can then access the finite element later on by calling + * DoFHandler::get_fe(). However, it is often more convenient to + * keep a named finite element object as a member variable in your + * main class and refer to it directly whenever you need to access + * properties of the finite element (such as + * FiniteElementData::dofs_per_cell). This is what all tutorial programs do. + */ + virtual void + set_fe(const FiniteElement &fe); + /** * Go through the triangulation and "distribute" the degrees of * freedom needed for the given finite element. "Distributing" @@ -498,17 +517,8 @@ class DoFHandler : public Subscriptor * step-2 tutorial program. * * @note This function makes a copy of the finite element given as - * argument, and stores it as a member variable. Consequently, it is - * possible to write code such as - * @code - * dof_handler.distribute_dofs (FE_Q(2)); - * @endcode - * You can then access the finite element later on by calling - * DoFHandler::get_fe(). However, it is often more convenient to - * keep a named finite element object as a member variable in your - * main class and refer to it directly whenever you need to access - * properties of the finite element (such as FiniteElement::dofs_per_cell). - * This is what all tutorial programs do. + * argument, and stores it as a member variable, similarly to the above + * function set_fe(). */ virtual void distribute_dofs(const FiniteElement &fe); diff --git a/include/deal.II/hp/dof_handler.h b/include/deal.II/hp/dof_handler.h index 29a3746ec89a..3b73789941c6 100644 --- a/include/deal.II/hp/dof_handler.h +++ b/include/deal.II/hp/dof_handler.h @@ -417,6 +417,19 @@ namespace hp initialize(const Triangulation & tria, const hp::FECollection &fe); + /** + * Assign a hp::FECollection @p fe to this object. + * + * In case a parallel::Triangulation is assigned to this object, + * the active_fe_indices will be exchanged between processors so that + * each one knows the indices on its own cells and all ghost cells. + * + * @note In accordance with dealii::DoFHandler::set_fe(), + * this function also makes a copy of the object given as argument. + */ + virtual void + set_fe(const hp::FECollection &fe); + /** * Go through the triangulation and "distribute" the degrees of * freedom needed for the given finite element. "Distributing" diff --git a/source/dofs/dof_handler.cc b/source/dofs/dof_handler.cc index 03603ee5a05e..f5b0a0fd2064 100644 --- a/source/dofs/dof_handler.cc +++ b/source/dofs/dof_handler.cc @@ -1197,6 +1197,18 @@ DoFHandler::memory_consumption() const +template +void +DoFHandler::set_fe(const FiniteElement &ff) +{ + // Only recreate the FECollection if we don't already store + // the exact same FiniteElement object. + if (fe_collection.size() == 0 || fe_collection[0] != ff) + fe_collection = hp::FECollection(ff); +} + + + template void DoFHandler::distribute_dofs( @@ -1210,10 +1222,8 @@ DoFHandler::distribute_dofs( Assert(tria->n_levels() > 0, ExcMessage("The Triangulation you are using is empty!")); - // Only recreate the FECollection if we don't already store - // the exact same FiniteElement object. - if (fe_collection.size() == 0 || fe_collection[0] != ff) - fe_collection = hp::FECollection(ff); + // first, assign the finite_element + set_fe(ff); // delete all levels and set them // up newly. note that we still diff --git a/source/hp/dof_handler.cc b/source/hp/dof_handler.cc index 01900459d885..35e4a1766649 100644 --- a/source/hp/dof_handler.cc +++ b/source/hp/dof_handler.cc @@ -1390,6 +1390,33 @@ namespace hp + template + void + DoFHandler::set_fe(const hp::FECollection &ff) + { + // don't create a new object if the one we have is already appropriate + if (fe_collection != ff) + fe_collection = hp::FECollection(ff); + + // ensure that the active_fe_indices vectors are initialized correctly + create_active_fe_table(); + + // make sure every processor knows the active_fe_indices + // on both its own cells and all ghost cells + dealii::internal::hp::DoFHandlerImplementation::Implementation:: + communicate_active_fe_indices(*this); + + // make sure that the fe collection is large enough to + // cover all fe indices presently in use on the mesh + for (const auto &cell : active_cell_iterators()) + if (cell->is_locally_owned()) + Assert(cell->active_fe_index() < fe_collection.size(), + ExcInvalidFEIndex(cell->active_fe_index(), + fe_collection.size())); + } + + + template void DoFHandler::distribute_dofs( @@ -1404,14 +1431,8 @@ namespace hp ExcMessage("The Triangulation you are using is empty!")); Assert(ff.size() > 0, ExcMessage("The hp::FECollection given is empty!")); - // don't create a new object if the one we have is already appropriate - if (fe_collection != ff) - fe_collection = hp::FECollection(ff); - - // at the beginning, make sure every processor knows the - // active_fe_indices on both its own cells and all ghost cells - dealii::internal::hp::DoFHandlerImplementation::Implementation:: - communicate_active_fe_indices(*this); + // first, assign the fe_collection + set_fe(ff); // If an underlying shared::Tria allows artificial cells, // then save the current set of subdomain ids, and set @@ -1425,51 +1446,29 @@ namespace hp { saved_subdomain_ids.resize(shared_tria->n_active_cells()); - typename parallel::shared::Triangulation:: - active_cell_iterator cell = get_triangulation().begin_active(), - endc = get_triangulation().end(); - const std::vector &true_subdomain_ids = shared_tria->get_true_subdomain_ids_of_cells(); - for (unsigned int index = 0; cell != endc; ++cell, ++index) + for (const auto &cell : shared_tria->active_cell_iterators()) { + const unsigned int index = cell->active_cell_index(); saved_subdomain_ids[index] = cell->subdomain_id(); cell->set_subdomain_id(true_subdomain_ids[index]); } } - // ensure that the active_fe_indices vectors are - // initialized correctly. - create_active_fe_table(); - - // up front make sure that the fe collection is large enough to - // cover all fe indices presently in use on the mesh - for (active_cell_iterator cell = begin_active(); cell != end(); ++cell) - if (cell->is_locally_owned()) - Assert(cell->active_fe_index() < fe_collection.size(), - ExcInvalidFEIndex(cell->active_fe_index(), - fe_collection.size())); - - - // then allocate space for all the other tables + // then allocate space for all tables dealii::internal::hp::DoFHandlerImplementation::Implementation:: reserve_space(*this); - // now undo the subdomain modification if (const parallel::shared::Triangulation *shared_tria = (dynamic_cast *>( &get_triangulation()))) if (shared_tria->with_artificial_cells()) - { - typename parallel::shared::Triangulation:: - active_cell_iterator cell = get_triangulation().begin_active(), - endc = get_triangulation().end(); - - for (unsigned int index = 0; cell != endc; ++cell, ++index) - cell->set_subdomain_id(saved_subdomain_ids[index]); - } + for (const auto &cell : shared_tria->active_cell_iterators()) + cell->set_subdomain_id( + saved_subdomain_ids[cell->active_cell_index()]); // Clear user flags because we will need them. But first we save diff --git a/tests/mpi/hp_active_fe_indices_transfer_01.cc b/tests/mpi/hp_active_fe_indices_transfer_01.cc index 2d5cb00ab231..5fd0cc5108dc 100644 --- a/tests/mpi/hp_active_fe_indices_transfer_01.cc +++ b/tests/mpi/hp_active_fe_indices_transfer_01.cc @@ -50,9 +50,8 @@ test() for (unsigned int i = 0; i < max_degree; ++i) fe_collection.push_back(FE_Q(max_degree - i)); - // this distribute_dofs() call is necessary // we need to introduce dof_handler to its fe_collection first - dh.distribute_dofs(fe_collection); + dh.set_fe(fe_collection); unsigned int i = 0; for (auto &cell : dh.active_cell_iterators()) diff --git a/tests/mpi/hp_active_fe_indices_transfer_02.cc b/tests/mpi/hp_active_fe_indices_transfer_02.cc index 65393457401e..e40dc29a2b67 100644 --- a/tests/mpi/hp_active_fe_indices_transfer_02.cc +++ b/tests/mpi/hp_active_fe_indices_transfer_02.cc @@ -48,10 +48,9 @@ test() GridGenerator::subdivided_hyper_cube(tria, 2); tria.refine_global(1); - // this distribute_dofs() call is necessary - // we need to introduce dof_handler to its fe_collection first hp::DoFHandler dh(tria); - dh.distribute_dofs(fe_collection); + // we need to introduce dof_handler to its fe_collection first + dh.set_fe(fe_collection); unsigned int i = 0; for (auto &cell : dh.active_cell_iterators()) @@ -85,10 +84,9 @@ test() GridGenerator::subdivided_hyper_cube(tria, 2); // triangulation has to be initialized with correct coarse cells - // this distribute_dofs() call is necessary // we need to introduce dof_handler to its fe_collection first hp::DoFHandler dh(tria); - dh.distribute_dofs(fe_collection); + dh.set_fe(fe_collection); // ----- transfer ----- tria.load("file"); diff --git a/tests/mpi/hp_cell_weights_01.cc b/tests/mpi/hp_cell_weights_01.cc index 6d15d5841b32..6edf11841294 100644 --- a/tests/mpi/hp_cell_weights_01.cc +++ b/tests/mpi/hp_cell_weights_01.cc @@ -57,17 +57,12 @@ test() fe_collection.push_back(FE_Q(5)); hp::DoFHandler dh(tria); + dh.set_fe(fe_collection); // default: active_fe_index = 0 for (auto &cell : dh.active_cell_iterators()) if (cell->is_locally_owned()) if (cell->id().to_string() == "0_2:00") cell->set_active_fe_index(1); - dh.distribute_dofs(fe_collection); - - - parallel::CellWeights cell_weights(dh); - cell_weights.register_ndofs_weighting(100000); - deallog << "Number of cells before repartitioning: " << tria.n_locally_owned_active_cells() << std::endl; @@ -80,8 +75,10 @@ test() } + parallel::CellWeights cell_weights(dh); + cell_weights.register_ndofs_weighting(100000); + tria.repartition(); - dh.distribute_dofs(fe_collection); deallog << "Number of cells after repartitioning: " diff --git a/tests/mpi/hp_cell_weights_02.cc b/tests/mpi/hp_cell_weights_02.cc index 5d13dff77469..e116925d70de 100644 --- a/tests/mpi/hp_cell_weights_02.cc +++ b/tests/mpi/hp_cell_weights_02.cc @@ -63,17 +63,12 @@ test() fe_collection.push_back(FE_Q(7)); hp::DoFHandler dh(tria); + dh.set_fe(fe_collection); // default: active_fe_index = 0 for (auto &cell : dh.active_cell_iterators()) if (cell->is_locally_owned()) if (cell->id().to_string() == "0_3:000") cell->set_active_fe_index(1); - dh.distribute_dofs(fe_collection); - - - parallel::CellWeights cell_weights(dh); - cell_weights.register_ndofs_weighting(100000); - deallog << "Number of cells before repartitioning: " << tria.n_locally_owned_active_cells() << std::endl; @@ -86,8 +81,10 @@ test() } + parallel::CellWeights cell_weights(dh); + cell_weights.register_ndofs_weighting(100000); + tria.repartition(); - dh.distribute_dofs(fe_collection); deallog << "Number of cells after repartitioning: " diff --git a/tests/mpi/hp_cell_weights_03.cc b/tests/mpi/hp_cell_weights_03.cc index c2eccc249f98..afe9d5be68d9 100644 --- a/tests/mpi/hp_cell_weights_03.cc +++ b/tests/mpi/hp_cell_weights_03.cc @@ -63,17 +63,12 @@ test() fe_collection.push_back(FE_Q(5)); hp::DoFHandler dh(tria); + dh.set_fe(fe_collection); // default: active_fe_index = 0 for (auto &cell : dh.active_cell_iterators()) if (cell->is_locally_owned()) if (cell->id().to_string() == "0_2:00") cell->set_active_fe_index(1); - dh.distribute_dofs(fe_collection); - - - parallel::CellWeights cell_weights(dh); - cell_weights.register_ndofs_weighting(100000); - deallog << "Number of cells before repartitioning: " << tria.n_locally_owned_active_cells() << std::endl; @@ -86,9 +81,11 @@ test() } + parallel::CellWeights cell_weights(dh); + cell_weights.register_ndofs_weighting(100000); + // we didn't mark any cells, but we want to repartition our domain tria.execute_coarsening_and_refinement(); - dh.distribute_dofs(fe_collection); deallog << "Number of cells after repartitioning: " diff --git a/tests/mpi/p4est_save_06.cc b/tests/mpi/p4est_save_06.cc index 5af46a86964b..453ed583896d 100644 --- a/tests/mpi/p4est_save_06.cc +++ b/tests/mpi/p4est_save_06.cc @@ -134,7 +134,7 @@ test() for (unsigned int i = 0; i < max_degree; ++i) fe_collection.push_back(FE_Q(max_degree - i)); - dh.distribute_dofs(fe_collection); + dh.set_fe(fe_collection); dh.deserialize_active_fe_indices(); dh.distribute_dofs(fe_collection); From 2be46094200872ffa8cc9f63d20d20926cb392eb Mon Sep 17 00:00:00 2001 From: Marc Fehling Date: Mon, 11 Feb 2019 18:02:27 +0100 Subject: [PATCH 205/507] Add warning to set_fe. --- include/deal.II/dofs/dof_handler.h | 5 +++++ include/deal.II/hp/dof_handler.h | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/include/deal.II/dofs/dof_handler.h b/include/deal.II/dofs/dof_handler.h index 1da5931739ac..d07ecf0738dd 100644 --- a/include/deal.II/dofs/dof_handler.h +++ b/include/deal.II/dofs/dof_handler.h @@ -487,6 +487,11 @@ class DoFHandler : public Subscriptor * main class and refer to it directly whenever you need to access * properties of the finite element (such as * FiniteElementData::dofs_per_cell). This is what all tutorial programs do. + * + * @warning This function only sets a FiniteElement. Degrees of freedom have + * either not been distributed yet, or are distributed using a previously set + * element. In both cases, accessing degrees of freedom will lead to invalid + * results. To restore consistency, call distribute_dofs(). */ virtual void set_fe(const FiniteElement &fe); diff --git a/include/deal.II/hp/dof_handler.h b/include/deal.II/hp/dof_handler.h index 3b73789941c6..e16a52495283 100644 --- a/include/deal.II/hp/dof_handler.h +++ b/include/deal.II/hp/dof_handler.h @@ -426,6 +426,12 @@ namespace hp * * @note In accordance with dealii::DoFHandler::set_fe(), * this function also makes a copy of the object given as argument. + * + * @warning This function only sets a hp::FECollection. Degrees of freedom + * have either not been distributed yet, or are distributed using a + * previously set collection. In both cases, accessing degrees of freedom + * will lead to invalid results. To restore consistency, call + * distribute_dofs(). */ virtual void set_fe(const hp::FECollection &fe); From a501894dc24a677998ba57fb6392547cb7d0fc71 Mon Sep 17 00:00:00 2001 From: Marc Fehling Date: Thu, 28 Feb 2019 13:57:06 +0100 Subject: [PATCH 206/507] hp::distribute_dofs: Move 'set_fe' call to the place where active_fe_indices are initialized. --- source/hp/dof_handler.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/hp/dof_handler.cc b/source/hp/dof_handler.cc index 35e4a1766649..f2cfe2686dbc 100644 --- a/source/hp/dof_handler.cc +++ b/source/hp/dof_handler.cc @@ -1431,9 +1431,6 @@ namespace hp ExcMessage("The Triangulation you are using is empty!")); Assert(ff.size() > 0, ExcMessage("The hp::FECollection given is empty!")); - // first, assign the fe_collection - set_fe(ff); - // If an underlying shared::Tria allows artificial cells, // then save the current set of subdomain ids, and set // subdomain ids to the "true" owner of each cell. we later @@ -1457,7 +1454,10 @@ namespace hp } } - // then allocate space for all tables + // assign the fe_collection and initialize all active_fe_indices + set_fe(ff); + + // then allocate space for all the other tables dealii::internal::hp::DoFHandlerImplementation::Implementation:: reserve_space(*this); From 15b4cfaac6b2aba3036d05ac155ec31db62ef6c6 Mon Sep 17 00:00:00 2001 From: tcclevenger Date: Fri, 8 Feb 2019 15:42:12 -0700 Subject: [PATCH 207/507] add no normal flux to MGConstrainedDoFs (box mesh) --- .../changes/minor/20190211ConradClevenger | 6 ++ .../deal.II/multigrid/mg_constrained_dofs.h | 75 +++++++++++++++++++ tests/multigrid/constrained_dofs_06.cc | 75 +++++++++++++++++++ tests/multigrid/constrained_dofs_06.output | 14 ++++ 4 files changed, 170 insertions(+) create mode 100644 doc/news/changes/minor/20190211ConradClevenger create mode 100644 tests/multigrid/constrained_dofs_06.cc create mode 100644 tests/multigrid/constrained_dofs_06.output 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/include/deal.II/multigrid/mg_constrained_dofs.h b/include/deal.II/multigrid/mg_constrained_dofs.h index 40f2cd7c0d1c..452563eb3b11 100644 --- a/include/deal.II/multigrid/mg_constrained_dofs.h +++ b/include/deal.II/multigrid/mg_constrained_dofs.h @@ -100,6 +100,26 @@ class MGConstrainedDoFs : public Subscriptor const std::set &boundary_ids, const ComponentMask & component_mask = ComponentMask()); + /** + * Fill the internal data structures with information + * about no normal flux boundary dofs. + * + * This function is limited to meshes whose no normal flux boundaries + * have faces which are normal to the x-, y-, or z-axis. Also, for a + * specific boundary id, all faces must be facing in the same direction, + * i.e., a boundary normal to the x-axis must have a different boundary + * id than a boundary normal to the y- or z-axis and so on. If the mesh + * was produced, for example, using the GridGenerator::hyper_cube() + * function, setting colorize=true during mesh generation and calling + * make_no_normal_flux_constraints() for each no normal flux boundary is + * sufficient. + */ + template + void + make_no_normal_flux_constraints(const DoFHandler &dof, + const types::boundary_id bid, + const unsigned int first_vector_component); + /** * Reset the data structures. */ @@ -321,6 +341,61 @@ MGConstrainedDoFs::make_zero_boundary_constraints( } +template +inline void +MGConstrainedDoFs::make_no_normal_flux_constraints( + const DoFHandler &dof, + const types::boundary_id bid, + const unsigned int first_vector_component) +{ + // For a given boundary id, find which vector component is on the boundary + // and set a zero boundary constraint for those degrees of freedom. + const unsigned int n_components = DoFTools::n_components(dof); + Assert(first_vector_component + dim <= n_components, + ExcIndexRange(first_vector_component, 0, n_components - dim + 1)); + + ComponentMask comp_mask(n_components, false); + + + typename Triangulation::face_iterator + face = dof.get_triangulation().begin_face(), + endf = dof.get_triangulation().end_face(); + for (; face != endf; ++face) + if (face->at_boundary() && face->boundary_id() == bid) + for (unsigned int d = 0; d < dim; ++d) + { + Tensor<1, dim, double> unit_vec; + unit_vec[d] = 1.0; + + const Tensor<1, dim> normal_vec = + face->get_manifold().normal_vector(face, face->center()); + + if (std::abs(std::abs(unit_vec * normal_vec) - 1.0) < 1e-10) + comp_mask.set(d + first_vector_component, true); + else + Assert( + std::abs(unit_vec * normal_vec) < 1e-10, + ExcMessage( + "We can currently only support no normal flux conditions " + "for a specific boundary id if all faces are normal to the " + "x, y, or z axis.")); + } + + Assert(comp_mask.n_selected_components() == 1, + ExcMessage( + "We can currently only support no normal flux conditions " + "for a specific boundary id if all faces are facing in the " + "same direction, i.e., a boundary normal to the x-axis must " + "have a different boundary id than a boundary normal to the " + "y- or z-axis and so on. If the mesh here was produced using " + "GridGenerator::..., setting colorize=true during mesh generation " + "and calling make_no_normal_flux_constraints() for each no normal " + "flux boundary will fulfill the condition.")); + + this->make_zero_boundary_constraints(dof, {bid}, comp_mask); +} + + inline void MGConstrainedDoFs::clear() { diff --git a/tests/multigrid/constrained_dofs_06.cc b/tests/multigrid/constrained_dofs_06.cc new file mode 100644 index 000000000000..cc0101f5995c --- /dev/null +++ b/tests/multigrid/constrained_dofs_06.cc @@ -0,0 +1,75 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Check make_no_normal_flux_constraints function for a box mesh + +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include "../tests.h" + + +template +void +test() +{ + Triangulation triangulation( + Triangulation::limit_level_difference_at_vertices); + GridGenerator::hyper_cube(triangulation, 0., 1., true); + triangulation.refine_global(4 - dim); + + DoFHandler dof_handler(triangulation); + dof_handler.distribute_dofs(FESystem(FE_Q(1), dim)); + dof_handler.distribute_mg_dofs(); + + std::set no_flux_boundary = {0, 1, 2}; + + MGConstrainedDoFs mg_constrained_dofs; + mg_constrained_dofs.initialize(dof_handler); + for (auto bid : no_flux_boundary) + mg_constrained_dofs.make_no_normal_flux_constraints(dof_handler, bid, 0); + + for (unsigned int level = 0; level < triangulation.n_levels(); ++level) + { + deallog << "Level " << level << ": " << std::flush; + mg_constrained_dofs.get_boundary_indices(level).print( + deallog.get_file_stream()); + deallog << std::endl; + } +} + +int +main() +{ + initlog(); + + deallog << "2D" << std::endl; + test<2>(); + deallog << std::endl << "3D" << std::endl; + test<3>(); + return 0; +} diff --git a/tests/multigrid/constrained_dofs_06.output b/tests/multigrid/constrained_dofs_06.output new file mode 100644 index 000000000000..8f3fffee1a76 --- /dev/null +++ b/tests/multigrid/constrained_dofs_06.output @@ -0,0 +1,14 @@ + +DEAL::2D +DEAL::Level 0: {[0,4], 6} + +DEAL::Level 1: {[0,1], [3,4], [8,10], 12, 16} + +DEAL::Level 2: {[0,1], [3,4], 9, 12, 19, [22,24], 28, 30, 36, 44, 48} + +DEAL:: +DEAL::3D +DEAL::Level 0: {[0,1], [3,4], 6, 9, [12,13], [15,16], 18, 21} + +DEAL::Level 1: {[0,1], 4, 6, [12,13], 16, 18, [24,25], 27, [30,31], 33, 36, 42, 48, 51, [54,55], 58, 60, [66,67], 69, 72, 78} + From 2b541384f0210bbf8140d7442ede9039fee4a831 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Thu, 28 Feb 2019 14:23:12 -0600 Subject: [PATCH 208/507] SparsityPattern::Iterator - add a constructor for initalizing an iterator from an accessor When trying to increment a sparsity pattern iterator: auto iterator = sparsity_pattern.begin(); iterator++; The corresponding function in LinearIndexIterator: template inline DerivedIterator LinearIndexIterator::operator++(int) { const DerivedIterator copy(this->accessor); operator+=(1); return copy; } creates a copy that is initialized by the accessor. Thus, we need a constructor that can create an interator from an accessor. --- include/deal.II/lac/sparsity_pattern.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/deal.II/lac/sparsity_pattern.h b/include/deal.II/lac/sparsity_pattern.h index 89c507a31e16..573c6c29475b 100644 --- a/include/deal.II/lac/sparsity_pattern.h +++ b/include/deal.II/lac/sparsity_pattern.h @@ -298,6 +298,12 @@ namespace SparsityPatternIterators * the zeroth row). */ Iterator(const SparsityPattern *sp, const std::size_t linear_index); + + /** + * Constructor. Create an iterator into the sparsity pattern @p sp for + * a given accessor. + */ + Iterator(const Accessor &accessor); }; } // namespace SparsityPatternIterators @@ -1272,6 +1278,13 @@ namespace SparsityPatternIterators const std::size_t linear_index) : LinearIndexIterator(Accessor(sp, linear_index)) {} + + + inline Iterator::Iterator(const Accessor &accessor) + : LinearIndexIterator(accessor) + {} + + } // namespace SparsityPatternIterators From e9c20e609eb6f7ff6ba75bf0377466b98dfbcc62 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Thu, 28 Feb 2019 14:34:24 -0600 Subject: [PATCH 209/507] add a test --- .../sparsity/sparsity_pattern_iterator_09.cc | 51 +++++++++++++++++++ .../sparsity_pattern_iterator_09.output | 2 + 2 files changed, 53 insertions(+) create mode 100644 tests/sparsity/sparsity_pattern_iterator_09.cc create mode 100644 tests/sparsity/sparsity_pattern_iterator_09.output diff --git a/tests/sparsity/sparsity_pattern_iterator_09.cc b/tests/sparsity/sparsity_pattern_iterator_09.cc new file mode 100644 index 000000000000..17493bd5123a --- /dev/null +++ b/tests/sparsity/sparsity_pattern_iterator_09.cc @@ -0,0 +1,51 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2004 - 2017 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. +// +// --------------------------------------------------------------------- + + + +// test that i++ and i+n operations work with SparsityPattern::iterator. + +#include + +#include "../tests.h" + +void +test() +{ + SparsityPattern sp(5, 5, 3); + for (unsigned int i = 0; i < 5; ++i) + for (unsigned int j = 0; j < 5; ++j) + if ((i + 2 * j + 1) % 3 == 0) + sp.add(i, j); + sp.compress(); + + SparsityPattern::const_iterator i = sp.begin(); + + ++i; + i++; + i + 2; + + deallog << "OK" << std::endl; +} + + + +int +main() +{ + initlog(); + + test(); +} diff --git a/tests/sparsity/sparsity_pattern_iterator_09.output b/tests/sparsity/sparsity_pattern_iterator_09.output new file mode 100644 index 000000000000..0fd8fc12f0b4 --- /dev/null +++ b/tests/sparsity/sparsity_pattern_iterator_09.output @@ -0,0 +1,2 @@ + +DEAL::OK From b9057152a4868e66dc828e27ba7258c211ac5f79 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 22 Feb 2019 15:36:31 +0100 Subject: [PATCH 210/507] Also instantiate for complex scalar types --- cmake/config/template-arguments.in | 6 ++++++ cmake/configure/configure_2_trilinos.cmake | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/cmake/config/template-arguments.in b/cmake/config/template-arguments.in index 8a58e905961b..2e1a69bd7618 100644 --- a/cmake/config/template-arguments.in +++ b/cmake/config/template-arguments.in @@ -97,6 +97,8 @@ VECTOR_TYPES := { 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@; @@ -153,6 +155,8 @@ EXTERNAL_PARALLEL_VECTORS := { @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_PETSC_MPI_BLOCKVECTOR@ } @@ -173,6 +177,8 @@ VECTORS_WITH_MATRIX := { 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@; } diff --git a/cmake/configure/configure_2_trilinos.cmake b/cmake/configure/configure_2_trilinos.cmake index 187fed907170..7a1f32cc5cc0 100644 --- a/cmake/configure/configure_2_trilinos.cmake +++ b/cmake/configure/configure_2_trilinos.cmake @@ -273,6 +273,10 @@ MACRO(FEATURE_TRILINOS_CONFIGURE_EXTERNAL) 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}) From a49023961e854d2629a6a289f1b0edc5b6bf2337 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 1 Mar 2019 01:06:17 +0100 Subject: [PATCH 211/507] Enhance error message --- cmake/configure/configure_1_cuda.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/configure/configure_1_cuda.cmake b/cmake/configure/configure_1_cuda.cmake index 9001a9416586..94c34940db70 100644 --- a/cmake/configure/configure_1_cuda.cmake +++ b/cmake/configure/configure_1_cuda.cmake @@ -115,7 +115,8 @@ MACRO(FEATURE_CUDA_FIND_EXTERNAL var) ${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." + "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() From 4f6a313d8eb6adc884951680bd860a81878b43e8 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 1 Mar 2019 01:22:29 +0100 Subject: [PATCH 212/507] Add description of memory and exceution space for CUDA support --- include/deal.II/lac/trilinos_tpetra_vector.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/deal.II/lac/trilinos_tpetra_vector.h b/include/deal.II/lac/trilinos_tpetra_vector.h index e883b24a00a8..35e31cc92eb1 100644 --- a/include/deal.II/lac/trilinos_tpetra_vector.h +++ b/include/deal.II/lac/trilinos_tpetra_vector.h @@ -54,9 +54,15 @@ namespace LinearAlgebra * LinearAlgebra::VectorSpaceVector class and requires Trilinos to be * compiled with MPI support. * + * Tpetra uses Kokkos for thread-parallelism. In case Trilinos was + * configured with CUDA support, this class stores the values in unified + * virtual memory space and performs its action on the GPU. In particular, + * there is no need for manually synchronizing memory between host and + * device. + * * @ingroup TrilinosWrappers * @ingroup Vectors - * @author Daniel Arndt, 2018 + * @author Daniel Arndt, 2019 */ template class Vector : public VectorSpaceVector, public Subscriptor From 2e5bd57206d8ee0c6f156aad67b0725010630979 Mon Sep 17 00:00:00 2001 From: Reza Rastak Date: Thu, 28 Feb 2019 16:55:00 -0800 Subject: [PATCH 213/507] Out of date description of quadrature_point_data test fixed --- tests/base/quadrature_point_data.cc | 2 +- tests/base/quadrature_point_data_02.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/base/quadrature_point_data.cc b/tests/base/quadrature_point_data.cc index 45aaefe99ad1..2963250bc09a 100644 --- a/tests/base/quadrature_point_data.cc +++ b/tests/base/quadrature_point_data.cc @@ -15,7 +15,7 @@ -// Check that QuadraturePointManager class. To that end first evaluate some +// Check CellDataStorage class. To that end first evaluate some // quadratic function at quadrature points. Then refine cells and project using // FE_Q(2). Finally check that the values at quadrature points are still // consistent with the original function. diff --git a/tests/base/quadrature_point_data_02.cc b/tests/base/quadrature_point_data_02.cc index 546c0a437d29..16d9f4df671d 100644 --- a/tests/base/quadrature_point_data_02.cc +++ b/tests/base/quadrature_point_data_02.cc @@ -15,7 +15,7 @@ -// Check that QuadraturePointManager class. To that end first evaluate some +// Check CellDataStorage class. To that end first evaluate some // quadratic function at quadrature points. Then refine cells and project using // FE_Q(2). Finally check that the values at quadrature points are still // consistent with the original function. Same as quadrature_point_data.cc, but From 98145fce9e71a0a14acb24197c0e839dcccaa58d Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Fri, 1 Mar 2019 00:10:36 -0700 Subject: [PATCH 214/507] Convert a few explicit loops to range-based for loops. --- source/grid/tria.cc | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/source/grid/tria.cc b/source/grid/tria.cc index b3c515621858..2e7fce823fe5 100644 --- a/source/grid/tria.cc +++ b/source/grid/tria.cc @@ -14119,9 +14119,7 @@ Triangulation::prepare_coarsening_and_refinement() if (((smooth_grid & coarsest_level_1) || (smooth_grid & patch_level_1)) && n_levels() >= 2) { - active_cell_iterator cell = begin_active(1), endc = end_active(1); - - for (; cell != endc; ++cell) + for (const auto &cell : active_cell_iterators_on_level(1)) cell->clear_coarsen_flag(); } @@ -14137,10 +14135,7 @@ Triangulation::prepare_coarsening_and_refinement() if (smooth_grid & do_not_produce_unrefined_islands && !(smooth_grid & patch_level_1)) { - cell_iterator cell; - const cell_iterator endc = end(); - - for (cell = begin(); cell != endc; ++cell) + for (const auto &cell : cell_iterators()) { // only do something if this // cell will be coarsened @@ -14173,10 +14168,7 @@ Triangulation::prepare_coarsening_and_refinement() eliminate_refined_boundary_islands) && !(smooth_grid & patch_level_1)) { - cell_iterator cell; - const cell_iterator endc = end(); - - for (cell = begin(); cell != endc; ++cell) + for (const auto &cell : cell_iterators()) if (!cell->active() || (cell->active() && cell->refine_flag_set() && cell->is_locally_owned())) { @@ -14271,9 +14263,8 @@ Triangulation::prepare_coarsening_and_refinement() // store highest level one of the cells adjacent to a vertex // belongs to - std::vector vertex_level(vertices.size(), 0); - active_cell_iterator cell = begin_active(), endc = end(); - for (; cell != endc; ++cell) + std::vector vertex_level(vertices.size(), 0); + for (const auto &cell : active_cell_iterators()) { if (cell->refine_flag_set()) for (unsigned int vertex = 0; @@ -14315,7 +14306,7 @@ Triangulation::prepare_coarsening_and_refinement() // refinement flags, but we will also have to remove // coarsening flags on cells adjacent to vertices that will // see refinement - for (cell = last_active(); cell != endc; --cell) + for (active_cell_iterator cell = last_active(); cell != end(); --cell) if (cell->refine_flag_set() == false) { for (unsigned int vertex = 0; @@ -14363,9 +14354,7 @@ Triangulation::prepare_coarsening_and_refinement() // may trigger more cells further down below if (smooth_grid & eliminate_unrefined_islands) { - active_cell_iterator cell = last_active(), endc = end(); - - for (; cell != endc; --cell) + for (active_cell_iterator cell = last_active(); cell != end(); --cell) // only do something if cell is not already flagged for // (isotropic) refinement if (cell->refine_flag_set() != @@ -14409,7 +14398,7 @@ Triangulation::prepare_coarsening_and_refinement() // active). If the refine flag of at least one of the // children is set then set_refine_flag and // clear_coarsen_flag of all children. - for (cell_iterator cell = begin(); cell != end(); ++cell) + for (const auto &cell : cell_iterators()) if (!cell->active()) { // ensure the invariant. we can then check whether all @@ -14445,7 +14434,7 @@ Triangulation::prepare_coarsening_and_refinement() // // for a case where this is a bit tricky, take a look at the // mesh_smoothing_0[12] testcases - for (cell_iterator cell = begin(); cell != end(); ++cell) + for (const auto &cell : cell_iterators()) { // check if this cell has active grandchildren. note // that we know that it is patch_level_1, i.e. if one of From 59a3884d61e5257e003135b719d93abb97b649f9 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Fri, 1 Mar 2019 10:00:40 -0700 Subject: [PATCH 215/507] work around gcc 4.8.5 behavior in GridTools::Cache fixes #7771 --- source/grid/grid_tools_cache.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/source/grid/grid_tools_cache.cc b/source/grid/grid_tools_cache.cc index 52f664b01aec..d1098c69862d 100644 --- a/source/grid/grid_tools_cache.cc +++ b/source/grid/grid_tools_cache.cc @@ -167,9 +167,16 @@ namespace GridTools // TO DO: the locally owned portion of the domain // might consists of more separate pieces: a single // bounding box might not always be the best choice. + + // Note: we create the local variable ptr here, because gcc 4.8.5 + // fails to compile if we pass the variable directly. IteratorFilters::LocallyOwnedCell locally_owned_cell_predicate; - const BoundingBox bbox = - GridTools::compute_bounding_box(*tria, locally_owned_cell_predicate); + std::function::active_cell_iterator &)> + ptr(locally_owned_cell_predicate); + + const BoundingBox bbox = + GridTools::compute_bounding_box(get_triangulation(), ptr); std::vector> bbox_v(1, bbox); From 15dbfa671881458b13f56aafe9dc19d62d1cde63 Mon Sep 17 00:00:00 2001 From: Marc Fehling Date: Fri, 1 Mar 2019 19:17:29 +0100 Subject: [PATCH 216/507] hp::DoFHandler::ActiveFEIndicesTransfer: Separate work from memory management. --- source/hp/dof_handler.cc | 235 ++++++++++++++++++++++++--------------- 1 file changed, 144 insertions(+), 91 deletions(-) diff --git a/source/hp/dof_handler.cc b/source/hp/dof_handler.cc index ad53874b5bd5..891b1ef72351 100644 --- a/source/hp/dof_handler.cc +++ b/source/hp/dof_handler.cc @@ -1036,6 +1036,131 @@ namespace internal ExcInternalError()); } } + + + + /** + * Collect all finite element indices on cells that will be affected by + * future refinement and coarsening. Further, prepare those indices to + * be distributed on on the updated triangulation later. + * + * On cells to be refined, the active_fe_index will be inherited to + * their childrean and thus will be stored as such. + * + * On cells to be coarsened, the active_fe_index on parent cells will be + * determined by the least dominating finite element of its children. We + * will thus assign the corresponding fe_index to the parent cell. See + * documentation of + * FECollection::find_least_dominating_fe_in_collection() for further + * information. + */ + template + static void + collect_fe_indices_on_cells_to_be_refined( + dealii::hp::DoFHandler &dof_handler) + { + const auto &fe_transfer = dof_handler.active_fe_index_transfer; + + for (const auto &cell : dof_handler.active_cell_iterators()) + if (cell->is_locally_owned()) + { + if (cell->refine_flag_set()) + { + // Store the active_fe_index of each cell that will be + // refined to and distribute it later on its children. + fe_transfer->refined_cells_fe_index.insert( + {cell, cell->active_fe_index()}); + } + else if (cell->coarsen_flag_set()) + { + // From all cells that will be coarsened, determine their + // parent and calculate its proper active_fe_index, so that + // it can be set after refinement. But first, check if that + // particular cell has a parent at all. + Assert(cell->level() > 0, ExcInternalError()); + const auto &parent = cell->parent(); + // Check if the active_fe_index for the current cell has + // been determined already. + if (fe_transfer->coarsened_cells_fe_index.find(parent) == + fe_transfer->coarsened_cells_fe_index.end()) + { + std::set fe_indices_children; + for (unsigned int child_index = 0; + child_index < parent->n_children(); + ++child_index) + { + Assert(parent->child(child_index)->active(), + ExcInternalError()); + + fe_indices_children.insert( + parent->child(child_index)->active_fe_index()); + } + + const unsigned int fe_index = + dof_handler.fe_collection + .find_least_dominating_fe_in_collection( + fe_indices_children, /*codim=*/0); + + Assert( + fe_index != numbers::invalid_unsigned_int, + ExcMessage( + "No FiniteElement has been found in your FECollection " + "that dominates all children of a cell you are trying " + "to coarsen!")); + + fe_transfer->coarsened_cells_fe_index.insert( + {parent, fe_index}); + } + } + } + } + + + + /** + * Distribute active finite element indices that have been previously + * prepared in collect_fe_indices_on_cells_to_be_refined(). + */ + template + static void + distribute_fe_indices_on_refined_cells( + dealii::hp::DoFHandler &dof_handler) + { + const auto &fe_transfer = dof_handler.active_fe_index_transfer; + + // Distribute active_fe_indices from all refined cells on their + // respective children. + for (const auto &pair : fe_transfer->refined_cells_fe_index) + { + const auto &parent = pair.first; + + for (unsigned int child_index = 0; + child_index < parent->n_children(); + ++child_index) + { + const auto &child = parent->child(child_index); + + if (child->is_locally_owned()) + { + Assert(child->active(), ExcInternalError()); + child->set_active_fe_index(pair.second); + } + } + } + + // Set active_fe_indices on coarsened cells that have been determined + // before the actual coarsening happened. + for (const auto &pair : fe_transfer->coarsened_cells_fe_index) + { + const auto &cell = pair.first; + + if (cell->is_locally_owned()) + { + Assert(cell->active(), ExcInternalError()); + cell->set_active_fe_index(pair.second); + } + } + } }; } // namespace DoFHandlerImplementation } // namespace hp @@ -1787,60 +1912,8 @@ namespace hp active_fe_index_transfer = std_cxx14::make_unique(); - // Store active_fe_index information for all cells that will be - // affected by refinement/coarsening. - for (const auto &cell : active_cell_iterators()) - if (cell->is_locally_owned()) - { - if (cell->refine_flag_set()) - { - // Store the active_fe_index of each cell that will be refined - // to and distribute it later on its children. - active_fe_index_transfer->refined_cells_fe_index.insert( - {cell, cell->active_fe_index()}); - } - else if (cell->coarsen_flag_set()) - { - // From all cells that will be coarsened, determine their - // parent and calculate its proper active_fe_index, so that it - // can be set after refinement. But first, check if that - // particular cell has a parent at all. - Assert(cell->level() > 0, ExcInternalError()); - const auto &parent = cell->parent(); - // Check if the active_fe_index for the current cell has been - // determined already. - if (active_fe_index_transfer->coarsened_cells_fe_index.find( - parent) == - active_fe_index_transfer->coarsened_cells_fe_index.end()) - { - std::set fe_indices_children; - for (unsigned int child_index = 0; - child_index < parent->n_children(); - ++child_index) - { - Assert(parent->child(child_index)->active(), - ExcInternalError()); - - fe_indices_children.insert( - parent->child(child_index)->active_fe_index()); - } - - const unsigned int fe_index = - fe_collection.find_least_dominating_fe_in_collection( - fe_indices_children, /*codim=*/0); - - Assert( - fe_index != numbers::invalid_unsigned_int, - ExcMessage( - "No FiniteElement has been found in your FECollection " - "that dominates all children of a cell you are trying " - "to coarsen!")); - - active_fe_index_transfer->coarsened_cells_fe_index.insert( - {parent, fe_index}); - } - } - } + dealii::internal::hp::DoFHandlerImplementation::Implementation:: + collect_fe_indices_on_cells_to_be_refined(*this); } } @@ -1859,6 +1932,9 @@ namespace hp { Assert(active_fe_index_transfer == nullptr, ExcInternalError()); + active_fe_index_transfer = + std_cxx14::make_unique(); + // If the underlying shared::Tria allows artificial cells, // then save the current set of subdomain ids, and set // subdomain ids to the "true" owner of each cell. We later @@ -1890,7 +1966,8 @@ namespace hp } // Now do what we would do in the sequential case. - pre_active_fe_index_transfer(); + dealii::internal::hp::DoFHandlerImplementation::Implementation:: + collect_fe_indices_on_cells_to_be_refined(*this); // Finally, restore current subdomain_ids. if (shared_tria->with_artificial_cells()) @@ -1921,8 +1998,12 @@ namespace hp { Assert(active_fe_index_transfer == nullptr, ExcInternalError()); + active_fe_index_transfer = + std_cxx14::make_unique(); + // First, do what we would do in the sequential case. - pre_active_fe_index_transfer(); + dealii::internal::hp::DoFHandlerImplementation::Implementation:: + collect_fe_indices_on_cells_to_be_refined(*this); // If we work on a p::d::Triangulation, we have to transfer all // active_fe_indices since ownership of cells may change. We will @@ -1983,40 +2064,8 @@ namespace hp // and we can re-use our previously gathered information from the // container. - // Distribute active_fe_indices from all refined cells on their - // respective children. - for (const auto &pair : - active_fe_index_transfer->refined_cells_fe_index) - { - const cell_iterator &parent = pair.first; - - for (unsigned int child_index = 0; - child_index < parent->n_children(); - ++child_index) - { - const cell_iterator child = parent->child(child_index); - - if (child->is_locally_owned()) - { - Assert(child->active(), ExcInternalError()); - child->set_active_fe_index(pair.second); - } - } - } - - // Set active_fe_indices on coarsened cells that have been determined - // before the actual coarsening happened. - for (const auto &pair : - active_fe_index_transfer->coarsened_cells_fe_index) - { - const cell_iterator &cell = pair.first; - - if (cell->is_locally_owned()) - { - Assert(cell->active(), ExcInternalError()); - cell->set_active_fe_index(pair.second); - } - } + dealii::internal::hp::DoFHandlerImplementation::Implementation:: + distribute_fe_indices_on_refined_cells(*this); // Free memory. active_fe_index_transfer.reset(); @@ -2039,13 +2088,17 @@ namespace hp Assert(active_fe_index_transfer != nullptr, ExcInternalError()); // Do what we normally do in the sequential case. - post_active_fe_index_transfer(); + dealii::internal::hp::DoFHandlerImplementation::Implementation:: + distribute_fe_indices_on_refined_cells(*this); // We have to distribute the information about active_fe_indices // on all processors, if a parallel::shared::Triangulation // has been used. dealii::internal::hp::DoFHandlerImplementation::Implementation:: communicate_active_fe_indices(*this); + + // Free memory. + active_fe_index_transfer.reset(); } #endif } From 92951fa7959b8a6b53d40b61516b304068023bcc Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 2 Mar 2019 17:16:12 +0100 Subject: [PATCH 217/507] Document the execution space some more --- include/deal.II/lac/trilinos_tpetra_vector.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/include/deal.II/lac/trilinos_tpetra_vector.h b/include/deal.II/lac/trilinos_tpetra_vector.h index 35e31cc92eb1..69303e228403 100644 --- a/include/deal.II/lac/trilinos_tpetra_vector.h +++ b/include/deal.II/lac/trilinos_tpetra_vector.h @@ -54,11 +54,18 @@ namespace LinearAlgebra * LinearAlgebra::VectorSpaceVector class and requires Trilinos to be * compiled with MPI support. * - * Tpetra uses Kokkos for thread-parallelism. In case Trilinos was - * configured with CUDA support, this class stores the values in unified - * virtual memory space and performs its action on the GPU. In particular, - * there is no need for manually synchronizing memory between host and - * device. + * Tpetra uses Kokkos for thread-parallelism and chooses the execution and + * memory space automatically depending on Kokkos configuration. The + * priority is ranked from highest to lowest: + * - Kokkos::Cuda + * - Kokkos::OpenMP + * - Kokkos::Threads + * - Kokkos::Serial + * + * In case Kokkos was configured with CUDA support, this class stores the + * values in unified virtual memory space and performs its action on the + * GPU. In particular, there is no need for manually synchronizing memory + * between host and device. * * @ingroup TrilinosWrappers * @ingroup Vectors From 4d60dc9831cc1f6be761e077d4cdaafd8a3d9051 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 2 Mar 2019 21:10:24 +0100 Subject: [PATCH 218/507] Fix inteference if material_id with the manifold object in the codimension case --- doc/news/changes/minor/20190302ArndtStark | 4 ++ source/grid/tria.cc | 48 +---------------- tests/codim_one/mesh_bug_02.cc | 53 +++++++++++++++++++ tests/codim_one/mesh_bug_02.output | 48 +++++++++++++++++ tests/opencascade/circle_normal_projection.cc | 3 +- .../circle_normal_projection.output | 32 +++++------ .../interpolation_curve_boundary.cc | 3 +- .../interpolation_curve_boundary.output | 32 +++++------ tests/serialization/triangulation_01.output | 4 +- tests/serialization/triangulation_02.output | 4 +- 10 files changed, 147 insertions(+), 84 deletions(-) create mode 100644 doc/news/changes/minor/20190302ArndtStark create mode 100644 tests/codim_one/mesh_bug_02.cc create mode 100644 tests/codim_one/mesh_bug_02.output 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/source/grid/tria.cc b/source/grid/tria.cc index b3c515621858..40d171cf074d 100644 --- a/source/grid/tria.cc +++ b/source/grid/tria.cc @@ -4984,29 +4984,7 @@ namespace internal typename Triangulation::line_iterator line = cell->line(line_no); if (line->has_children() == false) - { - line->set_user_flag(); - // TODO[WB]: we overwrite the user_index here - // because we later on need - // to find out which boundary object we have to - // ask to refine this line. we can't use the - // boundary_id field because that can only be used - // for lines at the boundary of the domain, but we - // also need a domain description for interior - // lines in the codim-1 case - if (spacedim > dim) - { - if (line->at_boundary()) - // if possible honor boundary - // indicator - line->set_user_index(line->boundary_id()); - else - // otherwise take manifold - // description from the adjacent - // cell - line->set_user_index(cell->material_id()); - } - } + line->set_user_flag(); } } } @@ -5098,29 +5076,7 @@ namespace internal "Internal error: During refinement, the triangulation wants to access an element of the 'vertices' array but it turns out that the array is not large enough.")); triangulation.vertices_used[next_unused_vertex] = true; - if (spacedim == dim) - { - // for the case of a domain in an - // equal-dimensional space we only have to treat - // boundary lines differently; for interior - // lines we can compute the midpoint as the mean - // of the two vertices: if (line->at_boundary()) - triangulation.vertices[next_unused_vertex] = - line->center(true); - } - else - // however, if spacedim>dim, we always have to ask - // the boundary object for its answer. We use the - // same object of the cell (which was stored in - // line->user_index() before) unless a manifold_id - // has been set on this very line. - if (line->manifold_id() == numbers::flat_manifold_id) - triangulation.vertices[next_unused_vertex] = - triangulation.get_manifold(line->user_index()) - .get_new_point_on_line(line); - else - triangulation.vertices[next_unused_vertex] = - line->center(true); + triangulation.vertices[next_unused_vertex] = line->center(true); // now that we created the right point, make up the // two child lines. To this end, find a pair of diff --git a/tests/codim_one/mesh_bug_02.cc b/tests/codim_one/mesh_bug_02.cc new file mode 100644 index 000000000000..c723f44ad7ac --- /dev/null +++ b/tests/codim_one/mesh_bug_02.cc @@ -0,0 +1,53 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Test that material_id and manifold_id don't interfere with each other. + +#include +#include +#include + +#include "../tests.h" + + +int +main() +{ + initlog(); + + // triangulation is a single 2d square element embedded into 3d space + Triangulation<2, 3> plane; + Point<3> p1(1., 0., 0.); + Point<3> p2(1., 1., 0.); + Point<3> p3(1., 0., 1.); + Point<3> p4(1., 1., 1.); + std::vector> vertices = {p1, p2, p3, p4}; + GridGenerator::general_cell(plane, vertices); + + // set the material id of the cell to 1 + plane.begin_active()->set_material_id(1); + + // now associate a spherical manifold object with manifold_id 1 + //(this object isn't used in this minimal example, but there could + // in principle be other cells to which the manifold_id 1 is assigned) + SphericalManifold<2, 3> spherical_manifold; + plane.set_manifold(1, spherical_manifold); + + plane.refine_global(2); + + GridOut gridout; + gridout.write_msh(plane, deallog.get_file_stream()); +} diff --git a/tests/codim_one/mesh_bug_02.output b/tests/codim_one/mesh_bug_02.output new file mode 100644 index 000000000000..7cbab8ea52ca --- /dev/null +++ b/tests/codim_one/mesh_bug_02.output @@ -0,0 +1,48 @@ + +$NOD +25 +1 1.00000 0.00000 0.00000 +2 1.00000 1.00000 0.00000 +3 1.00000 0.00000 1.00000 +4 1.00000 1.00000 1.00000 +5 1.00000 0.500000 0.00000 +6 1.00000 0.00000 0.500000 +7 1.00000 1.00000 0.500000 +8 1.00000 0.500000 1.00000 +9 1.00000 0.500000 0.500000 +10 1.00000 0.250000 0.00000 +11 1.00000 0.750000 0.00000 +12 1.00000 0.00000 0.250000 +13 1.00000 0.00000 0.750000 +14 1.00000 1.00000 0.250000 +15 1.00000 1.00000 0.750000 +16 1.00000 0.250000 1.00000 +17 1.00000 0.750000 1.00000 +18 1.00000 0.500000 0.250000 +19 1.00000 0.500000 0.750000 +20 1.00000 0.250000 0.500000 +21 1.00000 0.750000 0.500000 +22 1.00000 0.250000 0.250000 +23 1.00000 0.750000 0.250000 +24 1.00000 0.250000 0.750000 +25 1.00000 0.750000 0.750000 +$ENDNOD +$ELM +16 +1 3 1 0 4 1 10 22 12 +2 3 1 0 4 10 5 18 22 +3 3 1 0 4 12 22 20 6 +4 3 1 0 4 22 18 9 20 +5 3 1 0 4 5 11 23 18 +6 3 1 0 4 11 2 14 23 +7 3 1 0 4 18 23 21 9 +8 3 1 0 4 23 14 7 21 +9 3 1 0 4 6 20 24 13 +10 3 1 0 4 20 9 19 24 +11 3 1 0 4 13 24 16 3 +12 3 1 0 4 24 19 8 16 +13 3 1 0 4 9 21 25 19 +14 3 1 0 4 21 7 15 25 +15 3 1 0 4 19 25 17 8 +16 3 1 0 4 25 15 4 17 +$ENDELM diff --git a/tests/opencascade/circle_normal_projection.cc b/tests/opencascade/circle_normal_projection.cc index 1df8c677ccc3..77a2559403af 100644 --- a/tests/opencascade/circle_normal_projection.cc +++ b/tests/opencascade/circle_normal_projection.cc @@ -73,12 +73,13 @@ main() GridGenerator::hyper_cube(tria); // Set the exterior boundary + tria.set_all_manifold_ids(0); tria.set_manifold(0, boundary_line); // This is here to ignore the // points created in the interior // of the face. - tria.begin()->set_material_id(1); + tria.begin()->set_manifold_id(1); // We refine twice, and expect the // outer points to end up on the diff --git a/tests/opencascade/circle_normal_projection.output b/tests/opencascade/circle_normal_projection.output index 3291307f5a02..7b05605db020 100644 --- a/tests/opencascade/circle_normal_projection.output +++ b/tests/opencascade/circle_normal_projection.output @@ -25,19 +25,19 @@ 23 0.810567 0.189433 0.00000 24 0.189433 0.810567 0.00000 25 0.810567 0.810567 0.00000 -1 1 quad 1 10 22 12 -2 1 quad 10 5 18 22 -3 1 quad 12 22 20 6 -4 1 quad 22 18 9 20 -5 1 quad 5 11 23 18 -6 1 quad 11 2 14 23 -7 1 quad 18 23 21 9 -8 1 quad 23 14 7 21 -9 1 quad 6 20 24 13 -10 1 quad 20 9 19 24 -11 1 quad 13 24 16 3 -12 1 quad 24 19 8 16 -13 1 quad 9 21 25 19 -14 1 quad 21 7 15 25 -15 1 quad 19 25 17 8 -16 1 quad 25 15 4 17 +1 0 quad 1 10 22 12 +2 0 quad 10 5 18 22 +3 0 quad 12 22 20 6 +4 0 quad 22 18 9 20 +5 0 quad 5 11 23 18 +6 0 quad 11 2 14 23 +7 0 quad 18 23 21 9 +8 0 quad 23 14 7 21 +9 0 quad 6 20 24 13 +10 0 quad 20 9 19 24 +11 0 quad 13 24 16 3 +12 0 quad 24 19 8 16 +13 0 quad 9 21 25 19 +14 0 quad 21 7 15 25 +15 0 quad 19 25 17 8 +16 0 quad 25 15 4 17 diff --git a/tests/opencascade/interpolation_curve_boundary.cc b/tests/opencascade/interpolation_curve_boundary.cc index bbdaf50e46bf..55e4ec1c7d46 100644 --- a/tests/opencascade/interpolation_curve_boundary.cc +++ b/tests/opencascade/interpolation_curve_boundary.cc @@ -63,11 +63,12 @@ main() GridGenerator::hyper_cube(tria); // Set the exterior boundary + tria.set_all_manifold_ids(0); tria.set_manifold(0, boundary_line); // This is here to ignore the points created in the interior of the // face. - tria.begin()->set_material_id(1); + tria.begin()->set_manifold_id(1); // We refine twice, and expect the outer points to end up on a // smooth curve interpolating the square vertices. diff --git a/tests/opencascade/interpolation_curve_boundary.output b/tests/opencascade/interpolation_curve_boundary.output index 894bc2686080..f2609d8f092d 100644 --- a/tests/opencascade/interpolation_curve_boundary.output +++ b/tests/opencascade/interpolation_curve_boundary.output @@ -29,20 +29,20 @@ $NOD $ENDNOD $ELM 16 -1 3 1 0 4 1 10 22 12 -2 3 1 0 4 10 5 18 22 -3 3 1 0 4 12 22 20 6 -4 3 1 0 4 22 18 9 20 -5 3 1 0 4 5 11 23 18 -6 3 1 0 4 11 2 14 23 -7 3 1 0 4 18 23 21 9 -8 3 1 0 4 23 14 7 21 -9 3 1 0 4 6 20 24 13 -10 3 1 0 4 20 9 19 24 -11 3 1 0 4 13 24 16 3 -12 3 1 0 4 24 19 8 16 -13 3 1 0 4 9 21 25 19 -14 3 1 0 4 21 7 15 25 -15 3 1 0 4 19 25 17 8 -16 3 1 0 4 25 15 4 17 +1 3 0 0 4 1 10 22 12 +2 3 0 0 4 10 5 18 22 +3 3 0 0 4 12 22 20 6 +4 3 0 0 4 22 18 9 20 +5 3 0 0 4 5 11 23 18 +6 3 0 0 4 11 2 14 23 +7 3 0 0 4 18 23 21 9 +8 3 0 0 4 23 14 7 21 +9 3 0 0 4 6 20 24 13 +10 3 0 0 4 20 9 19 24 +11 3 0 0 4 13 24 16 3 +12 3 0 0 4 24 19 8 16 +13 3 0 0 4 9 21 25 19 +14 3 0 0 4 21 7 15 25 +15 3 0 0 4 19 25 17 8 +16 3 0 0 4 25 15 4 17 $ENDELM diff --git a/tests/serialization/triangulation_01.output b/tests/serialization/triangulation_01.output index 9808705bb2c7..7a0fb80a1518 100644 --- a/tests/serialization/triangulation_01.output +++ b/tests/serialization/triangulation_01.output @@ -23,12 +23,12 @@ DEAL::0 0 0 3 0 0 2 1 0 0 1 0 0 1 0 0 0 4 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 1 0 0 1 0 0 1 0 -1 1 1 0 0 0 0 1 0 0 0 4 1 2 0 3 2 0 0 2 0 0 1 0 0 0 3 1 1 1 0 0 0 1 0 0 0 0 1 0 4294967295 0 0 1 0 0 1 0 0 0 0 0 2 1 4 0 0 0 0 0 4 0 0 0 0 16 0 -1 -1 1 1 -1 -1 1 2 1 0 -1 -1 -1 -1 1 3 -1 -1 1 3 1 0 -1 -1 1 2 -1 -1 1 1 -1 -1 4 0 0 0 0 0 4 0 0 0 0 0 2 0 0 0 4 1 1 1 1 4 0 4 6 12 4 14 4 12 8 5 15 4 7 13 14 10 4 13 9 15 11 8 0 0 2 4 6 8 10 12 14 4 0 3 3 3 3 4 1 1 1 1 4 0 0 0 0 4 0 0 0 0 0 4 0 4294967295 4294967295 4294967295 4294967295 3 0 1 4 0 0 0 0 0 0 2 2 16 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 -1 -1 2 1 -1 -1 2 2 2 0 2 4 -1 -1 2 3 -1 -1 2 3 2 0 2 8 2 2 2 6 2 1 2 9 2 1 2 5 -1 -1 2 6 2 4 -1 -1 -1 -1 2 7 2 3 2 7 2 4 2 12 2 6 -1 -1 2 5 2 13 -1 -1 2 9 2 2 2 10 2 8 2 12 2 3 2 11 -1 -1 2 11 2 8 -1 -1 2 10 2 14 2 9 -1 -1 2 9 2 13 2 6 2 14 2 12 -1 -1 2 7 2 15 2 11 2 15 2 12 -1 -1 2 14 -1 -1 2 13 -1 -1 16 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 1 1 2 2 3 3 16 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 16 0 4 20 40 16 42 4 40 32 17 43 4 21 41 42 36 4 41 33 43 37 4 32 44 18 46 4 44 24 19 47 4 33 45 46 38 4 45 25 47 39 4 22 48 36 50 4 48 34 37 51 4 23 49 50 28 4 49 35 51 29 4 34 52 38 54 4 52 26 39 55 4 35 53 54 30 4 53 27 55 31 32 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 16 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 15 0 1 16 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 19 1 0 -3 0 0 0 0 56 0 0 0 2 0 1 2 0 2 2 1 3 2 2 3 2 0 4 2 4 1 2 0 5 2 5 2 2 1 6 2 6 3 2 2 7 2 7 3 2 4 8 2 8 7 2 5 8 2 8 6 2 0 9 2 9 4 2 4 10 2 10 1 2 0 11 2 11 5 2 5 12 2 12 2 2 1 13 2 13 6 2 6 14 2 14 3 2 2 15 2 15 7 2 7 16 2 16 3 2 4 17 2 17 8 2 8 18 2 18 7 2 5 19 2 19 8 2 8 20 2 20 6 2 9 21 2 21 19 2 11 21 2 21 17 2 10 22 2 22 20 2 17 22 2 22 13 2 19 23 2 23 15 2 12 23 2 23 18 2 20 24 2 24 16 2 18 24 2 24 14 56 0 4 6 8 10 16 18 20 22 24 26 28 30 32 34 36 38 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 56 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 0 0 0 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 56 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 55 0 1 0 0 56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 25 0 0 0 0 0 3 0 0 0.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 7.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 7.50000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 7.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 3 56 0 0 40 0 0 21 3 0 1 4 16 16 3 0 0 0 16 0 +3 0 0 0 0 56 0 0 0 2 0 1 2 0 2 2 1 3 2 2 3 2 0 4 2 4 1 2 0 5 2 5 2 2 1 6 2 6 3 2 2 7 2 7 3 2 4 8 2 8 7 2 5 8 2 8 6 2 0 9 2 9 4 2 4 10 2 10 1 2 0 11 2 11 5 2 5 12 2 12 2 2 1 13 2 13 6 2 6 14 2 14 3 2 2 15 2 15 7 2 7 16 2 16 3 2 4 17 2 17 8 2 8 18 2 18 7 2 5 19 2 19 8 2 8 20 2 20 6 2 9 21 2 21 19 2 11 21 2 21 17 2 10 22 2 22 20 2 17 22 2 22 13 2 19 23 2 23 15 2 12 23 2 23 18 2 20 24 2 24 16 2 18 24 2 24 14 56 0 4 6 8 10 16 18 20 22 24 26 28 30 32 34 36 38 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 56 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 0 0 0 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 56 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 55 0 1 0 0 56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 3 0 0 0.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 7.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 7.50000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 7.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 3 56 0 0 40 0 0 21 3 0 1 4 16 16 3 0 0 0 16 0 DEAL::0 0 0 3 0 0 2 1 0 0 1 0 0 1 0 0 0 6 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1 0 0 1 0 0 1 0 -1 0 0 0 0 0 1 0 0 0 6 2 3 0 4 1 5 4 0 0 2 4 6 0 0 1 0 0 0 7 1 1 1 0 0 0 1 0 0 0 0 1 0 4294967295 0 0 0 0 0 1 0 0 0 0 0 6 1 1 1 1 1 1 6 0 0 0 0 0 0 6 0 0 0 0 0 0 2 1 8 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 48 0 -1 -1 1 1 -1 -1 1 2 -1 -1 1 4 1 0 -1 -1 -1 -1 1 3 -1 -1 1 5 -1 -1 1 3 1 0 -1 -1 -1 -1 1 6 1 2 -1 -1 1 1 -1 -1 -1 -1 1 7 -1 -1 1 5 -1 -1 1 6 1 0 -1 -1 1 4 -1 -1 -1 -1 1 7 1 1 -1 -1 -1 -1 1 7 1 4 -1 -1 1 2 -1 -1 1 6 -1 -1 1 5 -1 -1 1 3 -1 -1 8 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 8 0 6 14 41 6 37 10 33 6 41 18 8 35 11 32 6 15 40 37 22 12 31 6 40 19 35 24 13 30 6 16 39 7 36 33 26 6 39 20 9 34 32 27 6 17 38 36 23 31 28 6 38 21 34 25 30 29 32 0 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 8 0 7 7 7 7 7 7 7 7 8 1 1 1 1 1 1 1 1 8 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 8 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 8 0 0 0 0 0 0 0 0 0 0 48 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 64 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 384 0 -1 -1 2 1 -1 -1 2 2 -1 -1 2 4 2 0 2 8 -1 -1 2 3 -1 -1 2 5 -1 -1 2 3 2 0 2 16 -1 -1 2 6 2 2 2 10 2 1 2 17 -1 -1 2 7 -1 -1 2 5 -1 -1 2 6 2 0 2 32 2 4 2 12 -1 -1 2 7 2 1 2 33 -1 -1 2 7 2 4 2 20 2 2 2 34 2 6 2 14 2 5 2 21 2 3 2 35 2 1 2 9 -1 -1 2 10 -1 -1 2 12 2 8 -1 -1 -1 -1 2 11 -1 -1 2 13 2 3 2 11 2 8 2 24 -1 -1 2 14 2 10 -1 -1 2 9 2 25 -1 -1 2 15 2 5 2 13 -1 -1 2 14 2 8 2 40 2 12 -1 -1 -1 -1 2 15 2 9 2 41 2 7 2 15 2 12 2 28 2 10 2 42 2 14 -1 -1 2 13 2 29 2 11 2 43 -1 -1 2 17 2 2 2 18 -1 -1 2 20 2 16 2 24 2 3 2 19 -1 -1 2 21 -1 -1 2 19 2 16 -1 -1 -1 -1 2 22 2 18 2 26 2 17 -1 -1 -1 -1 2 23 -1 -1 2 21 2 6 2 22 2 16 2 48 2 20 2 28 2 7 2 23 2 17 2 49 -1 -1 2 23 2 20 -1 -1 2 18 2 50 2 22 2 30 2 21 -1 -1 2 19 2 51 2 17 2 25 2 10 2 26 -1 -1 2 28 2 24 -1 -1 2 11 2 27 -1 -1 2 29 2 19 2 27 2 24 -1 -1 -1 -1 2 30 2 26 -1 -1 2 25 -1 -1 -1 -1 2 31 2 21 2 29 2 14 2 30 2 24 2 56 2 28 -1 -1 2 15 2 31 2 25 2 57 2 23 2 31 2 28 -1 -1 2 26 2 58 2 30 -1 -1 2 29 -1 -1 2 27 2 59 -1 -1 2 33 -1 -1 2 34 2 4 2 36 2 32 2 40 -1 -1 2 35 2 5 2 37 -1 -1 2 35 2 32 2 48 2 6 2 38 2 34 2 42 2 33 2 49 2 7 2 39 -1 -1 2 37 -1 -1 2 38 2 32 -1 -1 2 36 2 44 -1 -1 2 39 2 33 -1 -1 -1 -1 2 39 2 36 2 52 2 34 -1 -1 2 38 2 46 2 37 2 53 2 35 -1 -1 2 33 2 41 -1 -1 2 42 2 12 2 44 2 40 -1 -1 -1 -1 2 43 2 13 2 45 2 35 2 43 2 40 2 56 2 14 2 46 2 42 -1 -1 2 41 2 57 2 15 2 47 2 37 2 45 -1 -1 2 46 2 40 -1 -1 2 44 -1 -1 -1 -1 2 47 2 41 -1 -1 2 39 2 47 2 44 2 60 2 42 -1 -1 2 46 -1 -1 2 45 2 61 2 43 -1 -1 -1 -1 2 49 2 34 2 50 2 20 2 52 2 48 2 56 2 35 2 51 2 21 2 53 -1 -1 2 51 2 48 -1 -1 2 22 2 54 2 50 2 58 2 49 -1 -1 2 23 2 55 -1 -1 2 53 2 38 2 54 2 48 -1 -1 2 52 2 60 2 39 2 55 2 49 -1 -1 -1 -1 2 55 2 52 -1 -1 2 50 -1 -1 2 54 2 62 2 53 -1 -1 2 51 -1 -1 2 49 2 57 2 42 2 58 2 28 2 60 2 56 -1 -1 2 43 2 59 2 29 2 61 2 51 2 59 2 56 -1 -1 2 30 2 62 2 58 -1 -1 2 57 -1 -1 2 31 2 63 2 53 2 61 2 46 2 62 2 56 -1 -1 2 60 -1 -1 2 47 2 63 2 57 -1 -1 2 55 2 63 2 60 -1 -1 2 58 -1 -1 2 62 -1 -1 2 61 -1 -1 2 59 -1 -1 64 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 0 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5 5 5 5 6 6 6 6 7 7 7 7 0 64 0 6 74 281 42 277 58 273 6 281 182 44 275 59 272 6 75 280 277 166 60 271 6 280 183 275 168 61 270 6 76 279 43 276 273 150 6 279 184 45 274 272 151 6 77 278 276 167 271 152 6 278 185 274 169 270 153 6 182 269 50 265 62 261 6 269 90 52 263 63 260 6 183 268 265 158 64 259 6 268 91 263 160 65 258 6 184 267 51 264 261 146 6 267 92 53 262 260 147 6 185 266 264 159 259 148 6 266 93 262 161 258 149 6 78 257 166 253 66 249 6 257 178 168 251 67 248 6 79 256 253 106 68 247 6 256 179 251 108 69 246 6 80 255 167 252 249 142 6 255 180 169 250 248 143 6 81 254 252 107 247 144 6 254 181 250 109 246 145 6 178 245 158 241 70 237 6 245 94 160 239 71 236 6 179 244 241 114 72 235 6 244 95 239 116 73 234 6 180 243 159 240 237 138 6 243 96 161 238 236 139 6 181 242 240 115 235 140 6 242 97 238 117 234 141 6 82 233 46 229 150 225 6 233 174 48 227 151 224 6 83 232 229 162 152 223 6 232 175 227 164 153 222 6 84 231 47 228 225 122 6 231 176 49 226 224 123 6 85 230 228 163 223 124 6 230 177 226 165 222 125 6 174 221 54 217 146 213 6 221 98 56 215 147 212 6 175 220 217 154 148 211 6 220 99 215 156 149 210 6 176 219 55 216 213 126 6 219 100 57 214 212 127 6 177 218 216 155 211 128 6 218 101 214 157 210 129 6 86 209 162 205 142 201 6 209 170 164 203 143 200 6 87 208 205 110 144 199 6 208 171 203 112 145 198 6 88 207 163 204 201 130 6 207 172 165 202 200 131 6 89 206 204 111 199 132 6 206 173 202 113 198 133 6 170 197 154 193 138 189 6 197 102 156 191 139 188 6 171 196 193 118 140 187 6 196 103 191 120 141 186 6 172 195 155 192 189 134 6 195 104 157 190 188 135 6 173 194 192 119 187 136 6 194 105 190 121 186 137 256 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 64 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 64 0 64 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 384 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 384 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 384 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 1 0 -3 0 0 0 0 282 0 0 0 4 0 8 2 4 4 1 3 0 5 4 2 6 1 9 4 4 7 3 10 4 5 11 6 7 4 9 10 8 11 4 12 36 16 38 4 36 28 17 39 4 13 37 38 20 4 37 29 39 21 4 14 40 12 42 4 40 18 13 43 4 15 41 42 22 4 41 19 43 23 4 16 44 14 46 4 44 24 15 47 4 17 45 46 30 4 45 25 47 31 4 20 48 18 50 4 48 26 19 51 4 21 49 50 32 4 49 27 51 33 4 22 52 24 54 4 52 34 25 55 4 23 53 54 26 4 53 35 55 27 4 30 56 28 58 4 56 32 29 59 4 31 57 58 34 4 57 33 59 35 4 64 51 62 53 4 47 64 63 52 4 65 50 37 62 4 46 65 36 63 4 62 59 60 49 4 43 62 61 48 4 63 58 45 60 4 42 63 44 61 4 60 55 64 57 4 39 60 65 56 4 61 54 41 64 4 38 61 40 65 4 66 174 74 176 4 174 114 75 177 4 67 175 176 118 4 175 115 177 119 4 114 178 76 180 4 178 98 77 181 4 115 179 180 120 4 179 99 181 121 4 68 182 118 184 4 182 116 119 185 4 69 183 184 82 4 183 117 185 83 4 116 186 120 188 4 186 100 121 189 4 117 187 188 84 4 187 101 189 85 4 70 190 66 192 4 190 122 67 193 4 71 191 192 126 4 191 123 193 127 4 122 194 68 196 4 194 78 69 197 4 123 195 196 128 4 195 79 197 129 4 72 198 126 200 4 198 124 127 201 4 73 199 200 86 4 199 125 201 87 4 124 202 128 204 4 202 80 129 205 4 125 203 204 88 4 203 81 205 89 4 74 206 70 208 4 206 130 71 209 4 75 207 208 134 4 207 131 209 135 4 130 210 72 212 4 210 90 73 213 4 131 211 212 136 4 211 91 213 137 4 76 214 134 216 4 214 132 135 217 4 77 215 216 102 4 215 133 217 103 4 132 218 136 220 4 218 92 137 221 4 133 219 220 104 4 219 93 221 105 4 82 222 78 224 4 222 138 79 225 4 83 223 224 142 4 223 139 225 143 4 138 226 80 228 4 226 94 81 229 4 139 227 228 144 4 227 95 229 145 4 84 230 142 232 4 230 140 143 233 4 85 231 232 106 4 231 141 233 107 4 140 234 144 236 4 234 96 145 237 4 141 235 236 108 4 235 97 237 109 4 86 238 90 240 4 238 146 91 241 4 87 239 240 150 4 239 147 241 151 4 146 242 92 244 4 242 110 93 245 4 147 243 244 152 4 243 111 245 153 4 88 246 150 248 4 246 148 151 249 4 89 247 248 94 4 247 149 249 95 4 148 250 152 252 4 250 112 153 253 4 149 251 252 96 4 251 113 253 97 4 102 254 98 256 4 254 154 99 257 4 103 255 256 158 4 255 155 257 159 4 154 258 100 260 4 258 106 101 261 4 155 259 260 160 4 259 107 261 161 4 104 262 158 264 4 262 156 159 265 4 105 263 264 110 4 263 157 265 111 4 156 266 160 268 4 266 108 161 269 4 157 267 268 112 4 267 109 269 113 4 170 270 166 272 4 270 144 167 273 4 171 271 272 148 4 271 145 273 149 4 136 274 168 276 4 274 170 169 277 4 137 275 276 146 4 275 171 277 147 4 172 278 116 280 4 278 142 117 281 4 173 279 280 166 4 279 143 281 167 4 134 282 114 284 4 282 172 115 285 4 135 283 284 168 4 283 173 285 169 4 166 286 162 288 4 286 160 163 289 4 167 287 288 140 4 287 161 289 141 4 128 290 164 292 4 290 166 165 293 4 129 291 292 138 4 291 167 293 139 4 168 294 132 296 4 294 158 133 297 4 169 295 296 162 4 295 159 297 163 4 126 298 130 300 4 298 168 131 301 4 127 299 300 164 4 299 169 301 165 4 162 302 170 304 4 302 152 171 305 4 163 303 304 156 4 303 153 305 157 4 120 306 172 308 4 306 162 173 309 4 121 307 308 154 4 307 163 309 155 4 164 310 124 312 4 310 150 125 313 4 165 311 312 170 4 311 151 313 171 4 118 314 122 316 4 314 164 123 317 4 119 315 316 172 4 315 165 317 173 4 322 237 320 251 4 305 322 321 250 4 323 236 287 320 4 304 323 286 321 4 320 269 318 235 4 273 320 319 234 4 321 268 303 318 4 272 321 302 319 4 318 253 322 267 4 289 318 323 266 4 319 252 271 322 4 288 319 270 323 4 328 305 326 243 4 221 328 327 242 4 329 304 295 326 4 220 329 294 327 4 326 265 324 303 4 277 326 325 302 4 327 264 219 324 4 276 327 218 325 4 324 245 328 263 4 297 324 329 262 4 325 244 275 328 4 296 325 274 329 4 334 233 332 287 4 309 334 333 286 4 335 232 187 332 4 308 335 186 333 4 332 261 330 231 4 281 332 331 230 4 333 260 307 330 4 280 333 306 331 4 330 289 334 259 4 189 330 335 258 4 331 288 279 334 4 188 331 278 335 4 340 309 338 295 4 217 340 339 294 4 341 308 179 338 4 216 341 178 339 4 338 257 336 307 4 285 338 337 306 4 339 256 215 336 4 284 339 214 337 4 336 297 340 255 4 181 336 341 254 4 337 296 283 340 4 180 337 282 341 4 346 229 344 247 4 313 346 345 246 4 347 228 291 344 4 312 347 290 345 4 344 273 342 227 4 205 344 343 226 4 345 272 311 342 4 204 345 310 343 4 342 249 346 271 4 293 342 347 270 4 343 248 203 346 4 292 343 202 347 4 352 313 350 239 4 213 352 351 238 4 353 312 299 350 4 212 353 298 351 4 350 277 348 311 4 201 350 349 310 4 351 276 211 348 4 200 351 210 349 4 348 241 352 275 4 301 348 353 274 4 349 240 199 352 4 300 349 198 353 4 358 225 356 291 4 317 358 357 290 4 359 224 183 356 4 316 359 182 357 4 356 281 354 223 4 197 356 355 222 4 357 280 315 354 4 196 357 314 355 4 354 293 358 279 4 185 354 359 278 4 355 292 195 358 4 184 355 194 359 4 364 317 362 299 4 209 364 363 298 4 365 316 175 362 4 208 365 174 363 4 362 285 360 315 4 193 362 361 314 4 363 284 207 360 4 192 363 206 361 4 360 301 364 283 4 177 360 365 282 4 361 300 191 364 4 176 361 190 365 564 0 6 8 10 12 14 16 18 20 22 24 26 28 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 104 106 108 110 112 114 116 118 120 122 124 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 156 158 160 162 164 166 168 170 172 174 176 178 180 182 184 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 282 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 282 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 0 0 0 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 282 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 185 186 1 0 0 282 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1128 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 366 0 0 0 2 0 1 2 0 2 2 0 4 2 1 3 2 1 5 2 2 3 2 2 6 2 3 7 2 4 5 2 4 6 2 5 7 2 6 7 2 0 8 2 8 1 2 0 9 2 9 2 2 0 10 2 10 4 2 1 11 2 11 3 2 1 12 2 12 5 2 2 13 2 13 3 2 2 14 2 14 6 2 3 15 2 15 7 2 4 16 2 16 5 2 4 17 2 17 6 2 5 18 2 18 7 2 6 19 2 19 7 2 10 20 2 20 12 2 8 20 2 20 16 2 8 21 2 21 13 2 9 21 2 21 11 2 9 22 2 22 17 2 10 22 2 22 14 2 11 23 2 23 18 2 12 23 2 23 15 2 14 24 2 24 15 2 13 24 2 24 19 2 16 25 2 25 19 2 17 25 2 25 18 2 26 25 2 21 26 2 26 23 2 22 26 2 26 24 2 20 26 2 0 27 2 27 8 2 8 28 2 28 1 2 0 29 2 29 9 2 9 30 2 30 2 2 0 31 2 31 10 2 10 32 2 32 4 2 1 33 2 33 11 2 11 34 2 34 3 2 1 35 2 35 12 2 12 36 2 36 5 2 2 37 2 37 13 2 13 38 2 38 3 2 2 39 2 39 14 2 14 40 2 40 6 2 3 41 2 41 15 2 15 42 2 42 7 2 4 43 2 43 16 2 16 44 2 44 5 2 4 45 2 45 17 2 17 46 2 46 6 2 5 47 2 47 18 2 18 48 2 48 7 2 6 49 2 49 19 2 19 50 2 50 7 2 10 51 2 51 20 2 20 52 2 52 12 2 8 53 2 53 20 2 20 54 2 54 16 2 8 55 2 55 21 2 21 56 2 56 13 2 9 57 2 57 21 2 21 58 2 58 11 2 9 59 2 59 22 2 22 60 2 60 17 2 10 61 2 61 22 2 22 62 2 62 14 2 11 63 2 63 23 2 23 64 2 64 18 2 12 65 2 65 23 2 23 66 2 66 15 2 14 67 2 67 24 2 24 68 2 68 15 2 13 69 2 69 24 2 24 70 2 70 19 2 16 71 2 71 25 2 25 72 2 72 19 2 17 73 2 73 25 2 25 74 2 74 18 2 26 75 2 75 25 2 21 76 2 76 26 2 26 77 2 77 23 2 22 78 2 78 26 2 26 79 2 79 24 2 20 80 2 80 26 2 31 81 2 81 53 2 27 81 2 81 51 2 32 82 2 82 54 2 51 82 2 82 43 2 53 83 2 83 35 2 28 83 2 83 52 2 54 84 2 84 36 2 52 84 2 84 44 2 27 85 2 85 57 2 29 85 2 85 55 2 28 86 2 86 58 2 55 86 2 86 33 2 57 87 2 87 37 2 30 87 2 87 56 2 58 88 2 88 38 2 56 88 2 88 34 2 29 89 2 89 61 2 31 89 2 89 59 2 30 90 2 90 62 2 59 90 2 90 39 2 61 91 2 91 45 2 32 91 2 91 60 2 62 92 2 92 46 2 60 92 2 92 40 2 33 93 2 93 65 2 35 93 2 93 63 2 34 94 2 94 66 2 63 94 2 94 41 2 65 95 2 95 47 2 36 95 2 95 64 2 66 96 2 96 48 2 64 96 2 96 42 2 39 97 2 97 69 2 37 97 2 97 67 2 40 98 2 98 70 2 67 98 2 98 49 2 69 99 2 99 41 2 38 99 2 99 68 2 70 100 2 100 42 2 68 100 2 100 50 2 43 101 2 101 73 2 45 101 2 101 71 2 44 102 2 102 74 2 71 102 2 102 47 2 73 103 2 103 49 2 46 103 2 103 72 2 74 104 2 104 50 2 72 104 2 104 48 2 77 105 2 105 68 2 79 105 2 105 66 2 78 106 2 106 67 2 62 106 2 106 79 2 52 107 2 107 77 2 80 107 2 107 65 2 51 108 2 108 78 2 61 108 2 108 80 2 75 109 2 109 64 2 77 109 2 109 74 2 76 110 2 110 63 2 58 110 2 110 77 2 60 111 2 111 75 2 78 111 2 111 73 2 59 112 2 112 76 2 57 112 2 112 78 2 79 113 2 113 72 2 75 113 2 113 70 2 80 114 2 114 71 2 54 114 2 114 75 2 56 115 2 115 79 2 76 115 2 115 69 2 55 116 2 116 80 2 53 116 2 116 76 2 124 104 2 105 124 2 124 96 2 113 124 2 124 100 2 109 124 2 123 103 2 106 123 2 123 113 2 92 123 2 123 98 2 111 123 2 122 102 2 107 122 2 122 95 2 114 122 2 122 109 2 84 122 2 121 101 2 108 121 2 121 114 2 91 121 2 121 111 2 82 121 2 120 105 2 88 120 2 120 94 2 115 120 2 120 99 2 110 120 2 119 106 2 87 119 2 119 115 2 90 119 2 119 97 2 112 119 2 118 107 2 86 118 2 118 93 2 116 118 2 118 110 2 83 118 2 117 108 2 85 117 2 117 116 2 89 117 2 117 112 2 81 117 366 0 12 14 16 18 20 22 24 26 28 30 32 34 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 104 106 108 110 112 114 116 118 120 122 124 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 156 158 160 162 164 166 168 170 172 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 366 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 366 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 317 318 1 0 0 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 125 0 0 0 0 0 3 0 0 0.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 1.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 1.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 1.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 1.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 5.00000000000000000e-01 3 1.00000000000000000e+00 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 1.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000111e-01 5.00000000000000111e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 7.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 7.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 2.50000000000000000e-01 3 0.00000000000000000e+00 0.00000000000000000e+00 7.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 7.50000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 2.50000000000000000e-01 3 1.00000000000000000e+00 0.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 7.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 2.50000000000000000e-01 3 0.00000000000000000e+00 1.00000000000000000e+00 7.50000000000000000e-01 3 1.00000000000000000e+00 1.00000000000000000e+00 2.50000000000000000e-01 3 1.00000000000000000e+00 1.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 1.00000000000000000e+00 3 7.50000000000000000e-01 0.00000000000000000e+00 1.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 1.00000000000000000e+00 3 0.00000000000000000e+00 7.50000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 2.50000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 7.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 7.50000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 2.50000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 5.00000000000000000e-01 7.50000000000000000e-01 3 0.00000000000000000e+00 2.50000000000000000e-01 5.00000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 2.50000000000000056e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000056e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 2.50000000000000000e-01 7.50000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 7.50000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 2.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000056e-01 2.50000000000000056e-01 3 7.50000000000000000e-01 2.50000000000000056e-01 2.50000000000000056e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 2.50000000000000056e-01 3 7.50000000000000000e-01 7.50000000000000000e-01 2.50000000000000056e-01 3 2.50000000000000000e-01 2.50000000000000056e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 2.50000000000000056e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 125 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 3 366 0 0 300 0 0 282 0 0 240 0 0 73 3 0 1 8 64 64 3 0 0 0 64 0 +3 0 0 0 0 282 0 0 0 4 0 8 2 4 4 1 3 0 5 4 2 6 1 9 4 4 7 3 10 4 5 11 6 7 4 9 10 8 11 4 12 36 16 38 4 36 28 17 39 4 13 37 38 20 4 37 29 39 21 4 14 40 12 42 4 40 18 13 43 4 15 41 42 22 4 41 19 43 23 4 16 44 14 46 4 44 24 15 47 4 17 45 46 30 4 45 25 47 31 4 20 48 18 50 4 48 26 19 51 4 21 49 50 32 4 49 27 51 33 4 22 52 24 54 4 52 34 25 55 4 23 53 54 26 4 53 35 55 27 4 30 56 28 58 4 56 32 29 59 4 31 57 58 34 4 57 33 59 35 4 64 51 62 53 4 47 64 63 52 4 65 50 37 62 4 46 65 36 63 4 62 59 60 49 4 43 62 61 48 4 63 58 45 60 4 42 63 44 61 4 60 55 64 57 4 39 60 65 56 4 61 54 41 64 4 38 61 40 65 4 66 174 74 176 4 174 114 75 177 4 67 175 176 118 4 175 115 177 119 4 114 178 76 180 4 178 98 77 181 4 115 179 180 120 4 179 99 181 121 4 68 182 118 184 4 182 116 119 185 4 69 183 184 82 4 183 117 185 83 4 116 186 120 188 4 186 100 121 189 4 117 187 188 84 4 187 101 189 85 4 70 190 66 192 4 190 122 67 193 4 71 191 192 126 4 191 123 193 127 4 122 194 68 196 4 194 78 69 197 4 123 195 196 128 4 195 79 197 129 4 72 198 126 200 4 198 124 127 201 4 73 199 200 86 4 199 125 201 87 4 124 202 128 204 4 202 80 129 205 4 125 203 204 88 4 203 81 205 89 4 74 206 70 208 4 206 130 71 209 4 75 207 208 134 4 207 131 209 135 4 130 210 72 212 4 210 90 73 213 4 131 211 212 136 4 211 91 213 137 4 76 214 134 216 4 214 132 135 217 4 77 215 216 102 4 215 133 217 103 4 132 218 136 220 4 218 92 137 221 4 133 219 220 104 4 219 93 221 105 4 82 222 78 224 4 222 138 79 225 4 83 223 224 142 4 223 139 225 143 4 138 226 80 228 4 226 94 81 229 4 139 227 228 144 4 227 95 229 145 4 84 230 142 232 4 230 140 143 233 4 85 231 232 106 4 231 141 233 107 4 140 234 144 236 4 234 96 145 237 4 141 235 236 108 4 235 97 237 109 4 86 238 90 240 4 238 146 91 241 4 87 239 240 150 4 239 147 241 151 4 146 242 92 244 4 242 110 93 245 4 147 243 244 152 4 243 111 245 153 4 88 246 150 248 4 246 148 151 249 4 89 247 248 94 4 247 149 249 95 4 148 250 152 252 4 250 112 153 253 4 149 251 252 96 4 251 113 253 97 4 102 254 98 256 4 254 154 99 257 4 103 255 256 158 4 255 155 257 159 4 154 258 100 260 4 258 106 101 261 4 155 259 260 160 4 259 107 261 161 4 104 262 158 264 4 262 156 159 265 4 105 263 264 110 4 263 157 265 111 4 156 266 160 268 4 266 108 161 269 4 157 267 268 112 4 267 109 269 113 4 170 270 166 272 4 270 144 167 273 4 171 271 272 148 4 271 145 273 149 4 136 274 168 276 4 274 170 169 277 4 137 275 276 146 4 275 171 277 147 4 172 278 116 280 4 278 142 117 281 4 173 279 280 166 4 279 143 281 167 4 134 282 114 284 4 282 172 115 285 4 135 283 284 168 4 283 173 285 169 4 166 286 162 288 4 286 160 163 289 4 167 287 288 140 4 287 161 289 141 4 128 290 164 292 4 290 166 165 293 4 129 291 292 138 4 291 167 293 139 4 168 294 132 296 4 294 158 133 297 4 169 295 296 162 4 295 159 297 163 4 126 298 130 300 4 298 168 131 301 4 127 299 300 164 4 299 169 301 165 4 162 302 170 304 4 302 152 171 305 4 163 303 304 156 4 303 153 305 157 4 120 306 172 308 4 306 162 173 309 4 121 307 308 154 4 307 163 309 155 4 164 310 124 312 4 310 150 125 313 4 165 311 312 170 4 311 151 313 171 4 118 314 122 316 4 314 164 123 317 4 119 315 316 172 4 315 165 317 173 4 322 237 320 251 4 305 322 321 250 4 323 236 287 320 4 304 323 286 321 4 320 269 318 235 4 273 320 319 234 4 321 268 303 318 4 272 321 302 319 4 318 253 322 267 4 289 318 323 266 4 319 252 271 322 4 288 319 270 323 4 328 305 326 243 4 221 328 327 242 4 329 304 295 326 4 220 329 294 327 4 326 265 324 303 4 277 326 325 302 4 327 264 219 324 4 276 327 218 325 4 324 245 328 263 4 297 324 329 262 4 325 244 275 328 4 296 325 274 329 4 334 233 332 287 4 309 334 333 286 4 335 232 187 332 4 308 335 186 333 4 332 261 330 231 4 281 332 331 230 4 333 260 307 330 4 280 333 306 331 4 330 289 334 259 4 189 330 335 258 4 331 288 279 334 4 188 331 278 335 4 340 309 338 295 4 217 340 339 294 4 341 308 179 338 4 216 341 178 339 4 338 257 336 307 4 285 338 337 306 4 339 256 215 336 4 284 339 214 337 4 336 297 340 255 4 181 336 341 254 4 337 296 283 340 4 180 337 282 341 4 346 229 344 247 4 313 346 345 246 4 347 228 291 344 4 312 347 290 345 4 344 273 342 227 4 205 344 343 226 4 345 272 311 342 4 204 345 310 343 4 342 249 346 271 4 293 342 347 270 4 343 248 203 346 4 292 343 202 347 4 352 313 350 239 4 213 352 351 238 4 353 312 299 350 4 212 353 298 351 4 350 277 348 311 4 201 350 349 310 4 351 276 211 348 4 200 351 210 349 4 348 241 352 275 4 301 348 353 274 4 349 240 199 352 4 300 349 198 353 4 358 225 356 291 4 317 358 357 290 4 359 224 183 356 4 316 359 182 357 4 356 281 354 223 4 197 356 355 222 4 357 280 315 354 4 196 357 314 355 4 354 293 358 279 4 185 354 359 278 4 355 292 195 358 4 184 355 194 359 4 364 317 362 299 4 209 364 363 298 4 365 316 175 362 4 208 365 174 363 4 362 285 360 315 4 193 362 361 314 4 363 284 207 360 4 192 363 206 361 4 360 301 364 283 4 177 360 365 282 4 361 300 191 364 4 176 361 190 365 564 0 6 8 10 12 14 16 18 20 22 24 26 28 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 104 106 108 110 112 114 116 118 120 122 124 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 156 158 160 162 164 166 168 170 172 174 176 178 180 182 184 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 282 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 282 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 0 0 0 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 282 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 185 186 1 0 0 282 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1128 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 366 0 0 0 2 0 1 2 0 2 2 0 4 2 1 3 2 1 5 2 2 3 2 2 6 2 3 7 2 4 5 2 4 6 2 5 7 2 6 7 2 0 8 2 8 1 2 0 9 2 9 2 2 0 10 2 10 4 2 1 11 2 11 3 2 1 12 2 12 5 2 2 13 2 13 3 2 2 14 2 14 6 2 3 15 2 15 7 2 4 16 2 16 5 2 4 17 2 17 6 2 5 18 2 18 7 2 6 19 2 19 7 2 10 20 2 20 12 2 8 20 2 20 16 2 8 21 2 21 13 2 9 21 2 21 11 2 9 22 2 22 17 2 10 22 2 22 14 2 11 23 2 23 18 2 12 23 2 23 15 2 14 24 2 24 15 2 13 24 2 24 19 2 16 25 2 25 19 2 17 25 2 25 18 2 26 25 2 21 26 2 26 23 2 22 26 2 26 24 2 20 26 2 0 27 2 27 8 2 8 28 2 28 1 2 0 29 2 29 9 2 9 30 2 30 2 2 0 31 2 31 10 2 10 32 2 32 4 2 1 33 2 33 11 2 11 34 2 34 3 2 1 35 2 35 12 2 12 36 2 36 5 2 2 37 2 37 13 2 13 38 2 38 3 2 2 39 2 39 14 2 14 40 2 40 6 2 3 41 2 41 15 2 15 42 2 42 7 2 4 43 2 43 16 2 16 44 2 44 5 2 4 45 2 45 17 2 17 46 2 46 6 2 5 47 2 47 18 2 18 48 2 48 7 2 6 49 2 49 19 2 19 50 2 50 7 2 10 51 2 51 20 2 20 52 2 52 12 2 8 53 2 53 20 2 20 54 2 54 16 2 8 55 2 55 21 2 21 56 2 56 13 2 9 57 2 57 21 2 21 58 2 58 11 2 9 59 2 59 22 2 22 60 2 60 17 2 10 61 2 61 22 2 22 62 2 62 14 2 11 63 2 63 23 2 23 64 2 64 18 2 12 65 2 65 23 2 23 66 2 66 15 2 14 67 2 67 24 2 24 68 2 68 15 2 13 69 2 69 24 2 24 70 2 70 19 2 16 71 2 71 25 2 25 72 2 72 19 2 17 73 2 73 25 2 25 74 2 74 18 2 26 75 2 75 25 2 21 76 2 76 26 2 26 77 2 77 23 2 22 78 2 78 26 2 26 79 2 79 24 2 20 80 2 80 26 2 31 81 2 81 53 2 27 81 2 81 51 2 32 82 2 82 54 2 51 82 2 82 43 2 53 83 2 83 35 2 28 83 2 83 52 2 54 84 2 84 36 2 52 84 2 84 44 2 27 85 2 85 57 2 29 85 2 85 55 2 28 86 2 86 58 2 55 86 2 86 33 2 57 87 2 87 37 2 30 87 2 87 56 2 58 88 2 88 38 2 56 88 2 88 34 2 29 89 2 89 61 2 31 89 2 89 59 2 30 90 2 90 62 2 59 90 2 90 39 2 61 91 2 91 45 2 32 91 2 91 60 2 62 92 2 92 46 2 60 92 2 92 40 2 33 93 2 93 65 2 35 93 2 93 63 2 34 94 2 94 66 2 63 94 2 94 41 2 65 95 2 95 47 2 36 95 2 95 64 2 66 96 2 96 48 2 64 96 2 96 42 2 39 97 2 97 69 2 37 97 2 97 67 2 40 98 2 98 70 2 67 98 2 98 49 2 69 99 2 99 41 2 38 99 2 99 68 2 70 100 2 100 42 2 68 100 2 100 50 2 43 101 2 101 73 2 45 101 2 101 71 2 44 102 2 102 74 2 71 102 2 102 47 2 73 103 2 103 49 2 46 103 2 103 72 2 74 104 2 104 50 2 72 104 2 104 48 2 77 105 2 105 68 2 79 105 2 105 66 2 78 106 2 106 67 2 62 106 2 106 79 2 52 107 2 107 77 2 80 107 2 107 65 2 51 108 2 108 78 2 61 108 2 108 80 2 75 109 2 109 64 2 77 109 2 109 74 2 76 110 2 110 63 2 58 110 2 110 77 2 60 111 2 111 75 2 78 111 2 111 73 2 59 112 2 112 76 2 57 112 2 112 78 2 79 113 2 113 72 2 75 113 2 113 70 2 80 114 2 114 71 2 54 114 2 114 75 2 56 115 2 115 79 2 76 115 2 115 69 2 55 116 2 116 80 2 53 116 2 116 76 2 124 104 2 105 124 2 124 96 2 113 124 2 124 100 2 109 124 2 123 103 2 106 123 2 123 113 2 92 123 2 123 98 2 111 123 2 122 102 2 107 122 2 122 95 2 114 122 2 122 109 2 84 122 2 121 101 2 108 121 2 121 114 2 91 121 2 121 111 2 82 121 2 120 105 2 88 120 2 120 94 2 115 120 2 120 99 2 110 120 2 119 106 2 87 119 2 119 115 2 90 119 2 119 97 2 112 119 2 118 107 2 86 118 2 118 93 2 116 118 2 118 110 2 83 118 2 117 108 2 85 117 2 117 116 2 89 117 2 117 112 2 81 117 366 0 12 14 16 18 20 22 24 26 28 30 32 34 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 104 106 108 110 112 114 116 118 120 122 124 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 156 158 160 162 164 166 168 170 172 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 366 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 366 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 317 318 1 0 0 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 125 0 0 0 0 0 3 0 0 0.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 1.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 1.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 1.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 1.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 5.00000000000000000e-01 3 1.00000000000000000e+00 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 1.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 7.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 7.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 2.50000000000000000e-01 3 0.00000000000000000e+00 0.00000000000000000e+00 7.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 7.50000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 2.50000000000000000e-01 3 1.00000000000000000e+00 0.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 7.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 2.50000000000000000e-01 3 0.00000000000000000e+00 1.00000000000000000e+00 7.50000000000000000e-01 3 1.00000000000000000e+00 1.00000000000000000e+00 2.50000000000000000e-01 3 1.00000000000000000e+00 1.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 1.00000000000000000e+00 3 7.50000000000000000e-01 0.00000000000000000e+00 1.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 1.00000000000000000e+00 3 0.00000000000000000e+00 7.50000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 2.50000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 7.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 7.50000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 2.50000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 5.00000000000000000e-01 7.50000000000000000e-01 3 0.00000000000000000e+00 2.50000000000000000e-01 5.00000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 2.50000000000000000e-01 7.50000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 7.50000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 2.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 2.50000000000000000e-01 3 7.50000000000000000e-01 2.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 2.50000000000000000e-01 3 7.50000000000000000e-01 7.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 2.50000000000000000e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 125 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 3 366 0 0 300 0 0 282 0 0 240 0 0 73 3 0 1 8 64 64 3 0 0 0 64 0 DEAL::OK diff --git a/tests/serialization/triangulation_02.output b/tests/serialization/triangulation_02.output index 4b31b19f3592..a88c705ebd68 100644 --- a/tests/serialization/triangulation_02.output +++ b/tests/serialization/triangulation_02.output @@ -23,12 +23,12 @@ DEAL::0 0 0 3 0 0 2 1 0 0 1 0 0 1 0 0 0 4 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 1 0 0 1 0 0 1 0 -1 1 1 0 0 0 0 1 0 0 0 4 1 2 0 3 2 0 0 2 0 0 1 0 0 0 3 1 1 1 0 0 0 1 0 0 0 0 1 0 4294967295 0 0 1 0 0 1 0 0 0 0 0 2 1 4 0 0 1 0 0 4 0 0 0 0 16 0 -1 -1 1 1 -1 -1 1 2 1 0 -1 -1 -1 -1 1 3 -1 -1 1 3 1 0 -1 -1 1 2 -1 -1 1 1 -1 -1 4 0 0 1 0 0 4 0 0 4 0 0 2 0 0 0 4 1 1 1 1 4 0 4 6 12 4 14 4 12 8 5 15 4 7 13 14 10 4 13 9 15 11 8 0 0 2 -1 -1 -1 -1 -1 -1 4 0 3 0 0 0 4 1 1 1 1 4 0 1 0 0 4 0 0 2 0 0 4 0 4294967295 4294967295 4294967295 4294967295 3 0 1 4 0 0 3 0 0 2 2 2 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 -1 -1 2 1 -1 -1 2 2 2 0 1 1 -1 -1 2 3 -1 -1 2 3 2 0 1 2 2 2 1 1 2 1 1 2 2 1 2 5 -1 -1 2 6 2 4 -1 -1 -1 -1 2 7 2 3 2 7 2 4 2 12 2 6 -1 -1 2 5 2 13 -1 -1 2 9 2 2 2 10 2 8 2 12 2 3 2 11 -1 -1 2 11 2 8 -1 -1 2 10 2 14 2 9 -1 -1 2 9 2 13 2 6 2 14 2 12 -1 -1 2 7 2 15 2 11 2 15 2 12 -1 -1 2 14 -1 -1 2 13 -1 -1 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 1 1 2 2 3 3 16 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 16 0 4 18 24 16 26 4 24 20 17 27 4 19 25 26 22 4 25 21 27 23 4 32 44 18 46 4 44 24 19 47 4 33 45 46 38 4 45 25 47 39 4 22 48 36 50 4 48 34 37 51 4 23 49 50 28 4 49 35 51 29 4 34 52 38 54 4 52 26 39 55 4 35 53 54 30 4 53 27 55 31 32 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 3 2 1 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 1 0 -3 0 0 0 0 56 0 0 0 2 0 1 2 0 2 2 1 3 2 2 3 2 0 4 2 4 1 2 0 5 2 5 2 2 1 6 2 6 3 2 2 7 2 7 3 2 4 8 2 8 7 2 5 8 2 8 6 2 0 9 2 9 4 2 0 10 2 10 5 2 4 11 2 11 8 2 5 12 2 12 8 2 9 13 2 13 12 2 10 13 2 13 11 2 2 15 2 15 7 2 7 16 2 16 3 2 4 17 2 17 8 2 8 18 2 18 7 2 5 19 2 19 8 2 8 20 2 20 6 2 9 21 2 21 19 2 11 21 2 21 17 2 10 22 2 22 20 2 17 22 2 22 13 2 19 23 2 23 15 2 12 23 2 23 18 2 20 24 2 24 16 2 18 24 2 24 14 56 0 4 6 8 10 16 -1 18 -1 -1 -1 -1 -1 20 -1 22 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 56 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 0 0 0 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 56 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 27 24 1 0 0 56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 25 0 0 0 0 0 3 0 0 0.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 7.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 28 0 0 20 0 0 9 3 0 1 4 4 7 3 0 0 3 4 0 +3 0 0 0 0 56 0 0 0 2 0 1 2 0 2 2 1 3 2 2 3 2 0 4 2 4 1 2 0 5 2 5 2 2 1 6 2 6 3 2 2 7 2 7 3 2 4 8 2 8 7 2 5 8 2 8 6 2 0 9 2 9 4 2 0 10 2 10 5 2 4 11 2 11 8 2 5 12 2 12 8 2 9 13 2 13 12 2 10 13 2 13 11 2 2 15 2 15 7 2 7 16 2 16 3 2 4 17 2 17 8 2 8 18 2 18 7 2 5 19 2 19 8 2 8 20 2 20 6 2 9 21 2 21 19 2 11 21 2 21 17 2 10 22 2 22 20 2 17 22 2 22 13 2 19 23 2 23 15 2 12 23 2 23 18 2 20 24 2 24 16 2 18 24 2 24 14 56 0 4 6 8 10 16 -1 18 -1 -1 -1 -1 -1 20 -1 22 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 56 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 0 0 0 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 56 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 27 24 1 0 0 56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 3 0 0 0.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 7.50000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 28 0 0 20 0 0 9 3 0 1 4 4 7 3 0 0 3 4 0 DEAL::0 0 0 3 0 0 2 1 0 0 1 0 0 1 0 0 0 6 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1 0 0 1 0 0 1 0 -1 0 0 0 0 0 1 0 0 0 6 2 3 0 4 1 5 4 0 0 2 4 6 0 0 1 0 0 0 7 1 1 1 0 0 0 1 0 0 0 0 1 0 4294967295 0 0 0 0 0 1 0 0 0 0 0 6 1 1 1 1 1 1 6 0 0 0 0 0 0 6 0 0 0 0 0 0 2 1 8 0 0 1 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 48 0 -1 -1 1 1 -1 -1 1 2 -1 -1 1 4 1 0 -1 -1 -1 -1 1 3 -1 -1 1 5 -1 -1 1 3 1 0 -1 -1 -1 -1 1 6 1 2 -1 -1 1 1 -1 -1 -1 -1 1 7 -1 -1 1 5 -1 -1 1 6 1 0 -1 -1 1 4 -1 -1 -1 -1 1 7 1 1 -1 -1 -1 -1 1 7 1 4 -1 -1 1 2 -1 -1 1 6 -1 -1 1 5 -1 -1 1 3 -1 -1 8 0 0 1 0 0 0 0 0 0 8 0 0 4 0 0 0 0 0 0 4 0 0 0 0 0 0 8 0 6 14 41 6 37 10 33 6 41 18 8 35 11 32 6 15 40 37 22 12 31 6 40 19 35 24 13 30 6 16 39 7 36 33 26 6 39 20 9 34 32 27 6 17 38 36 23 31 28 6 38 21 34 25 30 29 32 0 0 2 4 6 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 8 0 7 0 0 0 0 0 0 0 8 1 1 1 1 1 1 1 1 8 0 1 0 0 0 0 0 0 8 0 0 2 0 0 0 0 0 0 8 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 8 0 0 3 0 0 0 0 0 0 2 48 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 384 0 -1 -1 2 1 -1 -1 2 2 -1 -1 2 4 2 0 1 1 -1 -1 2 3 -1 -1 2 5 -1 -1 2 3 2 0 1 2 -1 -1 2 6 2 2 1 1 2 1 1 2 -1 -1 2 7 -1 -1 2 5 -1 -1 2 6 2 0 1 4 2 4 1 1 -1 -1 2 7 2 1 1 4 -1 -1 2 7 2 4 1 2 2 2 1 4 2 6 1 1 2 5 1 2 2 3 1 4 2 1 2 9 -1 -1 2 10 -1 -1 2 12 2 8 -1 -1 -1 -1 2 11 -1 -1 2 13 2 3 2 11 2 8 2 24 -1 -1 2 14 2 10 -1 -1 2 9 2 25 -1 -1 2 15 2 5 2 13 -1 -1 2 14 2 8 2 40 2 12 -1 -1 -1 -1 2 15 2 9 2 41 2 7 2 15 2 12 2 28 2 10 2 42 2 14 -1 -1 2 13 2 29 2 11 2 43 -1 -1 2 17 2 2 2 18 -1 -1 2 20 2 16 2 24 2 3 2 19 -1 -1 2 21 -1 -1 2 19 2 16 -1 -1 -1 -1 2 22 2 18 2 26 2 17 -1 -1 -1 -1 2 23 -1 -1 2 21 2 6 2 22 2 16 2 48 2 20 2 28 2 7 2 23 2 17 2 49 -1 -1 2 23 2 20 -1 -1 2 18 2 50 2 22 2 30 2 21 -1 -1 2 19 2 51 2 17 2 25 2 10 2 26 -1 -1 2 28 2 24 -1 -1 2 11 2 27 -1 -1 2 29 2 19 2 27 2 24 -1 -1 -1 -1 2 30 2 26 -1 -1 2 25 -1 -1 -1 -1 2 31 2 21 2 29 2 14 2 30 2 24 2 56 2 28 -1 -1 2 15 2 31 2 25 2 57 2 23 2 31 2 28 -1 -1 2 26 2 58 2 30 -1 -1 2 29 -1 -1 2 27 2 59 -1 -1 2 33 -1 -1 2 34 2 4 2 36 2 32 2 40 -1 -1 2 35 2 5 2 37 -1 -1 2 35 2 32 2 48 2 6 2 38 2 34 2 42 2 33 2 49 2 7 2 39 -1 -1 2 37 -1 -1 2 38 2 32 -1 -1 2 36 2 44 -1 -1 2 39 2 33 -1 -1 -1 -1 2 39 2 36 2 52 2 34 -1 -1 2 38 2 46 2 37 2 53 2 35 -1 -1 2 33 2 41 -1 -1 2 42 2 12 2 44 2 40 -1 -1 -1 -1 2 43 2 13 2 45 2 35 2 43 2 40 2 56 2 14 2 46 2 42 -1 -1 2 41 2 57 2 15 2 47 2 37 2 45 -1 -1 2 46 2 40 -1 -1 2 44 -1 -1 -1 -1 2 47 2 41 -1 -1 2 39 2 47 2 44 2 60 2 42 -1 -1 2 46 -1 -1 2 45 2 61 2 43 -1 -1 -1 -1 2 49 2 34 2 50 2 20 2 52 2 48 2 56 2 35 2 51 2 21 2 53 -1 -1 2 51 2 48 -1 -1 2 22 2 54 2 50 2 58 2 49 -1 -1 2 23 2 55 -1 -1 2 53 2 38 2 54 2 48 -1 -1 2 52 2 60 2 39 2 55 2 49 -1 -1 -1 -1 2 55 2 52 -1 -1 2 50 -1 -1 2 54 2 62 2 53 -1 -1 2 51 -1 -1 2 49 2 57 2 42 2 58 2 28 2 60 2 56 -1 -1 2 43 2 59 2 29 2 61 2 51 2 59 2 56 -1 -1 2 30 2 62 2 58 -1 -1 2 57 -1 -1 2 31 2 63 2 53 2 61 2 46 2 62 2 56 -1 -1 2 60 -1 -1 2 47 2 63 2 57 -1 -1 2 55 2 63 2 60 -1 -1 2 58 -1 -1 2 62 -1 -1 2 61 -1 -1 2 59 -1 -1 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 0 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5 5 5 5 6 6 6 6 7 7 7 7 0 64 0 6 50 77 42 73 46 69 6 77 62 44 71 47 68 6 51 76 73 58 48 67 6 76 63 71 60 49 66 6 52 75 43 72 69 54 6 75 64 45 70 68 55 6 53 74 72 59 67 56 6 74 65 70 61 66 57 6 182 269 50 265 62 261 6 269 90 52 263 63 260 6 183 268 265 158 64 259 6 268 91 263 160 65 258 6 184 267 51 264 261 146 6 267 92 53 262 260 147 6 185 266 264 159 259 148 6 266 93 262 161 258 149 6 78 257 166 253 66 249 6 257 178 168 251 67 248 6 79 256 253 106 68 247 6 256 179 251 108 69 246 6 80 255 167 252 249 142 6 255 180 169 250 248 143 6 81 254 252 107 247 144 6 254 181 250 109 246 145 6 178 245 158 241 70 237 6 245 94 160 239 71 236 6 179 244 241 114 72 235 6 244 95 239 116 73 234 6 180 243 159 240 237 138 6 243 96 161 238 236 139 6 181 242 240 115 235 140 6 242 97 238 117 234 141 6 82 233 46 229 150 225 6 233 174 48 227 151 224 6 83 232 229 162 152 223 6 232 175 227 164 153 222 6 84 231 47 228 225 122 6 231 176 49 226 224 123 6 85 230 228 163 223 124 6 230 177 226 165 222 125 6 174 221 54 217 146 213 6 221 98 56 215 147 212 6 175 220 217 154 148 211 6 220 99 215 156 149 210 6 176 219 55 216 213 126 6 219 100 57 214 212 127 6 177 218 216 155 211 128 6 218 101 214 157 210 129 6 86 209 162 205 142 201 6 209 170 164 203 143 200 6 87 208 205 110 144 199 6 208 171 203 112 145 198 6 88 207 163 204 201 130 6 207 172 165 202 200 131 6 89 206 204 111 199 132 6 206 173 202 113 198 133 6 170 197 154 193 138 189 6 197 102 156 191 139 188 6 171 196 193 118 140 187 6 196 103 191 120 141 186 6 172 195 155 192 189 134 6 195 104 157 190 188 135 6 173 194 192 119 187 136 6 194 105 190 121 186 137 256 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 8 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 384 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 384 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 384 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 1 0 -3 0 0 0 0 282 0 0 0 4 0 8 2 4 4 1 3 0 5 4 2 6 1 9 4 4 7 3 10 4 5 11 6 7 4 9 10 8 11 4 12 36 16 38 4 36 28 17 39 4 13 37 38 20 4 37 29 39 21 4 14 40 12 42 4 40 18 13 43 4 15 41 42 22 4 41 19 43 23 4 16 44 14 46 4 44 24 15 47 4 17 45 46 30 4 45 25 47 31 4 20 48 18 50 4 48 26 19 51 4 21 49 50 32 4 49 27 51 33 4 22 52 24 54 4 52 34 25 55 4 23 53 54 26 4 53 35 55 27 4 30 56 28 58 4 56 32 29 59 4 31 57 58 34 4 57 33 59 35 4 64 51 62 53 4 47 64 63 52 4 65 50 37 62 4 46 65 36 63 4 62 59 60 49 4 43 62 61 48 4 63 58 45 60 4 42 63 44 61 4 60 55 64 57 4 39 60 65 56 4 61 54 41 64 4 38 61 40 65 4 66 90 70 92 4 90 72 71 93 4 67 91 92 74 4 91 73 93 75 4 68 94 66 96 4 94 76 67 97 4 69 95 96 78 4 95 77 97 79 4 70 98 68 100 4 98 80 69 101 4 71 99 100 82 4 99 81 101 83 4 82 102 72 104 4 102 88 73 105 4 83 103 104 86 4 103 89 105 87 4 78 106 80 108 4 106 86 81 109 4 79 107 108 84 4 107 87 109 85 4 74 110 76 112 4 110 84 77 113 4 75 111 112 88 4 111 85 113 89 4 118 113 116 107 4 101 118 117 106 4 119 112 91 116 4 100 119 90 117 4 116 105 114 111 4 97 116 115 110 4 117 104 99 114 4 96 117 98 115 4 114 109 118 103 4 93 114 119 102 4 115 108 95 118 4 92 115 94 119 4 130 210 72 212 4 210 90 73 213 4 131 211 212 136 4 211 91 213 137 4 76 214 134 216 4 214 132 135 217 4 77 215 216 102 4 215 133 217 103 4 132 218 136 220 4 218 92 137 221 4 133 219 220 104 4 219 93 221 105 4 82 222 78 224 4 222 138 79 225 4 83 223 224 142 4 223 139 225 143 4 138 226 80 228 4 226 94 81 229 4 139 227 228 144 4 227 95 229 145 4 84 230 142 232 4 230 140 143 233 4 85 231 232 106 4 231 141 233 107 4 140 234 144 236 4 234 96 145 237 4 141 235 236 108 4 235 97 237 109 4 86 238 90 240 4 238 146 91 241 4 87 239 240 150 4 239 147 241 151 4 146 242 92 244 4 242 110 93 245 4 147 243 244 152 4 243 111 245 153 4 88 246 150 248 4 246 148 151 249 4 89 247 248 94 4 247 149 249 95 4 148 250 152 252 4 250 112 153 253 4 149 251 252 96 4 251 113 253 97 4 102 254 98 256 4 254 154 99 257 4 103 255 256 158 4 255 155 257 159 4 154 258 100 260 4 258 106 101 261 4 155 259 260 160 4 259 107 261 161 4 104 262 158 264 4 262 156 159 265 4 105 263 264 110 4 263 157 265 111 4 156 266 160 268 4 266 108 161 269 4 157 267 268 112 4 267 109 269 113 4 170 270 166 272 4 270 144 167 273 4 171 271 272 148 4 271 145 273 149 4 136 274 168 276 4 274 170 169 277 4 137 275 276 146 4 275 171 277 147 4 172 278 116 280 4 278 142 117 281 4 173 279 280 166 4 279 143 281 167 4 134 282 114 284 4 282 172 115 285 4 135 283 284 168 4 283 173 285 169 4 166 286 162 288 4 286 160 163 289 4 167 287 288 140 4 287 161 289 141 4 128 290 164 292 4 290 166 165 293 4 129 291 292 138 4 291 167 293 139 4 168 294 132 296 4 294 158 133 297 4 169 295 296 162 4 295 159 297 163 4 126 298 130 300 4 298 168 131 301 4 127 299 300 164 4 299 169 301 165 4 162 302 170 304 4 302 152 171 305 4 163 303 304 156 4 303 153 305 157 4 120 306 172 308 4 306 162 173 309 4 121 307 308 154 4 307 163 309 155 4 164 310 124 312 4 310 150 125 313 4 165 311 312 170 4 311 151 313 171 4 118 314 122 316 4 314 164 123 317 4 119 315 316 172 4 315 165 317 173 4 322 237 320 251 4 305 322 321 250 4 323 236 287 320 4 304 323 286 321 4 320 269 318 235 4 273 320 319 234 4 321 268 303 318 4 272 321 302 319 4 318 253 322 267 4 289 318 323 266 4 319 252 271 322 4 288 319 270 323 4 328 305 326 243 4 221 328 327 242 4 329 304 295 326 4 220 329 294 327 4 326 265 324 303 4 277 326 325 302 4 327 264 219 324 4 276 327 218 325 4 324 245 328 263 4 297 324 329 262 4 325 244 275 328 4 296 325 274 329 4 334 233 332 287 4 309 334 333 286 4 335 232 187 332 4 308 335 186 333 4 332 261 330 231 4 281 332 331 230 4 333 260 307 330 4 280 333 306 331 4 330 289 334 259 4 189 330 335 258 4 331 288 279 334 4 188 331 278 335 4 340 309 338 295 4 217 340 339 294 4 341 308 179 338 4 216 341 178 339 4 338 257 336 307 4 285 338 337 306 4 339 256 215 336 4 284 339 214 337 4 336 297 340 255 4 181 336 341 254 4 337 296 283 340 4 180 337 282 341 4 346 229 344 247 4 313 346 345 246 4 347 228 291 344 4 312 347 290 345 4 344 273 342 227 4 205 344 343 226 4 345 272 311 342 4 204 345 310 343 4 342 249 346 271 4 293 342 347 270 4 343 248 203 346 4 292 343 202 347 4 352 313 350 239 4 213 352 351 238 4 353 312 299 350 4 212 353 298 351 4 350 277 348 311 4 201 350 349 310 4 351 276 211 348 4 200 351 210 349 4 348 241 352 275 4 301 348 353 274 4 349 240 199 352 4 300 349 198 353 4 358 225 356 291 4 317 358 357 290 4 359 224 183 356 4 316 359 182 357 4 356 281 354 223 4 197 356 355 222 4 357 280 315 354 4 196 357 314 355 4 354 293 358 279 4 185 354 359 278 4 355 292 195 358 4 184 355 194 359 4 364 317 362 299 4 209 364 363 298 4 365 316 175 362 4 208 365 174 363 4 362 285 360 315 4 193 362 361 314 4 363 284 207 360 4 192 363 206 361 4 360 301 364 283 4 177 360 365 282 4 361 300 191 364 4 176 361 190 365 564 0 6 8 10 12 14 16 18 20 22 24 26 28 42 44 -1 -1 -1 -1 -1 -1 46 48 -1 -1 -1 -1 -1 -1 50 52 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 54 56 -1 -1 -1 -1 -1 -1 58 60 -1 -1 -1 -1 -1 -1 62 64 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 282 0 0 0 3 3 3 3 3 3 3 0 0 0 3 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 0 0 0 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 282 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 65 66 1 0 0 282 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1128 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 366 0 0 0 2 0 1 2 0 2 2 0 4 2 1 3 2 1 5 2 2 3 2 2 6 2 3 7 2 4 5 2 4 6 2 5 7 2 6 7 2 0 8 2 8 1 2 0 9 2 9 2 2 0 10 2 10 4 2 1 11 2 11 3 2 1 12 2 12 5 2 2 13 2 13 3 2 2 14 2 14 6 2 3 15 2 15 7 2 4 16 2 16 5 2 4 17 2 17 6 2 5 18 2 18 7 2 6 19 2 19 7 2 10 20 2 20 12 2 8 20 2 20 16 2 8 21 2 21 13 2 9 21 2 21 11 2 9 22 2 22 17 2 10 22 2 22 14 2 11 23 2 23 18 2 12 23 2 23 15 2 14 24 2 24 15 2 13 24 2 24 19 2 16 25 2 25 19 2 17 25 2 25 18 2 26 25 2 21 26 2 26 23 2 22 26 2 26 24 2 20 26 2 0 27 2 27 8 2 0 28 2 28 9 2 0 29 2 29 10 2 10 30 2 30 20 2 8 31 2 31 20 2 8 32 2 32 21 2 9 33 2 33 21 2 9 34 2 34 22 2 10 35 2 35 22 2 21 36 2 36 26 2 22 37 2 37 26 2 20 38 2 38 26 2 29 39 2 39 31 2 27 39 2 39 30 2 27 40 2 40 33 2 28 40 2 40 32 2 28 41 2 41 35 2 29 41 2 41 34 2 30 42 2 42 37 2 35 42 2 42 38 2 34 43 2 43 36 2 33 43 2 43 37 2 32 44 2 44 38 2 31 44 2 44 36 2 45 42 2 40 45 2 45 44 2 41 45 2 45 43 2 39 45 2 20 54 2 54 16 2 8 55 2 55 21 2 21 56 2 56 13 2 9 57 2 57 21 2 21 58 2 58 11 2 9 59 2 59 22 2 22 60 2 60 17 2 10 61 2 61 22 2 22 62 2 62 14 2 11 63 2 63 23 2 23 64 2 64 18 2 12 65 2 65 23 2 23 66 2 66 15 2 14 67 2 67 24 2 24 68 2 68 15 2 13 69 2 69 24 2 24 70 2 70 19 2 16 71 2 71 25 2 25 72 2 72 19 2 17 73 2 73 25 2 25 74 2 74 18 2 26 75 2 75 25 2 21 76 2 76 26 2 26 77 2 77 23 2 22 78 2 78 26 2 26 79 2 79 24 2 20 80 2 80 26 2 31 81 2 81 53 2 27 81 2 81 51 2 32 82 2 82 54 2 51 82 2 82 43 2 53 83 2 83 35 2 28 83 2 83 52 2 54 84 2 84 36 2 52 84 2 84 44 2 27 85 2 85 57 2 29 85 2 85 55 2 28 86 2 86 58 2 55 86 2 86 33 2 57 87 2 87 37 2 30 87 2 87 56 2 58 88 2 88 38 2 56 88 2 88 34 2 29 89 2 89 61 2 31 89 2 89 59 2 30 90 2 90 62 2 59 90 2 90 39 2 61 91 2 91 45 2 32 91 2 91 60 2 62 92 2 92 46 2 60 92 2 92 40 2 33 93 2 93 65 2 35 93 2 93 63 2 34 94 2 94 66 2 63 94 2 94 41 2 65 95 2 95 47 2 36 95 2 95 64 2 66 96 2 96 48 2 64 96 2 96 42 2 39 97 2 97 69 2 37 97 2 97 67 2 40 98 2 98 70 2 67 98 2 98 49 2 69 99 2 99 41 2 38 99 2 99 68 2 70 100 2 100 42 2 68 100 2 100 50 2 43 101 2 101 73 2 45 101 2 101 71 2 44 102 2 102 74 2 71 102 2 102 47 2 73 103 2 103 49 2 46 103 2 103 72 2 74 104 2 104 50 2 72 104 2 104 48 2 77 105 2 105 68 2 79 105 2 105 66 2 78 106 2 106 67 2 62 106 2 106 79 2 52 107 2 107 77 2 80 107 2 107 65 2 51 108 2 108 78 2 61 108 2 108 80 2 75 109 2 109 64 2 77 109 2 109 74 2 76 110 2 110 63 2 58 110 2 110 77 2 60 111 2 111 75 2 78 111 2 111 73 2 59 112 2 112 76 2 57 112 2 112 78 2 79 113 2 113 72 2 75 113 2 113 70 2 80 114 2 114 71 2 54 114 2 114 75 2 56 115 2 115 79 2 76 115 2 115 69 2 55 116 2 116 80 2 53 116 2 116 76 2 124 104 2 105 124 2 124 96 2 113 124 2 124 100 2 109 124 2 123 103 2 106 123 2 123 113 2 92 123 2 123 98 2 111 123 2 122 102 2 107 122 2 122 95 2 114 122 2 122 109 2 84 122 2 121 101 2 108 121 2 121 114 2 91 121 2 121 111 2 82 121 2 120 105 2 88 120 2 120 94 2 115 120 2 120 99 2 110 120 2 119 106 2 87 119 2 119 115 2 90 119 2 119 97 2 112 119 2 118 107 2 86 118 2 118 93 2 116 118 2 118 110 2 83 118 2 117 108 2 85 117 2 117 116 2 89 117 2 117 112 2 81 117 366 0 12 14 16 18 20 22 24 26 28 30 32 34 66 -1 68 -1 70 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 72 -1 74 -1 76 -1 78 -1 80 -1 82 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 84 -1 86 -1 88 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 366 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 366 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 113 114 1 0 0 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 125 0 0 0 0 0 3 0 0 0.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 1.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 1.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 1.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 1.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 5.00000000000000000e-01 3 1.00000000000000000e+00 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 1.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000111e-01 5.00000000000000111e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 2.50000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 2.50000000000000056e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000056e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000056e-01 2.50000000000000056e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 2.50000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 7.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 7.50000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 2.50000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 5.00000000000000000e-01 7.50000000000000000e-01 3 0.00000000000000000e+00 2.50000000000000000e-01 5.00000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 2.50000000000000056e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000056e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 2.50000000000000000e-01 7.50000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 7.50000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 2.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000056e-01 2.50000000000000056e-01 3 7.50000000000000000e-01 2.50000000000000056e-01 2.50000000000000056e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 2.50000000000000056e-01 3 7.50000000000000000e-01 7.50000000000000000e-01 2.50000000000000056e-01 3 2.50000000000000000e-01 2.50000000000000056e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 2.50000000000000056e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 125 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 120 0 0 96 0 0 78 0 0 66 0 0 17 3 0 1 8 8 15 3 0 0 7 8 0 +3 0 0 0 0 282 0 0 0 4 0 8 2 4 4 1 3 0 5 4 2 6 1 9 4 4 7 3 10 4 5 11 6 7 4 9 10 8 11 4 12 36 16 38 4 36 28 17 39 4 13 37 38 20 4 37 29 39 21 4 14 40 12 42 4 40 18 13 43 4 15 41 42 22 4 41 19 43 23 4 16 44 14 46 4 44 24 15 47 4 17 45 46 30 4 45 25 47 31 4 20 48 18 50 4 48 26 19 51 4 21 49 50 32 4 49 27 51 33 4 22 52 24 54 4 52 34 25 55 4 23 53 54 26 4 53 35 55 27 4 30 56 28 58 4 56 32 29 59 4 31 57 58 34 4 57 33 59 35 4 64 51 62 53 4 47 64 63 52 4 65 50 37 62 4 46 65 36 63 4 62 59 60 49 4 43 62 61 48 4 63 58 45 60 4 42 63 44 61 4 60 55 64 57 4 39 60 65 56 4 61 54 41 64 4 38 61 40 65 4 66 90 70 92 4 90 72 71 93 4 67 91 92 74 4 91 73 93 75 4 68 94 66 96 4 94 76 67 97 4 69 95 96 78 4 95 77 97 79 4 70 98 68 100 4 98 80 69 101 4 71 99 100 82 4 99 81 101 83 4 82 102 72 104 4 102 88 73 105 4 83 103 104 86 4 103 89 105 87 4 78 106 80 108 4 106 86 81 109 4 79 107 108 84 4 107 87 109 85 4 74 110 76 112 4 110 84 77 113 4 75 111 112 88 4 111 85 113 89 4 118 113 116 107 4 101 118 117 106 4 119 112 91 116 4 100 119 90 117 4 116 105 114 111 4 97 116 115 110 4 117 104 99 114 4 96 117 98 115 4 114 109 118 103 4 93 114 119 102 4 115 108 95 118 4 92 115 94 119 4 130 210 72 212 4 210 90 73 213 4 131 211 212 136 4 211 91 213 137 4 76 214 134 216 4 214 132 135 217 4 77 215 216 102 4 215 133 217 103 4 132 218 136 220 4 218 92 137 221 4 133 219 220 104 4 219 93 221 105 4 82 222 78 224 4 222 138 79 225 4 83 223 224 142 4 223 139 225 143 4 138 226 80 228 4 226 94 81 229 4 139 227 228 144 4 227 95 229 145 4 84 230 142 232 4 230 140 143 233 4 85 231 232 106 4 231 141 233 107 4 140 234 144 236 4 234 96 145 237 4 141 235 236 108 4 235 97 237 109 4 86 238 90 240 4 238 146 91 241 4 87 239 240 150 4 239 147 241 151 4 146 242 92 244 4 242 110 93 245 4 147 243 244 152 4 243 111 245 153 4 88 246 150 248 4 246 148 151 249 4 89 247 248 94 4 247 149 249 95 4 148 250 152 252 4 250 112 153 253 4 149 251 252 96 4 251 113 253 97 4 102 254 98 256 4 254 154 99 257 4 103 255 256 158 4 255 155 257 159 4 154 258 100 260 4 258 106 101 261 4 155 259 260 160 4 259 107 261 161 4 104 262 158 264 4 262 156 159 265 4 105 263 264 110 4 263 157 265 111 4 156 266 160 268 4 266 108 161 269 4 157 267 268 112 4 267 109 269 113 4 170 270 166 272 4 270 144 167 273 4 171 271 272 148 4 271 145 273 149 4 136 274 168 276 4 274 170 169 277 4 137 275 276 146 4 275 171 277 147 4 172 278 116 280 4 278 142 117 281 4 173 279 280 166 4 279 143 281 167 4 134 282 114 284 4 282 172 115 285 4 135 283 284 168 4 283 173 285 169 4 166 286 162 288 4 286 160 163 289 4 167 287 288 140 4 287 161 289 141 4 128 290 164 292 4 290 166 165 293 4 129 291 292 138 4 291 167 293 139 4 168 294 132 296 4 294 158 133 297 4 169 295 296 162 4 295 159 297 163 4 126 298 130 300 4 298 168 131 301 4 127 299 300 164 4 299 169 301 165 4 162 302 170 304 4 302 152 171 305 4 163 303 304 156 4 303 153 305 157 4 120 306 172 308 4 306 162 173 309 4 121 307 308 154 4 307 163 309 155 4 164 310 124 312 4 310 150 125 313 4 165 311 312 170 4 311 151 313 171 4 118 314 122 316 4 314 164 123 317 4 119 315 316 172 4 315 165 317 173 4 322 237 320 251 4 305 322 321 250 4 323 236 287 320 4 304 323 286 321 4 320 269 318 235 4 273 320 319 234 4 321 268 303 318 4 272 321 302 319 4 318 253 322 267 4 289 318 323 266 4 319 252 271 322 4 288 319 270 323 4 328 305 326 243 4 221 328 327 242 4 329 304 295 326 4 220 329 294 327 4 326 265 324 303 4 277 326 325 302 4 327 264 219 324 4 276 327 218 325 4 324 245 328 263 4 297 324 329 262 4 325 244 275 328 4 296 325 274 329 4 334 233 332 287 4 309 334 333 286 4 335 232 187 332 4 308 335 186 333 4 332 261 330 231 4 281 332 331 230 4 333 260 307 330 4 280 333 306 331 4 330 289 334 259 4 189 330 335 258 4 331 288 279 334 4 188 331 278 335 4 340 309 338 295 4 217 340 339 294 4 341 308 179 338 4 216 341 178 339 4 338 257 336 307 4 285 338 337 306 4 339 256 215 336 4 284 339 214 337 4 336 297 340 255 4 181 336 341 254 4 337 296 283 340 4 180 337 282 341 4 346 229 344 247 4 313 346 345 246 4 347 228 291 344 4 312 347 290 345 4 344 273 342 227 4 205 344 343 226 4 345 272 311 342 4 204 345 310 343 4 342 249 346 271 4 293 342 347 270 4 343 248 203 346 4 292 343 202 347 4 352 313 350 239 4 213 352 351 238 4 353 312 299 350 4 212 353 298 351 4 350 277 348 311 4 201 350 349 310 4 351 276 211 348 4 200 351 210 349 4 348 241 352 275 4 301 348 353 274 4 349 240 199 352 4 300 349 198 353 4 358 225 356 291 4 317 358 357 290 4 359 224 183 356 4 316 359 182 357 4 356 281 354 223 4 197 356 355 222 4 357 280 315 354 4 196 357 314 355 4 354 293 358 279 4 185 354 359 278 4 355 292 195 358 4 184 355 194 359 4 364 317 362 299 4 209 364 363 298 4 365 316 175 362 4 208 365 174 363 4 362 285 360 315 4 193 362 361 314 4 363 284 207 360 4 192 363 206 361 4 360 301 364 283 4 177 360 365 282 4 361 300 191 364 4 176 361 190 365 564 0 6 8 10 12 14 16 18 20 22 24 26 28 42 44 -1 -1 -1 -1 -1 -1 46 48 -1 -1 -1 -1 -1 -1 50 52 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 54 56 -1 -1 -1 -1 -1 -1 58 60 -1 -1 -1 -1 -1 -1 62 64 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 282 0 0 0 3 3 3 3 3 3 3 0 0 0 3 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 0 0 0 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 42 42 42 42 42 42 42 42 42 42 42 42 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 282 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 65 66 1 0 0 282 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1128 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 366 0 0 0 2 0 1 2 0 2 2 0 4 2 1 3 2 1 5 2 2 3 2 2 6 2 3 7 2 4 5 2 4 6 2 5 7 2 6 7 2 0 8 2 8 1 2 0 9 2 9 2 2 0 10 2 10 4 2 1 11 2 11 3 2 1 12 2 12 5 2 2 13 2 13 3 2 2 14 2 14 6 2 3 15 2 15 7 2 4 16 2 16 5 2 4 17 2 17 6 2 5 18 2 18 7 2 6 19 2 19 7 2 10 20 2 20 12 2 8 20 2 20 16 2 8 21 2 21 13 2 9 21 2 21 11 2 9 22 2 22 17 2 10 22 2 22 14 2 11 23 2 23 18 2 12 23 2 23 15 2 14 24 2 24 15 2 13 24 2 24 19 2 16 25 2 25 19 2 17 25 2 25 18 2 26 25 2 21 26 2 26 23 2 22 26 2 26 24 2 20 26 2 0 27 2 27 8 2 0 28 2 28 9 2 0 29 2 29 10 2 10 30 2 30 20 2 8 31 2 31 20 2 8 32 2 32 21 2 9 33 2 33 21 2 9 34 2 34 22 2 10 35 2 35 22 2 21 36 2 36 26 2 22 37 2 37 26 2 20 38 2 38 26 2 29 39 2 39 31 2 27 39 2 39 30 2 27 40 2 40 33 2 28 40 2 40 32 2 28 41 2 41 35 2 29 41 2 41 34 2 30 42 2 42 37 2 35 42 2 42 38 2 34 43 2 43 36 2 33 43 2 43 37 2 32 44 2 44 38 2 31 44 2 44 36 2 45 42 2 40 45 2 45 44 2 41 45 2 45 43 2 39 45 2 20 54 2 54 16 2 8 55 2 55 21 2 21 56 2 56 13 2 9 57 2 57 21 2 21 58 2 58 11 2 9 59 2 59 22 2 22 60 2 60 17 2 10 61 2 61 22 2 22 62 2 62 14 2 11 63 2 63 23 2 23 64 2 64 18 2 12 65 2 65 23 2 23 66 2 66 15 2 14 67 2 67 24 2 24 68 2 68 15 2 13 69 2 69 24 2 24 70 2 70 19 2 16 71 2 71 25 2 25 72 2 72 19 2 17 73 2 73 25 2 25 74 2 74 18 2 26 75 2 75 25 2 21 76 2 76 26 2 26 77 2 77 23 2 22 78 2 78 26 2 26 79 2 79 24 2 20 80 2 80 26 2 31 81 2 81 53 2 27 81 2 81 51 2 32 82 2 82 54 2 51 82 2 82 43 2 53 83 2 83 35 2 28 83 2 83 52 2 54 84 2 84 36 2 52 84 2 84 44 2 27 85 2 85 57 2 29 85 2 85 55 2 28 86 2 86 58 2 55 86 2 86 33 2 57 87 2 87 37 2 30 87 2 87 56 2 58 88 2 88 38 2 56 88 2 88 34 2 29 89 2 89 61 2 31 89 2 89 59 2 30 90 2 90 62 2 59 90 2 90 39 2 61 91 2 91 45 2 32 91 2 91 60 2 62 92 2 92 46 2 60 92 2 92 40 2 33 93 2 93 65 2 35 93 2 93 63 2 34 94 2 94 66 2 63 94 2 94 41 2 65 95 2 95 47 2 36 95 2 95 64 2 66 96 2 96 48 2 64 96 2 96 42 2 39 97 2 97 69 2 37 97 2 97 67 2 40 98 2 98 70 2 67 98 2 98 49 2 69 99 2 99 41 2 38 99 2 99 68 2 70 100 2 100 42 2 68 100 2 100 50 2 43 101 2 101 73 2 45 101 2 101 71 2 44 102 2 102 74 2 71 102 2 102 47 2 73 103 2 103 49 2 46 103 2 103 72 2 74 104 2 104 50 2 72 104 2 104 48 2 77 105 2 105 68 2 79 105 2 105 66 2 78 106 2 106 67 2 62 106 2 106 79 2 52 107 2 107 77 2 80 107 2 107 65 2 51 108 2 108 78 2 61 108 2 108 80 2 75 109 2 109 64 2 77 109 2 109 74 2 76 110 2 110 63 2 58 110 2 110 77 2 60 111 2 111 75 2 78 111 2 111 73 2 59 112 2 112 76 2 57 112 2 112 78 2 79 113 2 113 72 2 75 113 2 113 70 2 80 114 2 114 71 2 54 114 2 114 75 2 56 115 2 115 79 2 76 115 2 115 69 2 55 116 2 116 80 2 53 116 2 116 76 2 124 104 2 105 124 2 124 96 2 113 124 2 124 100 2 109 124 2 123 103 2 106 123 2 123 113 2 92 123 2 123 98 2 111 123 2 122 102 2 107 122 2 122 95 2 114 122 2 122 109 2 84 122 2 121 101 2 108 121 2 121 114 2 91 121 2 121 111 2 82 121 2 120 105 2 88 120 2 120 94 2 115 120 2 120 99 2 110 120 2 119 106 2 87 119 2 119 115 2 90 119 2 119 97 2 112 119 2 118 107 2 86 118 2 118 93 2 116 118 2 118 110 2 83 118 2 117 108 2 85 117 2 117 116 2 89 117 2 117 112 2 81 117 366 0 12 14 16 18 20 22 24 26 28 30 32 34 66 -1 68 -1 70 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 72 -1 74 -1 76 -1 78 -1 80 -1 82 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 84 -1 86 -1 88 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 0 366 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 366 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 113 114 1 0 0 366 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 125 0 0 0 0 0 3 0 0 0.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 1.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 1.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 1.00000000000000000e+00 3 1.00000000000000000e+00 1.00000000000000000e+00 1.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 0.00000000000000000e+00 3 1.00000000000000000e+00 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 1.00000000000000000e+00 5.00000000000000000e-01 3 1.00000000000000000e+00 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 1.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 5.00000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 0.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 2.50000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 2.50000000000000000e-01 1.00000000000000000e+00 3 1.00000000000000000e+00 7.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 7.50000000000000000e-01 1.00000000000000000e+00 1.00000000000000000e+00 3 2.50000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 5.00000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 5.00000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 5.00000000000000000e-01 7.50000000000000000e-01 3 0.00000000000000000e+00 2.50000000000000000e-01 5.00000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 5.00000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 5.00000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 5.00000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 5.00000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 5.00000000000000000e-01 1.00000000000000000e+00 3 5.00000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 2.50000000000000000e-01 3 7.50000000000000000e-01 0.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 0.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 0.00000000000000000e+00 3 0.00000000000000000e+00 2.50000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 2.50000000000000000e-01 3 0.00000000000000000e+00 2.50000000000000000e-01 7.50000000000000000e-01 3 0.00000000000000000e+00 7.50000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 2.50000000000000000e-01 3 1.00000000000000000e+00 2.50000000000000000e-01 7.50000000000000000e-01 3 1.00000000000000000e+00 7.50000000000000000e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 2.50000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 2.50000000000000000e-01 3 7.50000000000000000e-01 1.00000000000000000e+00 7.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 2.50000000000000000e-01 1.00000000000000000e+00 3 2.50000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 1.00000000000000000e+00 3 7.50000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 5.00000000000000000e-01 3 7.50000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 5.00000000000000000e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 5.00000000000000000e-01 2.50000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 7.50000000000000000e-01 3 5.00000000000000000e-01 7.50000000000000000e-01 2.50000000000000000e-01 3 5.00000000000000000e-01 2.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 2.50000000000000000e-01 3 7.50000000000000000e-01 2.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 2.50000000000000000e-01 3 7.50000000000000000e-01 7.50000000000000000e-01 2.50000000000000000e-01 3 2.50000000000000000e-01 2.50000000000000000e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 2.50000000000000000e-01 7.50000000000000000e-01 3 2.50000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 3 7.50000000000000000e-01 7.50000000000000000e-01 7.50000000000000000e-01 125 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 120 0 0 96 0 0 78 0 0 66 0 0 17 3 0 1 8 8 15 3 0 0 7 8 0 DEAL::OK From aa24d0d936d79aae2c32ed419442206c68f0e686 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 3 Mar 2019 14:42:25 +0100 Subject: [PATCH 219/507] Move the TODO --- source/grid/tria.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/grid/tria.cc b/source/grid/tria.cc index 40d171cf074d..8493ae39df86 100644 --- a/source/grid/tria.cc +++ b/source/grid/tria.cc @@ -4907,8 +4907,7 @@ namespace internal } } - - // first clear user flags and pointers of lines; we're going + // TODO[WB]: we clear user flags and pointers of lines; we're going // to use them to flag which lines need refinement for (typename Triangulation::line_iterator line = triangulation.begin_line(); From be4fcc0a2569e74269124835fdff6e14c3464d1f Mon Sep 17 00:00:00 2001 From: Marc Fehling Date: Tue, 26 Feb 2019 16:34:09 +0100 Subject: [PATCH 220/507] Added hierarchy to hp::FECollection. --- doc/doxygen/headers/hp.h | 15 ++++ doc/news/changes/minor/20190228Fehling | 7 ++ include/deal.II/hp/fe_collection.h | 118 ++++++++++++++++++++++++- source/hp/fe_collection.cc | 68 ++++++++++++++ tests/hp/fe_hierarchy.cc | 61 +++++++++++++ tests/hp/fe_hierarchy.output | 11 +++ 6 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 doc/news/changes/minor/20190228Fehling create mode 100644 tests/hp/fe_hierarchy.cc create mode 100644 tests/hp/fe_hierarchy.output 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/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/include/deal.II/hp/fe_collection.h b/include/deal.II/hp/fe_collection.h index a58bef7ea2dc..c4668b89dcc5 100644 --- a/include/deal.II/hp/fe_collection.h +++ b/include/deal.II/hp/fe_collection.h @@ -54,11 +54,53 @@ namespace hp class FECollection : public Subscriptor { public: + /** + * 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. + * + * In this struct, we supply a hierachy that is imposed on all FECollection + * objects by default. + */ + struct DefaultHierarchy + { + /** + * Return the index succeeding @p fe_index in the @p fe_collection. + * + * Once the last element of the @p fe_collection is reached, there is no element on a higher level in + * the hierarchy and thus we return the last value. + */ + static unsigned int + next_index(const typename hp::FECollection &fe_collection, + const unsigned int fe_index) + { + return ((fe_index + 1) < fe_collection.size()) ? fe_index + 1 : + fe_index; + } + + /** + * Return the index preceding @p fe_index in the @p fe_collection. + * + * Once the first element of the @p fe_collection is reached, there is no element on a lower level in + * the hierarchy and thus we return the first value. + */ + static unsigned int + previous_index( + const typename hp::FECollection &fe_collection, + const unsigned int fe_index) + { + (void)fe_collection; + return (fe_index > 0) ? fe_index - 1 : fe_index; + } + }; + /** * Default constructor. Leads to an empty collection that can later be - * filled using push_back(). + * filled using push_back(). Establishes a hierarchy of finite elements + * corresponding to their index in the collection. */ - FECollection() = default; + FECollection(); /** * Conversion constructor. This constructor creates a FECollection from a @@ -94,7 +136,7 @@ namespace hp /** * Move constructor. */ - FECollection(FECollection &&) noexcept = default; + FECollection(FECollection &&) = default; /** * Move assignment operator. @@ -371,6 +413,60 @@ namespace hp find_dominating_fe_in_subset(const std::set &fes, const unsigned int codim = 0) const; + /** + * Set functions determining the hierarchy of finite elements, i.e. a + * function @p next that returns the index of the finite element following + * the given one, and a function @p prev returning the preceding one. + * + * Both functions expect an hp::FECollection to be passed along with a + * finite element index, on whose basis the new index will be found and + * returned. + * + * @note Both passed and returned indices have to be valid within the index + * range of this collection, i.e. within [0, size()). + */ + void + set_hierarchy(const std::function &, + const unsigned int)> &next, + const std::function &, + const unsigned int)> &prev); + + /** + * Set the default hierarchy corresponding to the index of each finite + * element in the collection. + * + * This default hierarchy is established with functions + * DefaultHierarchy::next_index() and DefaultHierarchy::previous_index(). + */ + void + set_default_hierarchy(); + + /** + * Function returning the index of the finite element following the given + * @p fe_index in hierarchy. + * + * By default, the index succeeding @p fe_index will be returned. If @p fe_index + * already corresponds to the last index, the last index will be returned. + * A custom hierarchy can be supplied via the member function + * set_hierachy(). + */ + unsigned int + next_in_hierarchy(const unsigned int fe_index) const; + + /** + * Function returning the index of the finite element preceding the given + * @p fe_index in hierarchy. + * + * By default, the index preceding @p fe_index will be returned. If @p fe_index + * already corresponds to the first index, the first index will be returned. + * A custom hierarchy can be supplied via the member function + * set_hierachy(). + */ + unsigned int + previous_in_hierarchy(const unsigned int fe_index) const; + /** * Return a component mask with as many elements as this object has vector * components and of which exactly the one component is true that @@ -576,6 +672,22 @@ namespace hp */ std::vector>> finite_elements; + + /** + * Function returning the index of the finite element following the given + * one in hierarchy. + */ + std::function &, + const unsigned int)> + hierarchy_next; + + /** + * Function returning the index of the finite element preceding the given + * one in hierarchy. + */ + std::function &, + const unsigned int)> + hierarchy_prev; }; diff --git a/source/hp/fe_collection.cc b/source/hp/fe_collection.cc index 616359767d63..cc3c26634a84 100644 --- a/source/hp/fe_collection.cc +++ b/source/hp/fe_collection.cc @@ -160,9 +160,18 @@ namespace hp + template + FECollection::FECollection() + { + set_default_hierarchy(); + } + + + template FECollection::FECollection( const FiniteElement &fe) + : FECollection() { push_back(fe); } @@ -172,6 +181,7 @@ namespace hp template FECollection::FECollection( const std::vector *> &fes) + : FECollection() { Assert(fes.size() > 0, ExcMessage("Need to pass at least one finite element.")); @@ -202,6 +212,64 @@ namespace hp + template + void + FECollection::set_hierarchy( + const std::function< + unsigned int(const typename hp::FECollection &, + const unsigned int)> &next, + const std::function< + unsigned int(const typename hp::FECollection &, + const unsigned int)> &prev) + { + // copy hierarchy functions + hierarchy_next = next; + hierarchy_prev = prev; + } + + + + template + void + FECollection::set_default_hierarchy() + { + // establish hierarchy corresponding to order of indices + set_hierarchy(&DefaultHierarchy::next_index, + &DefaultHierarchy::previous_index); + } + + + + template + unsigned int + FECollection::next_in_hierarchy( + const unsigned int fe_index) const + { + Assert(fe_index < size(), ExcIndexRange(fe_index, 0, size())); + + const unsigned int new_fe_index = hierarchy_next(*this, fe_index); + Assert(new_fe_index < size(), ExcIndexRange(new_fe_index, 0, size())); + + return new_fe_index; + } + + + + template + unsigned int + FECollection::previous_in_hierarchy( + const unsigned int fe_index) const + { + Assert(fe_index < size(), ExcIndexRange(fe_index, 0, size())); + + const unsigned int new_fe_index = hierarchy_prev(*this, fe_index); + Assert(new_fe_index < size(), ExcIndexRange(new_fe_index, 0, size())); + + return new_fe_index; + } + + + template ComponentMask FECollection::component_mask( diff --git a/tests/hp/fe_hierarchy.cc b/tests/hp/fe_hierarchy.cc new file mode 100644 index 000000000000..185421afa4ec --- /dev/null +++ b/tests/hp/fe_hierarchy.cc @@ -0,0 +1,61 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2005 - 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. +// +// --------------------------------------------------------------------- + + + +// Test default hierarchy of any hp::FECollection object. +// In the default implementation, the new indices are either the +// succeeding or preceding indices until limits are reached. + + +#include + +#include + +#include "../tests.h" + + +template +void +test() +{ + hp::FECollection fe_collection; + + while (fe_collection.size() < 3) + { + // add dummy fe to collection + fe_collection.push_back(FE_Q(1)); + deallog << "size:" << fe_collection.size() << std::endl; + + for (unsigned int fe_index = 0; fe_index < fe_collection.size(); + ++fe_index) + deallog << " idx:" << fe_index + << " next:" << fe_collection.next_in_hierarchy(fe_index) + << " prev:" << fe_collection.previous_in_hierarchy(fe_index) + << std::endl; + } +} + + + +int +main() +{ + initlog(); + + test<1>(); + + deallog << "OK" << std::endl; +} diff --git a/tests/hp/fe_hierarchy.output b/tests/hp/fe_hierarchy.output new file mode 100644 index 000000000000..64e52b61e739 --- /dev/null +++ b/tests/hp/fe_hierarchy.output @@ -0,0 +1,11 @@ + +DEAL::size:1 +DEAL:: idx:0 next:0 prev:0 +DEAL::size:2 +DEAL:: idx:0 next:1 prev:0 +DEAL:: idx:1 next:1 prev:0 +DEAL::size:3 +DEAL:: idx:0 next:1 prev:0 +DEAL:: idx:1 next:2 prev:0 +DEAL:: idx:2 next:2 prev:1 +DEAL::OK From 20094c005d082401ab4a43a68e48f5567eb2c3d1 Mon Sep 17 00:00:00 2001 From: Marc Fehling Date: Fri, 8 Feb 2019 00:59:12 +0100 Subject: [PATCH 221/507] Added 'repartition' signals. Attached 'active_fe_transfer' functions to them. --- doc/news/changes/minor/20190303Fehling | 5 + include/deal.II/grid/tria.h | 19 ++ source/distributed/tria.cc | 9 + source/hp/dof_handler.cc | 11 + tests/mpi/hp_active_fe_indices_transfer_03.cc | 104 ++++++++ ...ransfer_03.with_p4est=true.mpirun=2.output | 175 ++++++++++++++ ...ransfer_03.with_p4est=true.mpirun=8.output | 223 ++++++++++++++++++ 7 files changed, 546 insertions(+) create mode 100644 doc/news/changes/minor/20190303Fehling create mode 100644 tests/mpi/hp_active_fe_indices_transfer_03.cc create mode 100644 tests/mpi/hp_active_fe_indices_transfer_03.with_p4est=true.mpirun=2.output create mode 100644 tests/mpi/hp_active_fe_indices_transfer_03.with_p4est=true.mpirun=8.output 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/include/deal.II/grid/tria.h b/include/deal.II/grid/tria.h index 6976f51fb1f0..baf3beefda60 100644 --- a/include/deal.II/grid/tria.h +++ b/include/deal.II/grid/tria.h @@ -2327,6 +2327,25 @@ class Triangulation : public Subscriptor */ boost::signals2::signal post_distributed_refinement; + /** + * This signal is triggered at the beginning of execution of the + * parallel::distributed::Triangulation::repartition() function. At the time + * this signal is triggered, the triangulation is still unchanged. + * + * @note The parallel::distributed::Triangulation::repartition() function is + * also called by parallel::distributed::Triangulation::load(). Thus, the + * pre_distributed_repartition signal will be triggered after the + * pre_distributed_load one. + */ + boost::signals2::signal pre_distributed_repartition; + + /** + * This signal is triggered at the end of execution of the + * parallel::distributed::Triangulation::repartition() + * function when the triangulation has reached its final state. + */ + boost::signals2::signal post_distributed_repartition; + /** * This signal is triggered at the beginning of execution of the * parallel::distributed::Triangulation::save() diff --git a/source/distributed/tria.cc b/source/distributed/tria.cc index 9da8894cd146..7541203735c6 100644 --- a/source/distributed/tria.cc +++ b/source/distributed/tria.cc @@ -4085,6 +4085,9 @@ namespace parallel "Error: There shouldn't be any cells flagged for coarsening/refinement when calling repartition().")); # endif + // signal that repartitioning is going to happen + this->signals.pre_distributed_repartition(); + // before repartitioning the mesh let others attach mesh related info // (such as SolutionTransfer data) to the p4est std::vector::gloidx> @@ -4160,6 +4163,12 @@ namespace parallel // update how many cells, edges, etc, we store locally this->update_number_cache(); + + // signal that repartitioning is finished, + // this is triggered before update_periodic_face_map + // to be consistent with the serial triangulation class + this->signals.post_distributed_repartition(); + this->update_periodic_face_map(); } diff --git a/source/hp/dof_handler.cc b/source/hp/dof_handler.cc index 8e9dc7e65a9d..fb3742c33e38 100644 --- a/source/hp/dof_handler.cc +++ b/source/hp/dof_handler.cc @@ -1654,6 +1654,17 @@ namespace hp internal::DoFHandlerImplementation::Policy::ParallelDistributed< DoFHandler>>(*this); + tria_listeners.push_back( + this->tria->signals.pre_distributed_repartition.connect(std::bind( + &DoFHandler::pre_distributed_active_fe_index_transfer, + std::ref(*this)))); + tria_listeners.push_back( + this->tria->signals.post_distributed_repartition.connect(std::bind( + &DoFHandler::post_distributed_active_fe_index_transfer, + std::ref(*this)))); + tria_listeners.push_back( this->tria->signals.pre_distributed_refinement.connect(std::bind( &DoFHandler +#include + +#include + +#include + +#include + +#include "../tests.h" + + +template +void +test() +{ + const unsigned int myid = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); + + // ------ setup ------ + parallel::distributed::Triangulation tria(MPI_COMM_WORLD); + + GridGenerator::subdivided_hyper_cube(tria, 2); + tria.refine_global(1); + deallog << "cells before: " << tria.n_global_active_cells() << std::endl; + + // prepare FECollection with arbitrary number of entries + hp::FECollection fe_collection; + for (unsigned int i = 0; i < Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD); + ++i) + fe_collection.push_back(FE_Q(i + 1)); + + // we need to introduce dof_handler to its fe_collection first + hp::DoFHandler dh(tria); + dh.set_fe(fe_collection); + + for (auto &cell : dh.active_cell_iterators()) + if (cell->is_locally_owned()) + { + // set active fe index + if (!(cell->is_artificial())) + cell->set_active_fe_index(myid); + + deallog << "myid=" << myid << " cellid=" << cell->id() + << " fe_index=" << cell->active_fe_index() << std::endl; + } + + // ----- transfer ----- + parallel::CellWeights cell_weights(dh); + cell_weights.register_ndofs_weighting(100000); + + tria.repartition(); + + deallog << "cells after: " << tria.n_global_active_cells() << std::endl; + + // ------ verify ------ + // check if all children adopted the correct id + for (auto &cell : dh.active_cell_iterators()) + if (cell->is_locally_owned()) + deallog << "myid=" << myid << " cellid=" << cell->id() + << " fe_index=" << cell->active_fe_index() << std::endl; + + // for further calculations, distribute dofs, i.e. + // dh.distribute_dofs(fe_collection); + + // make sure no processor is hanging + MPI_Barrier(MPI_COMM_WORLD); + + deallog << "OK" << std::endl; +} + + +int +main(int argc, char *argv[]) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + MPILogInitAll log; + + deallog.push("2d"); + test<2>(); + deallog.pop(); + deallog.push("3d"); + test<3>(); + deallog.pop(); +} diff --git a/tests/mpi/hp_active_fe_indices_transfer_03.with_p4est=true.mpirun=2.output b/tests/mpi/hp_active_fe_indices_transfer_03.with_p4est=true.mpirun=2.output new file mode 100644 index 000000000000..7db8f630504a --- /dev/null +++ b/tests/mpi/hp_active_fe_indices_transfer_03.with_p4est=true.mpirun=2.output @@ -0,0 +1,175 @@ + +DEAL:0:2d::cells before: 16 +DEAL:0:2d::myid=0 cellid=0_1:0 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:1 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:2 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:3 fe_index=0 +DEAL:0:2d::myid=0 cellid=1_1:0 fe_index=0 +DEAL:0:2d::myid=0 cellid=1_1:1 fe_index=0 +DEAL:0:2d::myid=0 cellid=1_1:2 fe_index=0 +DEAL:0:2d::myid=0 cellid=1_1:3 fe_index=0 +DEAL:0:2d::cells after: 16 +DEAL:0:2d::myid=0 cellid=0_1:0 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:1 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:2 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:3 fe_index=0 +DEAL:0:2d::myid=0 cellid=1_1:0 fe_index=0 +DEAL:0:2d::myid=0 cellid=1_1:1 fe_index=0 +DEAL:0:2d::myid=0 cellid=1_1:2 fe_index=0 +DEAL:0:2d::myid=0 cellid=1_1:3 fe_index=0 +DEAL:0:2d::myid=0 cellid=2_1:0 fe_index=1 +DEAL:0:2d::myid=0 cellid=2_1:1 fe_index=1 +DEAL:0:2d::myid=0 cellid=2_1:2 fe_index=1 +DEAL:0:2d::myid=0 cellid=2_1:3 fe_index=1 +DEAL:0:2d::OK +DEAL:0:3d::cells before: 64 +DEAL:0:3d::myid=0 cellid=0_1:0 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:1 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:2 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:3 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:4 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:5 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:6 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:7 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:0 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:1 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:2 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:3 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:4 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:5 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:6 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:7 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:0 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:1 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:2 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:3 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:4 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:5 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:6 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:7 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:0 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:1 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:2 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:3 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:4 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:5 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:6 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:7 fe_index=0 +DEAL:0:3d::cells after: 64 +DEAL:0:3d::myid=0 cellid=0_1:0 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:1 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:2 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:3 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:4 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:5 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:6 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:7 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:0 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:1 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:2 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:3 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:4 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:5 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:6 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:7 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:0 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:1 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:2 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:3 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:4 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:5 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:6 fe_index=0 +DEAL:0:3d::myid=0 cellid=2_1:7 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:0 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:1 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:2 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:3 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:4 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:5 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:6 fe_index=0 +DEAL:0:3d::myid=0 cellid=3_1:7 fe_index=0 +DEAL:0:3d::myid=0 cellid=4_1:0 fe_index=1 +DEAL:0:3d::myid=0 cellid=4_1:1 fe_index=1 +DEAL:0:3d::myid=0 cellid=4_1:2 fe_index=1 +DEAL:0:3d::myid=0 cellid=4_1:3 fe_index=1 +DEAL:0:3d::myid=0 cellid=4_1:4 fe_index=1 +DEAL:0:3d::myid=0 cellid=4_1:5 fe_index=1 +DEAL:0:3d::myid=0 cellid=4_1:6 fe_index=1 +DEAL:0:3d::myid=0 cellid=4_1:7 fe_index=1 +DEAL:0:3d::myid=0 cellid=5_1:0 fe_index=1 +DEAL:0:3d::myid=0 cellid=5_1:1 fe_index=1 +DEAL:0:3d::myid=0 cellid=5_1:2 fe_index=1 +DEAL:0:3d::myid=0 cellid=5_1:3 fe_index=1 +DEAL:0:3d::myid=0 cellid=5_1:4 fe_index=1 +DEAL:0:3d::myid=0 cellid=5_1:5 fe_index=1 +DEAL:0:3d::myid=0 cellid=5_1:6 fe_index=1 +DEAL:0:3d::myid=0 cellid=5_1:7 fe_index=1 +DEAL:0:3d::OK + +DEAL:1:2d::cells before: 16 +DEAL:1:2d::myid=1 cellid=2_1:0 fe_index=1 +DEAL:1:2d::myid=1 cellid=2_1:1 fe_index=1 +DEAL:1:2d::myid=1 cellid=2_1:2 fe_index=1 +DEAL:1:2d::myid=1 cellid=2_1:3 fe_index=1 +DEAL:1:2d::myid=1 cellid=3_1:0 fe_index=1 +DEAL:1:2d::myid=1 cellid=3_1:1 fe_index=1 +DEAL:1:2d::myid=1 cellid=3_1:2 fe_index=1 +DEAL:1:2d::myid=1 cellid=3_1:3 fe_index=1 +DEAL:1:2d::cells after: 16 +DEAL:1:2d::myid=1 cellid=3_1:0 fe_index=1 +DEAL:1:2d::myid=1 cellid=3_1:1 fe_index=1 +DEAL:1:2d::myid=1 cellid=3_1:2 fe_index=1 +DEAL:1:2d::myid=1 cellid=3_1:3 fe_index=1 +DEAL:1:2d::OK +DEAL:1:3d::cells before: 64 +DEAL:1:3d::myid=1 cellid=4_1:0 fe_index=1 +DEAL:1:3d::myid=1 cellid=4_1:1 fe_index=1 +DEAL:1:3d::myid=1 cellid=4_1:2 fe_index=1 +DEAL:1:3d::myid=1 cellid=4_1:3 fe_index=1 +DEAL:1:3d::myid=1 cellid=4_1:4 fe_index=1 +DEAL:1:3d::myid=1 cellid=4_1:5 fe_index=1 +DEAL:1:3d::myid=1 cellid=4_1:6 fe_index=1 +DEAL:1:3d::myid=1 cellid=4_1:7 fe_index=1 +DEAL:1:3d::myid=1 cellid=5_1:0 fe_index=1 +DEAL:1:3d::myid=1 cellid=5_1:1 fe_index=1 +DEAL:1:3d::myid=1 cellid=5_1:2 fe_index=1 +DEAL:1:3d::myid=1 cellid=5_1:3 fe_index=1 +DEAL:1:3d::myid=1 cellid=5_1:4 fe_index=1 +DEAL:1:3d::myid=1 cellid=5_1:5 fe_index=1 +DEAL:1:3d::myid=1 cellid=5_1:6 fe_index=1 +DEAL:1:3d::myid=1 cellid=5_1:7 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:0 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:1 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:2 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:3 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:4 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:5 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:6 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:7 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:0 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:1 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:2 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:3 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:4 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:5 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:6 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:7 fe_index=1 +DEAL:1:3d::cells after: 64 +DEAL:1:3d::myid=1 cellid=6_1:0 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:1 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:2 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:3 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:4 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:5 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:6 fe_index=1 +DEAL:1:3d::myid=1 cellid=6_1:7 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:0 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:1 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:2 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:3 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:4 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:5 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:6 fe_index=1 +DEAL:1:3d::myid=1 cellid=7_1:7 fe_index=1 +DEAL:1:3d::OK + diff --git a/tests/mpi/hp_active_fe_indices_transfer_03.with_p4est=true.mpirun=8.output b/tests/mpi/hp_active_fe_indices_transfer_03.with_p4est=true.mpirun=8.output new file mode 100644 index 000000000000..167a31a6fe41 --- /dev/null +++ b/tests/mpi/hp_active_fe_indices_transfer_03.with_p4est=true.mpirun=8.output @@ -0,0 +1,223 @@ + +DEAL:0:2d::cells before: 16 +DEAL:0:2d::myid=0 cellid=0_1:0 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:1 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:2 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:3 fe_index=0 +DEAL:0:2d::cells after: 16 +DEAL:0:2d::myid=0 cellid=0_1:0 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:1 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:2 fe_index=0 +DEAL:0:2d::myid=0 cellid=0_1:3 fe_index=0 +DEAL:0:2d::myid=0 cellid=1_1:0 fe_index=2 +DEAL:0:2d::myid=0 cellid=1_1:1 fe_index=2 +DEAL:0:2d::myid=0 cellid=1_1:2 fe_index=2 +DEAL:0:2d::myid=0 cellid=1_1:3 fe_index=2 +DEAL:0:2d::OK +DEAL:0:3d::cells before: 64 +DEAL:0:3d::myid=0 cellid=0_1:0 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:1 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:2 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:3 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:4 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:5 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:6 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:7 fe_index=0 +DEAL:0:3d::cells after: 64 +DEAL:0:3d::myid=0 cellid=0_1:0 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:1 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:2 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:3 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:4 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:5 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:6 fe_index=0 +DEAL:0:3d::myid=0 cellid=0_1:7 fe_index=0 +DEAL:0:3d::myid=0 cellid=1_1:0 fe_index=1 +DEAL:0:3d::myid=0 cellid=1_1:1 fe_index=1 +DEAL:0:3d::myid=0 cellid=1_1:2 fe_index=1 +DEAL:0:3d::myid=0 cellid=1_1:3 fe_index=1 +DEAL:0:3d::myid=0 cellid=1_1:4 fe_index=1 +DEAL:0:3d::myid=0 cellid=1_1:5 fe_index=1 +DEAL:0:3d::myid=0 cellid=1_1:6 fe_index=1 +DEAL:0:3d::myid=0 cellid=1_1:7 fe_index=1 +DEAL:0:3d::myid=0 cellid=2_1:0 fe_index=2 +DEAL:0:3d::myid=0 cellid=2_1:1 fe_index=2 +DEAL:0:3d::myid=0 cellid=2_1:2 fe_index=2 +DEAL:0:3d::myid=0 cellid=2_1:3 fe_index=2 +DEAL:0:3d::myid=0 cellid=2_1:4 fe_index=2 +DEAL:0:3d::myid=0 cellid=2_1:5 fe_index=2 +DEAL:0:3d::myid=0 cellid=2_1:6 fe_index=2 +DEAL:0:3d::myid=0 cellid=2_1:7 fe_index=2 +DEAL:0:3d::myid=0 cellid=3_1:0 fe_index=3 +DEAL:0:3d::myid=0 cellid=3_1:1 fe_index=3 +DEAL:0:3d::myid=0 cellid=3_1:2 fe_index=3 +DEAL:0:3d::myid=0 cellid=3_1:3 fe_index=3 +DEAL:0:3d::myid=0 cellid=3_1:4 fe_index=3 +DEAL:0:3d::myid=0 cellid=3_1:5 fe_index=3 +DEAL:0:3d::myid=0 cellid=3_1:6 fe_index=3 +DEAL:0:3d::myid=0 cellid=3_1:7 fe_index=3 +DEAL:0:3d::OK + +DEAL:1:2d::cells before: 16 +DEAL:1:2d::cells after: 16 +DEAL:1:2d::myid=1 cellid=2_1:0 fe_index=4 +DEAL:1:2d::myid=1 cellid=2_1:1 fe_index=4 +DEAL:1:2d::myid=1 cellid=2_1:2 fe_index=4 +DEAL:1:2d::myid=1 cellid=2_1:3 fe_index=4 +DEAL:1:2d::OK +DEAL:1:3d::cells before: 64 +DEAL:1:3d::myid=1 cellid=1_1:0 fe_index=1 +DEAL:1:3d::myid=1 cellid=1_1:1 fe_index=1 +DEAL:1:3d::myid=1 cellid=1_1:2 fe_index=1 +DEAL:1:3d::myid=1 cellid=1_1:3 fe_index=1 +DEAL:1:3d::myid=1 cellid=1_1:4 fe_index=1 +DEAL:1:3d::myid=1 cellid=1_1:5 fe_index=1 +DEAL:1:3d::myid=1 cellid=1_1:6 fe_index=1 +DEAL:1:3d::myid=1 cellid=1_1:7 fe_index=1 +DEAL:1:3d::cells after: 64 +DEAL:1:3d::myid=1 cellid=4_1:0 fe_index=4 +DEAL:1:3d::myid=1 cellid=4_1:1 fe_index=4 +DEAL:1:3d::myid=1 cellid=4_1:2 fe_index=4 +DEAL:1:3d::myid=1 cellid=4_1:3 fe_index=4 +DEAL:1:3d::myid=1 cellid=4_1:4 fe_index=4 +DEAL:1:3d::myid=1 cellid=4_1:5 fe_index=4 +DEAL:1:3d::myid=1 cellid=4_1:6 fe_index=4 +DEAL:1:3d::myid=1 cellid=4_1:7 fe_index=4 +DEAL:1:3d::OK + + +DEAL:2:2d::cells before: 16 +DEAL:2:2d::myid=2 cellid=1_1:0 fe_index=2 +DEAL:2:2d::myid=2 cellid=1_1:1 fe_index=2 +DEAL:2:2d::myid=2 cellid=1_1:2 fe_index=2 +DEAL:2:2d::myid=2 cellid=1_1:3 fe_index=2 +DEAL:2:2d::cells after: 16 +DEAL:2:2d::OK +DEAL:2:3d::cells before: 64 +DEAL:2:3d::myid=2 cellid=2_1:0 fe_index=2 +DEAL:2:3d::myid=2 cellid=2_1:1 fe_index=2 +DEAL:2:3d::myid=2 cellid=2_1:2 fe_index=2 +DEAL:2:3d::myid=2 cellid=2_1:3 fe_index=2 +DEAL:2:3d::myid=2 cellid=2_1:4 fe_index=2 +DEAL:2:3d::myid=2 cellid=2_1:5 fe_index=2 +DEAL:2:3d::myid=2 cellid=2_1:6 fe_index=2 +DEAL:2:3d::myid=2 cellid=2_1:7 fe_index=2 +DEAL:2:3d::cells after: 64 +DEAL:2:3d::myid=2 cellid=5_1:0 fe_index=5 +DEAL:2:3d::myid=2 cellid=5_1:1 fe_index=5 +DEAL:2:3d::myid=2 cellid=5_1:2 fe_index=5 +DEAL:2:3d::myid=2 cellid=5_1:3 fe_index=5 +DEAL:2:3d::myid=2 cellid=5_1:4 fe_index=5 +DEAL:2:3d::myid=2 cellid=5_1:5 fe_index=5 +DEAL:2:3d::myid=2 cellid=5_1:6 fe_index=5 +DEAL:2:3d::myid=2 cellid=5_1:7 fe_index=5 +DEAL:2:3d::OK + + +DEAL:3:2d::cells before: 16 +DEAL:3:2d::cells after: 16 +DEAL:3:2d::myid=3 cellid=3_1:0 fe_index=6 +DEAL:3:2d::myid=3 cellid=3_1:1 fe_index=6 +DEAL:3:2d::myid=3 cellid=3_1:2 fe_index=6 +DEAL:3:2d::myid=3 cellid=3_1:3 fe_index=6 +DEAL:3:2d::OK +DEAL:3:3d::cells before: 64 +DEAL:3:3d::myid=3 cellid=3_1:0 fe_index=3 +DEAL:3:3d::myid=3 cellid=3_1:1 fe_index=3 +DEAL:3:3d::myid=3 cellid=3_1:2 fe_index=3 +DEAL:3:3d::myid=3 cellid=3_1:3 fe_index=3 +DEAL:3:3d::myid=3 cellid=3_1:4 fe_index=3 +DEAL:3:3d::myid=3 cellid=3_1:5 fe_index=3 +DEAL:3:3d::myid=3 cellid=3_1:6 fe_index=3 +DEAL:3:3d::myid=3 cellid=3_1:7 fe_index=3 +DEAL:3:3d::cells after: 64 +DEAL:3:3d::myid=3 cellid=6_1:0 fe_index=6 +DEAL:3:3d::myid=3 cellid=6_1:1 fe_index=6 +DEAL:3:3d::myid=3 cellid=6_1:2 fe_index=6 +DEAL:3:3d::myid=3 cellid=6_1:3 fe_index=6 +DEAL:3:3d::myid=3 cellid=6_1:4 fe_index=6 +DEAL:3:3d::myid=3 cellid=6_1:5 fe_index=6 +DEAL:3:3d::myid=3 cellid=6_1:6 fe_index=6 +DEAL:3:3d::myid=3 cellid=6_1:7 fe_index=6 +DEAL:3:3d::OK + + +DEAL:4:2d::cells before: 16 +DEAL:4:2d::myid=4 cellid=2_1:0 fe_index=4 +DEAL:4:2d::myid=4 cellid=2_1:1 fe_index=4 +DEAL:4:2d::myid=4 cellid=2_1:2 fe_index=4 +DEAL:4:2d::myid=4 cellid=2_1:3 fe_index=4 +DEAL:4:2d::cells after: 16 +DEAL:4:2d::OK +DEAL:4:3d::cells before: 64 +DEAL:4:3d::myid=4 cellid=4_1:0 fe_index=4 +DEAL:4:3d::myid=4 cellid=4_1:1 fe_index=4 +DEAL:4:3d::myid=4 cellid=4_1:2 fe_index=4 +DEAL:4:3d::myid=4 cellid=4_1:3 fe_index=4 +DEAL:4:3d::myid=4 cellid=4_1:4 fe_index=4 +DEAL:4:3d::myid=4 cellid=4_1:5 fe_index=4 +DEAL:4:3d::myid=4 cellid=4_1:6 fe_index=4 +DEAL:4:3d::myid=4 cellid=4_1:7 fe_index=4 +DEAL:4:3d::cells after: 64 +DEAL:4:3d::OK + + +DEAL:5:2d::cells before: 16 +DEAL:5:2d::cells after: 16 +DEAL:5:2d::OK +DEAL:5:3d::cells before: 64 +DEAL:5:3d::myid=5 cellid=5_1:0 fe_index=5 +DEAL:5:3d::myid=5 cellid=5_1:1 fe_index=5 +DEAL:5:3d::myid=5 cellid=5_1:2 fe_index=5 +DEAL:5:3d::myid=5 cellid=5_1:3 fe_index=5 +DEAL:5:3d::myid=5 cellid=5_1:4 fe_index=5 +DEAL:5:3d::myid=5 cellid=5_1:5 fe_index=5 +DEAL:5:3d::myid=5 cellid=5_1:6 fe_index=5 +DEAL:5:3d::myid=5 cellid=5_1:7 fe_index=5 +DEAL:5:3d::cells after: 64 +DEAL:5:3d::myid=5 cellid=7_1:0 fe_index=7 +DEAL:5:3d::myid=5 cellid=7_1:1 fe_index=7 +DEAL:5:3d::myid=5 cellid=7_1:2 fe_index=7 +DEAL:5:3d::myid=5 cellid=7_1:3 fe_index=7 +DEAL:5:3d::myid=5 cellid=7_1:4 fe_index=7 +DEAL:5:3d::myid=5 cellid=7_1:5 fe_index=7 +DEAL:5:3d::myid=5 cellid=7_1:6 fe_index=7 +DEAL:5:3d::myid=5 cellid=7_1:7 fe_index=7 +DEAL:5:3d::OK + + +DEAL:6:2d::cells before: 16 +DEAL:6:2d::myid=6 cellid=3_1:0 fe_index=6 +DEAL:6:2d::myid=6 cellid=3_1:1 fe_index=6 +DEAL:6:2d::myid=6 cellid=3_1:2 fe_index=6 +DEAL:6:2d::myid=6 cellid=3_1:3 fe_index=6 +DEAL:6:2d::cells after: 16 +DEAL:6:2d::OK +DEAL:6:3d::cells before: 64 +DEAL:6:3d::myid=6 cellid=6_1:0 fe_index=6 +DEAL:6:3d::myid=6 cellid=6_1:1 fe_index=6 +DEAL:6:3d::myid=6 cellid=6_1:2 fe_index=6 +DEAL:6:3d::myid=6 cellid=6_1:3 fe_index=6 +DEAL:6:3d::myid=6 cellid=6_1:4 fe_index=6 +DEAL:6:3d::myid=6 cellid=6_1:5 fe_index=6 +DEAL:6:3d::myid=6 cellid=6_1:6 fe_index=6 +DEAL:6:3d::myid=6 cellid=6_1:7 fe_index=6 +DEAL:6:3d::cells after: 64 +DEAL:6:3d::OK + + +DEAL:7:2d::cells before: 16 +DEAL:7:2d::cells after: 16 +DEAL:7:2d::OK +DEAL:7:3d::cells before: 64 +DEAL:7:3d::myid=7 cellid=7_1:0 fe_index=7 +DEAL:7:3d::myid=7 cellid=7_1:1 fe_index=7 +DEAL:7:3d::myid=7 cellid=7_1:2 fe_index=7 +DEAL:7:3d::myid=7 cellid=7_1:3 fe_index=7 +DEAL:7:3d::myid=7 cellid=7_1:4 fe_index=7 +DEAL:7:3d::myid=7 cellid=7_1:5 fe_index=7 +DEAL:7:3d::myid=7 cellid=7_1:6 fe_index=7 +DEAL:7:3d::myid=7 cellid=7_1:7 fe_index=7 +DEAL:7:3d::cells after: 64 +DEAL:7:3d::OK + From 514aff2d48c675ca4e0aa10eeb796414207b5e51 Mon Sep 17 00:00:00 2001 From: Marc Fehling Date: Mon, 4 Mar 2019 22:39:52 +0100 Subject: [PATCH 222/507] Call post_distributed signals in the end of 'execute_coarsening_and_refinement' and 'repartition'. --- source/distributed/tria.cc | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/source/distributed/tria.cc b/source/distributed/tria.cc index 7541203735c6..f814270c31a8 100644 --- a/source/distributed/tria.cc +++ b/source/distributed/tria.cc @@ -4059,12 +4059,10 @@ namespace parallel this->update_number_cache(); - // signal that refinement is finished, - // this is triggered before update_periodic_face_map - // to be consistent with the serial triangulation class - this->signals.post_distributed_refinement(); - this->update_periodic_face_map(); + + // signal that refinement is finished + this->signals.post_distributed_refinement(); } @@ -4164,12 +4162,10 @@ namespace parallel // update how many cells, edges, etc, we store locally this->update_number_cache(); - // signal that repartitioning is finished, - // this is triggered before update_periodic_face_map - // to be consistent with the serial triangulation class - this->signals.post_distributed_repartition(); - this->update_periodic_face_map(); + + // signal that repartitioning is finished + this->signals.post_distributed_repartition(); } From 48954cca022288b739fb598b2be76cf15c5d28be Mon Sep 17 00:00:00 2001 From: Marc Fehling Date: Tue, 5 Mar 2019 00:05:15 +0100 Subject: [PATCH 223/507] Explicitly set noexcept specifier for move constructor. --- include/deal.II/hp/fe_collection.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/include/deal.II/hp/fe_collection.h b/include/deal.II/hp/fe_collection.h index c4668b89dcc5..4368627dff7d 100644 --- a/include/deal.II/hp/fe_collection.h +++ b/include/deal.II/hp/fe_collection.h @@ -135,8 +135,19 @@ namespace hp /** * Move constructor. - */ - FECollection(FECollection &&) = default; + * + * @note The implementation of standard datatypes may change with different + * libraries, so their move members may or may not be flagged non-throwing. + * We need to explicitly set the noexcept specifier according to its + * member variables to still get the performance benefits (and to satisfy + * clang-tidy). + */ + FECollection(FECollection &&) noexcept( + std::is_nothrow_move_constructible< + std::vector>>>::value + &&std::is_nothrow_move_constructible &, + const unsigned int)>>::value) = default; /** * Move assignment operator. From a0f02dedcde22b485d0a2ed24f700894785d2e2c Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Tue, 5 Mar 2019 18:39:31 +0100 Subject: [PATCH 224/507] Fix documentation of cylindrical manifold --- include/deal.II/grid/manifold_lib.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/include/deal.II/grid/manifold_lib.h b/include/deal.II/grid/manifold_lib.h index 6eb5d7e32878..a550c26613fa 100644 --- a/include/deal.II/grid/manifold_lib.h +++ b/include/deal.II/grid/manifold_lib.h @@ -406,17 +406,19 @@ class CylindricalManifold : public ChartManifold clone() const override; /** - * Compute the Cartesian coordinates for a point given in cylindrical - * coordinates. + * Compute the cylindrical coordinates $(r, \phi, \lambda)$ for the given + * space point where $r$ denotes the distance from the axis, + * $\phi$ the angle between the given point and the computed normal + * direction, and $\lambda$ the axial position. */ virtual Point<3> pull_back(const Point &space_point) const override; /** - * Compute the cylindrical coordinates $(r, \phi, \lambda)$ for the given - * point where $r$ denotes the distance from the axis, - * $\phi$ the angle between the given point and the computed normal - * direction and $\lambda$ the axial position. + * Compute the Cartesian coordinates for a chart point given in cylindrical + * coordinates $(r, \phi, \lambda)$, where $r$ denotes the distance from the + * axis, $\phi$ the angle between the given point and the computed normal + * direction, and $\lambda$ the axial position. */ virtual Point push_forward(const Point<3> &chart_point) const override; @@ -425,7 +427,7 @@ class CylindricalManifold : public ChartManifold * Compute the derivatives of the mapping from cylindrical coordinates * $(r, \phi, \lambda)$ to cartesian coordinates where $r$ denotes the * distance from the axis, $\phi$ the angle between the given point and the - * computed normal direction and $\lambda$ the axial position. + * computed normal direction, and $\lambda$ the axial position. */ virtual DerivativeForm<1, 3, spacedim> push_forward_gradient(const Point<3> &chart_point) const override; From dc21bf441614471a2a330a28eb1aab455c3180eb Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Tue, 5 Mar 2019 18:40:11 +0100 Subject: [PATCH 225/507] Fix EllipticalManifold::push_forward_gradient --- source/grid/manifold_lib.cc | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/source/grid/manifold_lib.cc b/source/grid/manifold_lib.cc index 4dd1c9a31d05..c08bff2f32e5 100644 --- a/source/grid/manifold_lib.cc +++ b/source/grid/manifold_lib.cc @@ -1091,11 +1091,7 @@ CylindricalManifold::push_forward( Assert(spacedim == 3, ExcMessage("CylindricalManifold can only be used for spacedim==3!")); - // Rotate the orthogonal direction by the given angle. - // Formula from Section 5.2 in - // http://inside.mines.edu/fs_home/gmurray/ArbitraryAxisRotation/ - // simplified assuming normal_direction and direction are orthogonal - // and unit vectors. + // Rotate the orthogonal direction by the given angle const double sine_r = std::sin(chart_point(1)) * chart_point(0); const double cosine_r = std::cos(chart_point(1)) * chart_point(0); const Tensor<1, spacedim> dxn = cross_product_3d(direction, normal_direction); @@ -1118,11 +1114,7 @@ CylindricalManifold::push_forward_gradient( Tensor<2, 3> derivatives; - // Rotate the orthogonal direction by the given angle. - // Formula from Section 5.2 in - // http://inside.mines.edu/fs_home/gmurray/ArbitraryAxisRotation/ - // simplified assuming normal_direction and direction are orthogonal - // and unit vectors. + // Rotate the orthogonal direction by the given angle const double sine = std::sin(chart_point(1)); const double cosine = std::cos(chart_point(1)); const Tensor<1, spacedim> dxn = cross_product_3d(direction, normal_direction); @@ -1289,14 +1281,19 @@ DerivativeForm<1, 2, 2> EllipticalManifold<2, 2>::push_forward_gradient( const Point<2> &chart_point) const { - const double cs = std::cos(chart_point[1]); - const double sn = std::sin(chart_point[1]); - DerivativeForm<1, 2, 2> dX; + const double cs = std::cos(chart_point[1]); + const double sn = std::sin(chart_point[1]); + Tensor<2, 2> dX; dX[0][0] = cosh_u * cs; dX[0][1] = -chart_point[0] * cosh_u * sn; dX[1][0] = sinh_u * sn; - dX[1][1] = chart_point[1] * sinh_u * cs; - return dX; + dX[1][1] = chart_point[0] * sinh_u * cs; + + // rotate according to the major axis direction + Tensor<2, 2, double> rot{ + {{+direction[0], -direction[1]}, {direction[1], direction[0]}}}; + + return rot * dX; } From 8537d3b27290f665b31276c6c2b5515770ee2e98 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Tue, 5 Mar 2019 18:41:11 +0100 Subject: [PATCH 226/507] Fix CylindricalManifold::get_new_point --- source/grid/manifold_lib.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/grid/manifold_lib.cc b/source/grid/manifold_lib.cc index c08bff2f32e5..eb0be274ff17 100644 --- a/source/grid/manifold_lib.cc +++ b/source/grid/manifold_lib.cc @@ -1049,7 +1049,7 @@ CylindricalManifold::get_new_point( const double lambda = middle * direction; if ((middle - direction * lambda).square() < tolerance * average_length) - return Point() + direction * lambda; + return point_on_axis + direction * lambda; else // If not, using the ChartManifold should yield valid results. return ChartManifold::get_new_point(surrounding_points, weights); From 38d757306e87fc15e8819be1370d96e68668f278 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Tue, 5 Mar 2019 18:41:39 +0100 Subject: [PATCH 227/507] Add test for cylindrical manifold --- tests/manifold/cylindrical_manifold_03.cc | 75 +++++++++++++++++++ tests/manifold/cylindrical_manifold_03.output | 4 + 2 files changed, 79 insertions(+) create mode 100644 tests/manifold/cylindrical_manifold_03.cc create mode 100644 tests/manifold/cylindrical_manifold_03.output diff --git a/tests/manifold/cylindrical_manifold_03.cc b/tests/manifold/cylindrical_manifold_03.cc new file mode 100644 index 000000000000..ec2994904b68 --- /dev/null +++ b/tests/manifold/cylindrical_manifold_03.cc @@ -0,0 +1,75 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Test cylindrical manifold for the mid point axis of a cylinder + +#include "../tests.h" + + +// all include files you need here +#include + + + +int +main() +{ + initlog(); + deallog << std::setprecision(10); + + Tensor<1, 3> axis({0.0, 0.0, 1.0}); + const Point<3> origin(1.0, 2.0, 3.0); + + // the larger the tolerance value, the more likely we identify the mid point + const double tolerance = 1e-6; + + const CylindricalManifold<3> cylinder(axis, origin, tolerance); + + // take two points symmetric about cylinder axis + const double offset = 1.0; + std::vector> surrounding_points_vector( + {Point<3>(origin[0] + offset, origin[1], origin[2]), + Point<3>(origin[0] - offset, origin[1], origin[2])}); + const ArrayView> surrounding_points = + make_array_view(surrounding_points_vector); + const std::vector weights_vector({0.5, 0.5}); + const ArrayView weights = make_array_view(weights_vector); + + deallog << "New point is at " + << cylinder.get_new_point(surrounding_points, weights) + << " and it should be " << origin << std::endl; + + surrounding_points_vector[0][2] = -1; + surrounding_points_vector[1][2] = -1; + + deallog << "New point is at " + << cylinder.get_new_point(surrounding_points, weights) + << " and it should be " << Point<3>(origin[0], origin[1], -1.0) + << std::endl; + + axis[0] = 0.3; + axis[1] = 0.6; + axis[2] = 0.8; + + surrounding_points_vector[0][2] = origin[2]; + surrounding_points_vector[1][2] = origin[2]; + + const CylindricalManifold<3> second_cylinder(axis, origin, tolerance); + deallog << "New point is at " + << second_cylinder.get_new_point(surrounding_points, weights) + << " and it should be " << origin << std::endl; + + return 0; +} diff --git a/tests/manifold/cylindrical_manifold_03.output b/tests/manifold/cylindrical_manifold_03.output new file mode 100644 index 000000000000..87c17c1da545 --- /dev/null +++ b/tests/manifold/cylindrical_manifold_03.output @@ -0,0 +1,4 @@ + +DEAL::New point is at 1.000000000 2.000000000 3.000000000 and it should be 1.000000000 2.000000000 3.000000000 +DEAL::New point is at 1.000000000 2.000000000 -1.000000000 and it should be 1.000000000 2.000000000 -1.000000000 +DEAL::New point is at 1.000000000 2.000000000 3.000000000 and it should be 1.000000000 2.000000000 3.000000000 From b65307e98f613676fad3935851ee89743d6a7d37 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Tue, 5 Mar 2019 18:41:56 +0100 Subject: [PATCH 228/507] Add test for EllipticalManifold::push_forward_gradient --- tests/manifold/elliptical_manifold_03.cc | 78 ++++++++++++++++++++ tests/manifold/elliptical_manifold_03.output | 3 + 2 files changed, 81 insertions(+) create mode 100644 tests/manifold/elliptical_manifold_03.cc create mode 100644 tests/manifold/elliptical_manifold_03.output diff --git a/tests/manifold/elliptical_manifold_03.cc b/tests/manifold/elliptical_manifold_03.cc new file mode 100644 index 000000000000..ad72999421e3 --- /dev/null +++ b/tests/manifold/elliptical_manifold_03.cc @@ -0,0 +1,78 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Check gradient of elliptical manifold + +#include "../tests.h" + + +// all include files you need here +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + + +int +main() +{ + initlog(); + + deallog << std::setprecision(10); + + // setup elliptical manifold + const Tensor<1, 2> major_axis({2.0, 1.0}); + const Point<2> center(7.0, 6.0); + const double eccentricity = 0.1; + + const EllipticalManifold<2> ellipse(center, major_axis, eccentricity); + + // reference point for computing gradient + const Point<2> chart_point(1.0, 0.25 * numbers::PI); + + // compute gradient by central finite differences + const double h = 1e-6; + const Point<2> chart_point_plusc(chart_point[0] + h, chart_point[1]); + const Point<2> chart_point_minusc(chart_point[0] - h, chart_point[1]); + const Point<2> chart_point_plusphi(chart_point[0], chart_point[1] + h); + const Point<2> chart_point_minusphi(chart_point[0], chart_point[1] - h); + + const Point<2> space_point_plusc = ellipse.push_forward(chart_point_plusc); + const Point<2> space_point_minusc = ellipse.push_forward(chart_point_minusc); + const Point<2> space_point_plusphi = + ellipse.push_forward(chart_point_plusphi); + const Point<2> space_point_minusphi = + ellipse.push_forward(chart_point_minusphi); + + deallog << "Gradient by finite differences: " + << (space_point_plusc - space_point_minusc) / (2.0 * h) << " " + << (space_point_plusphi - space_point_minusphi) / (2.0 * h) + << std::endl; + deallog << "Analytic gradient: " + << transpose(Tensor<2, 2>(ellipse.push_forward_gradient(chart_point))) + << std::endl; + + return 0; +} diff --git a/tests/manifold/elliptical_manifold_03.output b/tests/manifold/elliptical_manifold_03.output new file mode 100644 index 000000000000..602c91bbc8b7 --- /dev/null +++ b/tests/manifold/elliptical_manifold_03.output @@ -0,0 +1,3 @@ + +DEAL::Gradient by finite differences: 3.178128775 9.455130749 -9.470981865 3.130575430 +DEAL::Analytic gradient: 3.178128776 9.455130749 -9.470981865 3.130575429 From 3c544115ac47a81d59c947f982e86e86d31bd387 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Tue, 5 Mar 2019 18:47:19 +0100 Subject: [PATCH 229/507] Add changelogs --- .../changes/minor/20190305DanielAppelMartinKronbichler-1 | 5 +++++ .../changes/minor/20190305DanielAppelMartinKronbichler-2 | 4 ++++ 2 files changed, 9 insertions(+) create mode 100644 doc/news/changes/minor/20190305DanielAppelMartinKronbichler-1 create mode 100644 doc/news/changes/minor/20190305DanielAppelMartinKronbichler-2 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) From 41e0507737bebcaae9d8a6859cef9c2d1c6ef189 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Tue, 5 Mar 2019 15:13:53 +0100 Subject: [PATCH 230/507] add two more type traits to FEEvaluation --- include/deal.II/matrix_free/fe_evaluation.h | 52 ++++++++ .../fe_evaluation_type_traits_02.cc | 120 ++++++++++++++++++ .../fe_evaluation_type_traits_02.output | 8 ++ 3 files changed, 180 insertions(+) create mode 100644 tests/matrix_free/fe_evaluation_type_traits_02.cc create mode 100644 tests/matrix_free/fe_evaluation_type_traits_02.output diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index 337846d4bd28..5d3b0f41288e 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -3431,6 +3431,58 @@ namespace internal template const bool has_local_element::value; + + + // a helper type-trait that leverage SFINAE to figure out if type T has + // void T::add_local_element(const uint, const typename T::value_type) + template + struct has_add_local_element + { + private: + static int + detect(...); + + template + static decltype( + std::declval().add_local_element(0, typename T::value_type())) + detect(const U &); + + public: + static const bool value = + !std::is_same()))>::value; + }; + + // We need to have a separate declaration for static const members + template + const bool has_add_local_element::value; + + + + // a helper type-trait that leverage SFINAE to figure out if type T has + // void T::set_local_element(const uint, const typename T::value_type) + template + struct has_set_local_element + { + private: + static int + detect(...); + + template + static decltype( + std::declval().set_local_element(0, typename T::value_type())) + detect(const U &); + + public: + static const bool value = + !std::is_same()))>::value; + }; + + // We need to have a separate declaration for static const members + template + const bool has_set_local_element::value; + + + // same as above to check // bool T::partitioners_are_compatible(const Utilities::MPI::Partitioner &) // const diff --git a/tests/matrix_free/fe_evaluation_type_traits_02.cc b/tests/matrix_free/fe_evaluation_type_traits_02.cc new file mode 100644 index 000000000000..f87bf95c1b00 --- /dev/null +++ b/tests/matrix_free/fe_evaluation_type_traits_02.cc @@ -0,0 +1,120 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + + +// test internal typetraits used in FEEvaluation + +#include + +#include "../tests.h" + +// dummy class we use to check typetraits and internal function. +// this one mimics LA::d::Vec +template +class Dummy +{ +public: + using value_type = Number; + + Number + local_element(const unsigned int) const + { + deallog << "Dummy::local_element() const" << std::endl; + return Number(); + } + + void + set_local_element(const unsigned int, const Number) + { + deallog << "Dummy::set_local_element()" << std::endl; + } + + void + add_local_element(const unsigned int, const Number) + { + deallog << "Dummy::add_local_element()" << std::endl; + } + + Number + operator()(const unsigned int) const + { + deallog << "Dummy::operator() const" << std::endl; + return Number(); + } +}; + + +template +class Dummy2 +{ +public: + using value_type = Number; + + Number + local_element(const unsigned int) const + { + deallog << "Dummy2::local_element() const" << std::endl; + return Number(); + } + + Number & + local_element(const unsigned int) + { + deallog << "Dummy2::local_element()" << std::endl; + return dummy; + } + + Number + operator()(const unsigned int) const + { + deallog << "Dummy2::operator() const" << std::endl; + return Number(); + } + + Number & + operator()(const unsigned int) + { + deallog << "Dummy2::operator()" << std::endl; + return dummy; + } + +private: + Number dummy; +}; + + +int +main() +{ + initlog(); + + Dummy dummy; + Dummy2 dummy2; + + deallog << "has_add_local_element:" << std::endl + << "Dummy = " << internal::has_add_local_element>::value + << std::endl + << "Dummy2 = " + << internal::has_add_local_element>::value << std::endl + << "has_set_local_element:" << std::endl + << "Dummy = " << internal::has_set_local_element>::value + << std::endl + << "Dummy2 = " + << internal::has_set_local_element>::value + << std::endl; + + deallog << "OK" << std::endl; +} diff --git a/tests/matrix_free/fe_evaluation_type_traits_02.output b/tests/matrix_free/fe_evaluation_type_traits_02.output new file mode 100644 index 000000000000..d6fcec824872 --- /dev/null +++ b/tests/matrix_free/fe_evaluation_type_traits_02.output @@ -0,0 +1,8 @@ + +DEAL::has_add_local_element: +DEAL::Dummy = 1 +DEAL::Dummy2 = 0 +DEAL::has_set_local_element: +DEAL::Dummy = 1 +DEAL::Dummy2 = 0 +DEAL::OK From e217995d6f04b92a285f79263e8b43078e14583e Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Wed, 6 Mar 2019 12:09:06 +0100 Subject: [PATCH 231/507] Fix file name date in two changelog entries --- .../minor/{20190401ArndtTurcksin => 20190104ArndtTurcksin} | 0 .../changes/minor/{20191301VishalBoddu => 20190113VishalBoddu} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename doc/news/changes/minor/{20190401ArndtTurcksin => 20190104ArndtTurcksin} (100%) rename doc/news/changes/minor/{20191301VishalBoddu => 20190113VishalBoddu} (100%) 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/20191301VishalBoddu b/doc/news/changes/minor/20190113VishalBoddu similarity index 100% rename from doc/news/changes/minor/20191301VishalBoddu rename to doc/news/changes/minor/20190113VishalBoddu From aa7ee309719ddccef14056091b39594051189768 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Wed, 6 Mar 2019 12:20:30 +0100 Subject: [PATCH 232/507] Fix date markup for changelog. --- doc/news/changes/major/20180524MatthiasMaierDanielArndt | 2 +- doc/news/changes/major/20180531MatthiasMaier | 2 +- doc/news/changes/major/20180709Harper | 2 +- doc/news/changes/major/20180811DavidWells | 2 +- doc/news/changes/major/20190208MatthiasMaier | 2 +- doc/news/changes/minor/20180524MartinKronbichlerDenisDavydov | 2 +- doc/news/changes/minor/20180529DenisDavydov | 2 +- doc/news/changes/minor/20180529DenisDavydov_b | 2 +- doc/news/changes/minor/20180606SambitDas | 2 +- doc/news/changes/minor/20180611MatthiasMaier | 2 +- doc/news/changes/minor/20180612DenisDavydov | 2 +- doc/news/changes/minor/20180614PiYuehChuang | 2 +- doc/news/changes/minor/20180614UweKoecher | 2 +- doc/news/changes/minor/20180621DenisDavydov | 2 +- doc/news/changes/minor/20180621DenisDavydov_b | 3 ++- doc/news/changes/minor/20180706DenisDavydov | 2 +- doc/news/changes/minor/20180726DenisDavydov | 2 +- doc/news/changes/minor/20180802DenisDavydov | 2 +- doc/news/changes/minor/20180810BenjaminBrands | 2 +- doc/news/changes/minor/20180813AlexanderKnieps | 2 +- doc/news/changes/minor/20180821SvenjaSchoeder | 1 + doc/news/changes/minor/20180913DenisDavydov | 2 +- doc/news/changes/minor/20180919DenisDavydov | 2 +- doc/news/changes/minor/20180920DenisDavydov | 2 +- doc/news/changes/minor/20181005DenisDavydov | 2 +- doc/news/changes/minor/20190210MarcFehling | 2 +- doc/news/changes/minor/20190213MatthiasMaier | 2 +- 27 files changed, 28 insertions(+), 26 deletions(-) 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/20190208MatthiasMaier b/doc/news/changes/major/20190208MatthiasMaier index b1cd3de01f22..2131b88f999b 100644 --- a/doc/news/changes/major/20190208MatthiasMaier +++ b/doc/news/changes/major/20190208MatthiasMaier @@ -1,4 +1,4 @@ Improved: The preconditioner and solver setup in step-20 has been rewritten to highlight the new LinearOperator and PackagedOperation classes.
    -(2019/02/08, Matthias Maier) +(Matthias Maier, 2019/02/08) 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/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/20190210MarcFehling b/doc/news/changes/minor/20190210MarcFehling index 9a3e1e9f4751..ab3127585a65 100644 --- a/doc/news/changes/minor/20190210MarcFehling +++ b/doc/news/changes/minor/20190210MarcFehling @@ -3,4 +3,4 @@ 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.
    -(2019/02/10, Marc Fehling) +(Marc Fehling, 2019/02/10) diff --git a/doc/news/changes/minor/20190213MatthiasMaier b/doc/news/changes/minor/20190213MatthiasMaier index 6d3a30db0f87..4307beeed445 100644 --- a/doc/news/changes/minor/20190213MatthiasMaier +++ b/doc/news/changes/minor/20190213MatthiasMaier @@ -2,4 +2,4 @@ Fixed: inverse_operator() now handles a (composite) LinearOperator, the temporary PreconditionIdentity(), or no argument as preconditioner argument correctly.
    -(Matthias Maier 2018/06/11) +(Matthias Maier, 2019/02/13) From 45cf863d2d1dacca033ad79b313d8cec2460dd98 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Tue, 5 Mar 2019 19:24:58 +0100 Subject: [PATCH 233/507] add more vector_access_XYZ internal function in FEEvaluation and improve const-correctness of reader class --- include/deal.II/matrix_free/fe_evaluation.h | 209 ++++++++++++++++-- .../fe_evaluation_type_traits_02.cc | 9 + .../fe_evaluation_type_traits_02.output | 6 + 3 files changed, 205 insertions(+), 19 deletions(-) diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index 5d3b0f41288e..5ae7b1905cd0 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -36,6 +36,7 @@ #include #include + DEAL_II_NAMESPACE_OPEN @@ -3592,6 +3593,96 @@ namespace internal + // same for const access + template ::value, + VectorType>::type * = nullptr> + inline typename VectorType::value_type + vector_access(const VectorType &vec, const unsigned int entry) + { + return vec.local_element(entry); + } + + + + template ::value, + VectorType>::type * = nullptr> + inline void + vector_access_add(VectorType & vec, + const unsigned int entry, + const typename VectorType::value_type &val) + { + vec.add_local_element(entry, val); + } + + + + template ::value, + VectorType>::type * = nullptr> + inline void + vector_access_add(VectorType & vec, + const unsigned int entry, + const typename VectorType::value_type &val) + { + vector_access(vec, entry) += val; + } + + + + template ::value, + VectorType>::type * = nullptr> + inline void + vector_access_add_global(VectorType & vec, + const types::global_dof_index entry, + const typename VectorType::value_type &val) + { + vec.add(entry, val); + } + + + + template ::value, + VectorType>::type * = nullptr> + inline void + vector_access_add_global(VectorType & vec, + const types::global_dof_index entry, + const typename VectorType::value_type &val) + { + vec(entry) += val; + } + + + + template ::value, + VectorType>::type * = nullptr> + inline void + vector_access_set(VectorType & vec, + const unsigned int entry, + const typename VectorType::value_type &val) + { + vec.set_local_element(entry, val); + } + + + + template ::value, + VectorType>::type * = nullptr> + inline void + vector_access_set(VectorType & vec, + const unsigned int entry, + const typename VectorType::value_type &val) + { + vector_access(vec, entry) = val; + } + + + // this is to make sure that the parallel partitioning in VectorType // is really the same as stored in MatrixFree. // version below is when has_partitioners_are_compatible == false @@ -3612,6 +3703,7 @@ namespace internal } + // same as above for has_partitioners_are_compatible == true template < typename VectorType, @@ -3632,17 +3724,28 @@ namespace internal "compatible vector.")); } - // A class to use the same code to read from and write to vector + + + // Below, three classes (VectorReader, VectorSetter, + // VectorDistributorLocalToGlobal) implement the same interface and can be + // used to to read from vector, set elements of a vector and add to elements + // of the vector. + + // 1. A class to read data from vector template struct VectorReader { template void - process_dof(const unsigned int index, VectorType &vec, Number &res) const + process_dof(const unsigned int index, + const VectorType & vec, + Number & res) const { res = vector_access(vec, index); } + + template void process_dofs_vectorized(const unsigned int dofs_per_cell, @@ -3658,11 +3761,12 @@ namespace internal } + template void process_dofs_vectorized(const unsigned int dofs_per_cell, const unsigned int dof_index, - VectorType & vec, + const VectorType & vec, VectorizedArray *dof_values, std::integral_constant) const { @@ -3673,6 +3777,8 @@ namespace internal vec, dof_index + v + i * VectorizedArray::n_array_elements); } + + template void process_dofs_vectorized_transpose(const unsigned int dofs_per_cell, @@ -3688,11 +3794,12 @@ namespace internal } + template void process_dofs_vectorized_transpose(const unsigned int dofs_per_cell, const unsigned int * dof_indices, - VectorType & vec, + const VectorType & vec, VectorizedArray *dof_values, std::integral_constant) const { @@ -3702,6 +3809,8 @@ namespace internal dof_values[d][v] = vector_access(vec, dof_indices[v] + d); } + + // variant where VectorType::value_type is the same as Number -> can call // gather template @@ -3715,12 +3824,14 @@ namespace internal res.gather(vec.begin() + constant_offset, indices); } + + // variant where VectorType::value_type is not the same as Number -> must // manually load the data template void process_dof_gather(const unsigned int * indices, - VectorType & vec, + const VectorType & vec, const unsigned int constant_offset, VectorizedArray &res, std::integral_constant) const @@ -3730,37 +3841,47 @@ namespace internal res[v] = vector_access(vec, indices[v] + constant_offset); } + + template void process_dof_global(const types::global_dof_index index, - VectorType & vec, + const VectorType & vec, Number & res) const { - res = const_cast(vec)(index); + res = vec(index); } + + void pre_constraints(const Number &, Number &res) const { res = Number(); } + + template void process_constraint(const unsigned int index, const Number weight, - VectorType & vec, + const VectorType & vec, Number & res) const { res += weight * vector_access(vec, index); } + + void post_constraints(const Number &sum, Number &write_pos) const { write_pos = sum; } + + void process_empty(VectorizedArray &res) const { @@ -3768,7 +3889,10 @@ namespace internal } }; - // A class to use the same code to read from and write to vector + + + // 2. A class to add values to the vector during + // FEEvaluation::distribute_local_to_global() call template struct VectorDistributorLocalToGlobal { @@ -3776,9 +3900,11 @@ namespace internal void process_dof(const unsigned int index, VectorType &vec, Number &res) const { - vector_access(vec, index) += res; + vector_access_add(vec, index, res); } + + template void process_dofs_vectorized(const unsigned int dofs_per_cell, @@ -3798,6 +3924,8 @@ namespace internal } } + + template void process_dofs_vectorized(const unsigned int dofs_per_cell, @@ -3809,12 +3937,14 @@ namespace internal for (unsigned int i = 0; i < dofs_per_cell; ++i) for (unsigned int v = 0; v < VectorizedArray::n_array_elements; ++v) - vector_access(vec, - dof_index + v + - i * VectorizedArray::n_array_elements) += - dof_values[i][v]; + vector_access_add(vec, + dof_index + v + + i * VectorizedArray::n_array_elements, + dof_values[i][v]); } + + template void process_dofs_vectorized_transpose(const unsigned int dofs_per_cell, @@ -3827,6 +3957,8 @@ namespace internal true, dofs_per_cell, dof_values, dof_indices, vec.begin()); } + + template void process_dofs_vectorized_transpose(const unsigned int dofs_per_cell, @@ -3838,9 +3970,11 @@ namespace internal for (unsigned int d = 0; d < dofs_per_cell; ++d) for (unsigned int v = 0; v < VectorizedArray::n_array_elements; ++v) - vector_access(vec, dof_indices[v] + d) += dof_values[d][v]; + vector_access_add(vec, dof_indices[v] + d, dof_values[d][v]); } + + // variant where VectorType::value_type is the same as Number -> can call // scatter template @@ -3864,6 +3998,8 @@ namespace internal # endif } + + // variant where VectorType::value_type is not the same as Number -> must // manually append all data template @@ -3876,24 +4012,30 @@ namespace internal { for (unsigned int v = 0; v < VectorizedArray::n_array_elements; ++v) - vector_access(vec, indices[v] + constant_offset) += res[v]; + vector_access_add(vec, indices[v] + constant_offset, res[v]); } + + template void process_dof_global(const types::global_dof_index index, VectorType & vec, Number & res) const { - vec(index) += res; + vector_access_add_global(vec, index, res); } + + void pre_constraints(const Number &input, Number &res) const { res = input; } + + template void process_constraint(const unsigned int index, @@ -3901,20 +4043,25 @@ namespace internal VectorType & vec, Number & res) const { - vector_access(vec, index) += weight * res; + vector_access_add(vec, index, weight * res); } + + void post_constraints(const Number &, Number &) const {} + + void process_empty(VectorizedArray &) const {} }; - // A class to use the same code to read from and write to vector + + // 3. A class to set elements of the vector template struct VectorSetter { @@ -3925,6 +4072,8 @@ namespace internal vector_access(vec, index) = res; } + + template void process_dofs_vectorized(const unsigned int dofs_per_cell, @@ -3939,6 +4088,8 @@ namespace internal dof_values[i].store(vec_ptr); } + + template void process_dofs_vectorized(const unsigned int dofs_per_cell, @@ -3956,6 +4107,8 @@ namespace internal dof_values[i][v]; } + + template void process_dofs_vectorized_transpose(const unsigned int dofs_per_cell, @@ -3968,6 +4121,8 @@ namespace internal false, dofs_per_cell, dof_values, dof_indices, vec.begin()); } + + template void process_dofs_vectorized_transpose(const unsigned int dofs_per_cell, @@ -3982,6 +4137,8 @@ namespace internal vector_access(vec, dof_indices[v] + i) = dof_values[i][v]; } + + template void process_dof_gather(const unsigned int * indices, @@ -3993,6 +4150,8 @@ namespace internal res.scatter(indices, vec.begin() + constant_offset); } + + template void process_dof_gather(const unsigned int * indices, @@ -4006,6 +4165,8 @@ namespace internal vector_access(vec, indices[v] + constant_offset) = res[v]; } + + template void process_dof_global(const types::global_dof_index index, @@ -4015,10 +4176,14 @@ namespace internal vec(index) = res; } + + void pre_constraints(const Number &, Number &) const {} + + template void process_constraint(const unsigned int, @@ -4027,15 +4192,21 @@ namespace internal Number &) const {} + + void post_constraints(const Number &, Number &) const {} + + void process_empty(VectorizedArray &) const {} }; + + // allows to select between block vectors and non-block vectors, which // allows to use a unified interface for extracting blocks on block vectors // and doing nothing on usual vectors diff --git a/tests/matrix_free/fe_evaluation_type_traits_02.cc b/tests/matrix_free/fe_evaluation_type_traits_02.cc index f87bf95c1b00..6f57b2aab2d7 100644 --- a/tests/matrix_free/fe_evaluation_type_traits_02.cc +++ b/tests/matrix_free/fe_evaluation_type_traits_02.cc @@ -116,5 +116,14 @@ main() << internal::has_set_local_element>::value << std::endl; + // now check internal::vector_access_[set|add] wrappers + deallog << "internal::vector_access_set:" << std::endl; + internal::vector_access_set(dummy, 0, 0); + internal::vector_access_set(dummy2, 0, 0); + + deallog << "internal::vector_access_add:" << std::endl; + internal::vector_access_add(dummy, 0, 0); + internal::vector_access_add(dummy2, 0, 0); + deallog << "OK" << std::endl; } diff --git a/tests/matrix_free/fe_evaluation_type_traits_02.output b/tests/matrix_free/fe_evaluation_type_traits_02.output index d6fcec824872..8413d1fad52e 100644 --- a/tests/matrix_free/fe_evaluation_type_traits_02.output +++ b/tests/matrix_free/fe_evaluation_type_traits_02.output @@ -5,4 +5,10 @@ DEAL::Dummy2 = 0 DEAL::has_set_local_element: DEAL::Dummy = 1 DEAL::Dummy2 = 0 +DEAL::internal::vector_access_set: +DEAL::Dummy::set_local_element() +DEAL::Dummy2::local_element() +DEAL::internal::vector_access_add: +DEAL::Dummy::add_local_element() +DEAL::Dummy2::local_element() DEAL::OK From 74685cc3082336d0aff9560c43ba01dd6337a7ab Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Wed, 6 Mar 2019 13:43:08 +0100 Subject: [PATCH 234/507] add LA::d::Vector::set_ghost_state() and use it in VectorDataExchange::update_ghost_values_finish() to allow reading from ghosts in LA::d::Vector::local_element() const --- include/deal.II/lac/la_parallel_vector.h | 16 ++++++++++++++++ include/deal.II/matrix_free/matrix_free.h | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/include/deal.II/lac/la_parallel_vector.h b/include/deal.II/lac/la_parallel_vector.h index 840a5ca03116..8b7cbb9119ff 100644 --- a/include/deal.II/lac/la_parallel_vector.h +++ b/include/deal.II/lac/la_parallel_vector.h @@ -1192,6 +1192,13 @@ namespace LinearAlgebra bool partitioners_are_globally_compatible( const Utilities::MPI::Partitioner &part) const; + + /** + * Change the ghost state of this vector to @p ghosted. + */ + void + set_ghost_state(const bool ghosted) const; + //@} /** @@ -1812,6 +1819,15 @@ namespace LinearAlgebra return partitioner; } + + + template + inline void + Vector::set_ghost_state(const bool ghosted) const + { + vector_is_ghosted = ghosted; + } + #endif } // namespace distributed diff --git a/include/deal.II/matrix_free/matrix_free.h b/include/deal.II/matrix_free/matrix_free.h index a0134ebfe76d..e1d18fc083a7 100644 --- a/include/deal.II/matrix_free/matrix_free.h +++ b/include/deal.II/matrix_free/matrix_free.h @@ -2805,6 +2805,10 @@ namespace internal matrix_free.release_scratch_data_non_threadsafe( tmp_data[component_in_block_vector]); tmp_data[component_in_block_vector] = nullptr; + + // let vector know that ghosts are being updated and we can read from + // them + vec.set_ghost_state(true); # endif } } @@ -2938,6 +2942,9 @@ namespace internal .local_element(j + part.local_size()) = 0.; } } + + // let vector know that it's not ghosted anymore + vec.set_ghost_state(false); # endif } } From 2b4c20d6f4d9fe96e5d278b46eccdba079211967 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Thu, 7 Mar 2019 15:51:44 +0100 Subject: [PATCH 235/507] Type to string. --- doc/news/changes/minor/20190307LucaHeltai | 4 +++ include/deal.II/base/utilities.h | 23 +++++++++++++++ tests/base/utilities_15.cc | 35 +++++++++++++++++++++++ tests/base/utilities_15.output | 4 +++ 4 files changed, 66 insertions(+) create mode 100644 doc/news/changes/minor/20190307LucaHeltai create mode 100644 tests/base/utilities_15.cc create mode 100644 tests/base/utilities_15.output 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/include/deal.II/base/utilities.h b/include/deal.II/base/utilities.h index f49c3021321b..9e3c8c278fc4 100644 --- a/include/deal.II/base/utilities.h +++ b/include/deal.II/base/utilities.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ #include #include +#include #include #include #include @@ -340,6 +342,18 @@ namespace Utilities double generate_normal_random_number(const double a, const double sigma); + /** + * Return a string description of the type of the variable @p t. + * + * In general, C++ uses mangled names to identify types. This function + * uses boost::core::demangle to return a human readable string describing + * the type of the variable passed as argument. + * + * @author Luca Heltai, 2019. + */ + template + std::string + type_to_string(const T &t); /** * Calculate a fixed power, provided as a template argument, of a number. @@ -1019,6 +1033,15 @@ namespace Utilities + template + inline std::string + type_to_string(const T &t) + { + return boost::core::demangle(typeid(t).name()); + } + + + template inline Iterator lower_bound(Iterator first, Iterator last, const T &val) diff --git a/tests/base/utilities_15.cc b/tests/base/utilities_15.cc new file mode 100644 index 000000000000..e4054b9d2781 --- /dev/null +++ b/tests/base/utilities_15.cc @@ -0,0 +1,35 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// test Utilities::type_to_string() + +#include + +#include "../tests.h" + +int +main() +{ + initlog(); + + double a = 1.0; + int b = 3; + Point<2> c; + + deallog << Utilities::type_to_string(a) << std::endl + << Utilities::type_to_string(b) << std::endl + << Utilities::type_to_string(c) << std::endl; +} diff --git a/tests/base/utilities_15.output b/tests/base/utilities_15.output new file mode 100644 index 000000000000..3e6cc9b262ef --- /dev/null +++ b/tests/base/utilities_15.output @@ -0,0 +1,4 @@ + +DEAL::double +DEAL::int +DEAL::dealii::Point<2, double> From fa5b5beb0d66e21b114f3b4467115d4a4de0e757 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Thu, 7 Mar 2019 13:25:00 -0700 Subject: [PATCH 236/507] fix uninitialized reads valgrind warns about uninitialized reads in the following two MPI functions. The totals are only available on rank 0. Note that the value doesn't matter as the results will be thrown away for rank !=0. --- source/distributed/grid_refinement.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source/distributed/grid_refinement.cc b/source/distributed/grid_refinement.cc index 6de9b6a6b8a5..ccd69d2c55b3 100644 --- a/source/distributed/grid_refinement.cc +++ b/source/distributed/grid_refinement.cc @@ -260,7 +260,8 @@ namespace return c > test_threshold; }); - unsigned int total_count; + unsigned int total_count = 0; + ierr = MPI_Reduce(&my_count, &total_count, 1, @@ -270,7 +271,7 @@ namespace mpi_communicator); AssertThrowMPI(ierr); - // now adjust the range. if we have to many cells, we take the upper + // now adjust the range. if we have too many cells, we take the upper // half of the previous range, otherwise the lower half. if we have // hit the right number, then set the range to the exact value. // slave nodes also update their own interesting_range, however their @@ -369,7 +370,8 @@ namespace if (criteria(i) > test_threshold) my_error += criteria(i); - double total_error; + double total_error = 0.; + ierr = MPI_Reduce(&my_error, &total_error, 1, @@ -379,7 +381,7 @@ namespace mpi_communicator); AssertThrowMPI(ierr); - // now adjust the range. if we have to many cells, we take the upper + // now adjust the range. if we have too many cells, we take the upper // half of the previous range, otherwise the lower half. if we have // hit the right number, then set the range to the exact value. // slave nodes also update their own interesting_range, however their From cf869efca396e8f53d9a2ec727c6f37d0b6be1dc Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Wed, 6 Mar 2019 22:48:18 +0000 Subject: [PATCH 237/507] Fix a bug where add_and_dot was giving the wrong results if the vector size was greater than 4096 --- doc/news/changes/minor/20190306BrunoTurcksin | 4 ++ include/deal.II/lac/cuda_kernels.templates.h | 2 +- tests/cuda/cuda_vector_05.cu | 71 ++++++++++++++++++++ tests/cuda/cuda_vector_05.output | 2 + 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 doc/news/changes/minor/20190306BrunoTurcksin create mode 100644 tests/cuda/cuda_vector_05.cu create mode 100644 tests/cuda/cuda_vector_05.output 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/include/deal.II/lac/cuda_kernels.templates.h b/include/deal.II/lac/cuda_kernels.templates.h index cadeb4d11a39..d42e469329e1 100644 --- a/include/deal.II/lac/cuda_kernels.templates.h +++ b/include/deal.II/lac/cuda_kernels.templates.h @@ -517,7 +517,7 @@ namespace LinearAlgebra else res_buf[local_idx] = 0.; - for (unsigned int i = 1; i < block_size; ++i) + for (unsigned int i = 1; i < chunk_size; ++i) { const unsigned int idx = global_idx + i * block_size; if (idx < N) diff --git a/tests/cuda/cuda_vector_05.cu b/tests/cuda/cuda_vector_05.cu new file mode 100644 index 000000000000..d11c59877478 --- /dev/null +++ b/tests/cuda/cuda_vector_05.cu @@ -0,0 +1,71 @@ +// --------------------------------------------------------------------- +// +// 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 + +#include +#include + +#include +#include +#include + +#include "../tests.h" + +// There was a bug where add_and_dot would give the wrong result if the size of +// the vectors was greater than BLOCK_SIZE*CHUNK_SIZE. + +void +test() +{ + const unsigned int size = 4100; + LinearAlgebra::CUDAWrappers::Vector a(size); + LinearAlgebra::CUDAWrappers::Vector b(size); + Vector a_host(size); + Vector b_host(size); + + LinearAlgebra::ReadWriteVector read_write_1(size); + LinearAlgebra::ReadWriteVector read_write_2(size); + + for (unsigned int i = 0; i < size; ++i) + { + read_write_1[i] = i; + read_write_2[i] = 5. + i; + a_host[i] = i; + b_host[i] = 5. + i; + } + + a.import(read_write_1, VectorOperation::insert); + b.import(read_write_2, VectorOperation::insert); + AssertThrow(a.add_and_dot(2., a, b) == a_host.add_and_dot(2., a_host, b_host), + ExcMessage("Problem in add_and_dot")); +} + + +int +main(int argc, char **argv) +{ + initlog(); + deallog.depth_console(0); + + init_cuda(); + + test(); + + deallog << "OK" << std::endl; + + return 0; +} diff --git a/tests/cuda/cuda_vector_05.output b/tests/cuda/cuda_vector_05.output new file mode 100644 index 000000000000..0fd8fc12f0b4 --- /dev/null +++ b/tests/cuda/cuda_vector_05.output @@ -0,0 +1,2 @@ + +DEAL::OK From e68d75d19c94cd100b1b312669641b1f6a8bc90a Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Fri, 8 Mar 2019 19:13:06 +0100 Subject: [PATCH 238/507] Fix renumbering of mg dofs for FE_Q --- source/dofs/dof_handler_policy.cc | 59 +++-- tests/multigrid/renumbering_08.cc | 130 ++++++++++ ...mbering_08.with_p4est=true.mpirun=2.output | 227 ++++++++++++++++++ 3 files changed, 392 insertions(+), 24 deletions(-) create mode 100644 tests/multigrid/renumbering_08.cc create mode 100644 tests/multigrid/renumbering_08.with_p4est=true.mpirun=2.output diff --git a/source/dofs/dof_handler_policy.cc b/source/dofs/dof_handler_policy.cc index aa9b53c70372..a2f2eca38fe4 100644 --- a/source/dofs/dof_handler_policy.cc +++ b/source/dofs/dof_handler_policy.cc @@ -3097,6 +3097,7 @@ namespace internal const unsigned int level, const bool check_validity) { + (void)check_validity; Assert(level < dof_handler.get_triangulation().n_levels(), ExcInternalError()); @@ -3116,18 +3117,21 @@ namespace internal d, dof_handler.get_fe().dofs_per_vertex); - if (check_validity) - Assert(idx != numbers::invalid_dof_index, - ExcInternalError()); - if (idx != numbers::invalid_dof_index) - i->set_index(level, - d, - dof_handler.get_fe().dofs_per_vertex, - (indices_we_care_about.size() == 0) ? - (new_numbers[idx]) : - (new_numbers[indices_we_care_about - .index_within_set(idx)])); + { + Assert(check_validity == false || + (indices_we_care_about.size() > 0 ? + indices_we_care_about.is_element(idx) : + (idx < new_numbers.size())), + ExcInternalError()); + i->set_index(level, + d, + dof_handler.get_fe().dofs_per_vertex, + (indices_we_care_about.size() == 0) ? + (new_numbers[idx]) : + (new_numbers[indices_we_care_about + .index_within_set(idx)])); + } } } @@ -3215,10 +3219,12 @@ namespace internal typename DoFHandler<2, spacedim>::level_cell_iterator cell, endc = dof_handler.end(level); for (cell = dof_handler.begin(level); cell != endc; ++cell) - for (unsigned int line = 0; - line < GeometryInfo<2>::faces_per_cell; - ++line) - cell->face(line)->set_user_flag(); + if (cell->level_subdomain_id() != + numbers::artificial_subdomain_id) + for (unsigned int line = 0; + line < GeometryInfo<2>::faces_per_cell; + ++line) + cell->face(line)->set_user_flag(); for (typename DoFHandler<2, spacedim>::cell_iterator cell = dof_handler.begin(); @@ -3283,10 +3289,12 @@ namespace internal typename DoFHandler<3, spacedim>::level_cell_iterator cell, endc = dof_handler.end(level); for (cell = dof_handler.begin(level); cell != endc; ++cell) - for (unsigned int line = 0; - line < GeometryInfo<3>::lines_per_cell; - ++line) - cell->line(line)->set_user_flag(); + if (cell->level_subdomain_id() != + numbers::artificial_subdomain_id) + for (unsigned int line = 0; + line < GeometryInfo<3>::lines_per_cell; + ++line) + cell->line(line)->set_user_flag(); for (typename DoFHandler<3, spacedim>::cell_iterator cell = dof_handler.begin(); @@ -3322,10 +3330,12 @@ namespace internal // those quads logically belong to the same level as the cell, // at least for isotropic refinement for (cell = dof_handler.begin(level); cell != endc; ++cell) - for (unsigned int quad = 0; - quad < GeometryInfo<3>::quads_per_cell; - ++quad) - cell->quad(quad)->set_user_flag(); + if (cell->level_subdomain_id() != + numbers::artificial_subdomain_id) + for (unsigned int quad = 0; + quad < GeometryInfo<3>::quads_per_cell; + ++quad) + cell->quad(quad)->set_user_flag(); for (typename DoFHandler<3, spacedim>::cell_iterator cell = dof_handler.begin(); @@ -5898,7 +5908,8 @@ namespace internal // in case we do not own any of the given level (but only some remote // processor), we do not need to call the renumbering - if (level < this->dof_handler->get_triangulation().n_levels()) + if (level < this->dof_handler->get_triangulation().n_levels() && + relevant_dofs.n_elements() > 0) Implementation::renumber_mg_dofs( ghosted_new_numbers, relevant_dofs, *dof_handler, level, true); #else diff --git a/tests/multigrid/renumbering_08.cc b/tests/multigrid/renumbering_08.cc new file mode 100644 index 000000000000..64d388beb44d --- /dev/null +++ b/tests/multigrid/renumbering_08.cc @@ -0,0 +1,130 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// check renumbering the degrees of freedom on the multigrid levels in +// parallel for FE_Q, otherwise similar to renumbering_05 + +#include + +#include + +#include + +#include +#include + +#include + +#include "../tests.h" + +using namespace std; + + +template +void +print_dof_numbers(const DoFHandler &dof) +{ + std::vector dof_indices(dof.get_fe().dofs_per_cell); + deallog << "DoF numbers on active cells" << std::endl; + for (auto cell : dof.active_cell_iterators()) + if (!cell->is_artificial()) + { + cell->get_dof_indices(dof_indices); + deallog << "cell " << cell->id() << ": "; + for (types::global_dof_index i : dof_indices) + deallog << i << " "; + deallog << std::endl; + } + for (unsigned int l = 0; l < dof.get_triangulation().n_global_levels(); ++l) + { + deallog << "DoF numbers on level " << l << std::endl; + for (auto cell : dof.cell_iterators_on_level(l)) + if (cell->level_subdomain_id() != numbers::artificial_subdomain_id) + { + cell->get_mg_dof_indices(dof_indices); + deallog << "cell " << cell->id() << ": "; + for (types::global_dof_index i : dof_indices) + deallog << i << " "; + deallog << std::endl; + } + } +} + +template +void +check() +{ + FE_Q fe(2); + + parallel::distributed::Triangulation tr( + MPI_COMM_WORLD, + Triangulation::limit_level_difference_at_vertices, + parallel::distributed::Triangulation::construct_multigrid_hierarchy); + for (unsigned int cycle = 0; cycle < 5; ++cycle) + { + tr.clear(); + const unsigned int n_refine = cycle / 3; + const unsigned int remainder = cycle % 3; + Point p1; + for (unsigned int d = 0; d < dim; ++d) + p1[d] = -1; + Point p2; + for (unsigned int d = 0; d < remainder; ++d) + p2[d] = 2.8; + for (unsigned int d = remainder; d < dim; ++d) + p2[d] = 1; + std::vector subdivisions(dim, 1); + for (unsigned int d = 0; d < remainder; ++d) + subdivisions[d] = 2; + GridGenerator::subdivided_hyper_rectangle(tr, subdivisions, p1, p2); + + DoFHandler mgdof(tr); + mgdof.distribute_dofs(fe); + mgdof.distribute_mg_dofs(); + + print_dof_numbers(mgdof); + + // compute a renumbering on the level degrees of freedom by simply + // flipping the local numbers + for (unsigned int l = 0; l < tr.n_global_levels(); ++l) + { + std::vector new_indices; + if (mgdof.locally_owned_mg_dofs(l).n_elements() > 0) + { + const types::global_dof_index first = + mgdof.locally_owned_mg_dofs(l).nth_index_in_set(0); + const types::global_dof_index last = + first + mgdof.locally_owned_mg_dofs(l).n_elements(); + for (unsigned int i = 0; i < last - first; ++i) + new_indices.push_back(last - 1 - i); + } + mgdof.renumber_dofs(l, new_indices); + } + + print_dof_numbers(mgdof); + } +} + + +int +main(int argc, char **argv) +{ + Utilities::MPI::MPI_InitFinalize mpi(argc, argv); + MPILogInitAll log; + + check<2>(); + check<3>(); +} diff --git a/tests/multigrid/renumbering_08.with_p4est=true.mpirun=2.output b/tests/multigrid/renumbering_08.with_p4est=true.mpirun=2.output new file mode 100644 index 000000000000..9f389f39c949 --- /dev/null +++ b/tests/multigrid/renumbering_08.with_p4est=true.mpirun=2.output @@ -0,0 +1,227 @@ + +DEAL:0::DoF numbers on active cells +DEAL:0::DoF numbers on level 0 +DEAL:0::DoF numbers on active cells +DEAL:0::DoF numbers on level 0 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:0::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:0::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:0::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 8 7 6 5 4 3 2 1 0 +DEAL:0::cell 1_0:: 7 14 5 13 3 12 11 10 9 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:0::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:0::cell 2_0:: 2 3 15 16 17 18 7 19 20 +DEAL:0::cell 3_0:: 3 10 16 21 18 22 13 23 24 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:0::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:0::cell 2_0:: 2 3 15 16 17 18 7 19 20 +DEAL:0::cell 3_0:: 3 10 16 21 18 22 13 23 24 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:0::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:0::cell 2_0:: 2 3 15 16 17 18 7 19 20 +DEAL:0::cell 3_0:: 3 10 16 21 18 22 13 23 24 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 14 13 12 11 10 9 8 7 6 +DEAL:0::cell 1_0:: 13 5 11 4 9 3 2 1 0 +DEAL:0::cell 2_0:: 12 11 24 23 22 21 7 20 19 +DEAL:0::cell 3_0:: 11 4 23 18 21 17 1 16 15 +DEAL:0::DoF numbers on active cells +DEAL:0::DoF numbers on level 0 +DEAL:0::DoF numbers on active cells +DEAL:0::DoF numbers on level 0 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:0::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:0::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:0::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 8 7 6 5 4 3 2 1 0 +DEAL:0::cell 1_0:: 7 14 5 13 3 12 11 10 9 +DEAL:0::DoF numbers on active cells +DEAL:0::DoF numbers on level 0 +DEAL:0::DoF numbers on active cells +DEAL:0::DoF numbers on level 0 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +DEAL:0::cell 1_0:: 25 44 23 43 21 42 19 41 17 40 39 38 13 37 36 35 9 34 7 33 5 32 31 30 29 28 27 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:0::cell 2_0:: 2 3 45 46 6 7 47 48 49 50 11 51 52 53 15 54 18 19 55 56 57 58 23 59 60 61 62 +DEAL:0::cell 3_0:: 3 28 46 63 7 30 48 64 50 65 33 66 53 67 36 68 19 38 56 69 58 70 41 71 72 73 74 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:0::cell 2_0:: 2 3 45 46 6 7 47 48 49 50 11 51 52 53 15 54 18 19 55 56 57 58 23 59 60 61 62 +DEAL:0::cell 3_0:: 3 28 46 63 7 30 48 64 50 65 33 66 53 67 36 68 19 38 56 69 58 70 41 71 72 73 74 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:0::cell 2_0:: 2 3 45 46 6 7 47 48 49 50 11 51 52 53 15 54 18 19 55 56 57 58 23 59 60 61 62 +DEAL:0::cell 3_0:: 3 28 46 63 7 30 48 64 50 65 33 66 53 67 36 68 19 38 56 69 58 70 41 71 72 73 74 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 +DEAL:0::cell 1_0:: 43 17 41 16 39 15 37 14 35 13 12 11 31 10 9 8 27 7 25 6 23 5 4 3 2 1 0 +DEAL:0::cell 2_0:: 42 41 74 73 38 37 72 71 70 69 33 68 67 66 29 65 26 25 64 63 62 61 21 60 59 58 57 +DEAL:0::cell 3_0:: 41 16 73 56 37 14 71 55 69 54 11 53 66 52 8 51 25 6 63 50 61 49 3 48 47 46 45 +DEAL:0::DoF numbers on active cells +DEAL:0::DoF numbers on level 0 +DEAL:0::DoF numbers on active cells +DEAL:0::DoF numbers on level 0 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:0::DoF numbers on active cells +DEAL:0::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:0::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:0::DoF numbers on level 0 +DEAL:0::cell 0_0:: 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +DEAL:0::cell 1_0:: 25 44 23 43 21 42 19 41 17 40 39 38 13 37 36 35 9 34 7 33 5 32 31 30 29 28 27 + +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 8 7 6 5 4 3 2 1 0 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 8 7 6 5 4 3 2 1 0 +DEAL:1::cell 1_0:: 7 14 5 13 3 12 11 10 9 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:1::cell 2_0:: 2 3 15 16 17 18 7 19 20 +DEAL:1::cell 3_0:: 3 10 16 21 18 22 13 23 24 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:1::cell 2_0:: 2 3 15 16 17 18 7 19 20 +DEAL:1::cell 3_0:: 3 10 16 21 18 22 13 23 24 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:1::cell 2_0:: 2 3 15 16 17 18 7 19 20 +DEAL:1::cell 3_0:: 3 10 16 21 18 22 13 23 24 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 14 13 12 11 10 9 8 7 6 +DEAL:1::cell 1_0:: 13 5 11 4 9 3 2 1 0 +DEAL:1::cell 2_0:: 12 11 24 23 22 21 7 20 19 +DEAL:1::cell 3_0:: 11 4 23 18 21 17 1 16 15 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 8 7 6 5 4 3 2 1 0 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 +DEAL:1::cell 1_0:: 1 9 3 10 5 11 12 13 14 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 8 7 6 5 4 3 2 1 0 +DEAL:1::cell 1_0:: 7 14 5 13 3 12 11 10 9 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +DEAL:1::cell 1_0:: 25 44 23 43 21 42 19 41 17 40 39 38 13 37 36 35 9 34 7 33 5 32 31 30 29 28 27 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:1::cell 2_0:: 2 3 45 46 6 7 47 48 49 50 11 51 52 53 15 54 18 19 55 56 57 58 23 59 60 61 62 +DEAL:1::cell 3_0:: 3 28 46 63 7 30 48 64 50 65 33 66 53 67 36 68 19 38 56 69 58 70 41 71 72 73 74 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:1::cell 2_0:: 2 3 45 46 6 7 47 48 49 50 11 51 52 53 15 54 18 19 55 56 57 58 23 59 60 61 62 +DEAL:1::cell 3_0:: 3 28 46 63 7 30 48 64 50 65 33 66 53 67 36 68 19 38 56 69 58 70 41 71 72 73 74 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:1::cell 2_0:: 2 3 45 46 6 7 47 48 49 50 11 51 52 53 15 54 18 19 55 56 57 58 23 59 60 61 62 +DEAL:1::cell 3_0:: 3 28 46 63 7 30 48 64 50 65 33 66 53 67 36 68 19 38 56 69 58 70 41 71 72 73 74 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 +DEAL:1::cell 1_0:: 43 17 41 16 39 15 37 14 35 13 12 11 31 10 9 8 27 7 25 6 23 5 4 3 2 1 0 +DEAL:1::cell 2_0:: 42 41 74 73 38 37 72 71 70 69 33 68 67 66 29 65 26 25 64 63 62 61 21 60 59 58 57 +DEAL:1::cell 3_0:: 41 16 73 56 37 14 71 55 69 54 11 53 66 52 8 51 25 6 63 50 61 49 3 48 47 46 45 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:1::DoF numbers on active cells +DEAL:1::cell 0_0:: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +DEAL:1::cell 1_0:: 1 27 3 28 5 29 7 30 9 31 32 33 13 34 35 36 17 37 19 38 21 39 40 41 42 43 44 +DEAL:1::DoF numbers on level 0 +DEAL:1::cell 0_0:: 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +DEAL:1::cell 1_0:: 25 44 23 43 21 42 19 41 17 40 39 38 13 37 36 35 9 34 7 33 5 32 31 30 29 28 27 + From 0f870e05318229d0edf00e05f3c93739fc7e4f73 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Fri, 8 Mar 2019 19:13:14 +0100 Subject: [PATCH 239/507] Add changelog --- doc/news/changes/minor/20190308MartinKronbichler | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 doc/news/changes/minor/20190308MartinKronbichler 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) From c58e98040508b2581a6ed3a59cce9d0a9a94ab22 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Wed, 6 Mar 2019 17:52:18 +0100 Subject: [PATCH 240/507] add internal type-traits to be used with VectorDataExchange of matrix-free framework --- include/deal.II/matrix_free/fe_evaluation.h | 151 +------- include/deal.II/matrix_free/matrix_free.h | 1 + include/deal.II/matrix_free/type_traits.h | 328 ++++++++++++++++++ tests/matrix_free/matrix_free_type_traits.cc | 94 +++++ ...free_type_traits.with_trilinos=true.output | 22 ++ 5 files changed, 447 insertions(+), 149 deletions(-) create mode 100644 include/deal.II/matrix_free/type_traits.h create mode 100644 tests/matrix_free/matrix_free_type_traits.cc create mode 100644 tests/matrix_free/matrix_free_type_traits.with_trilinos=true.output diff --git a/include/deal.II/matrix_free/fe_evaluation.h b/include/deal.II/matrix_free/fe_evaluation.h index 5ae7b1905cd0..0a8e2c29e259 100644 --- a/include/deal.II/matrix_free/fe_evaluation.h +++ b/include/deal.II/matrix_free/fe_evaluation.h @@ -35,6 +35,7 @@ #include #include #include +#include DEAL_II_NAMESPACE_OPEN @@ -3401,155 +3402,7 @@ FEEvaluationBase::read_cell_data( namespace internal { - // a helper type-trait that leverage SFINAE to figure out if type T has - // ... T::local_element() const - template - struct has_local_element - { - private: - // this will work always. - // we let it be void as we know T::local_element() (if exists) should - // certainly return something - static void - detect(...); - - // this detecter will work only if we have "... T::local_element() const" - // and its return type will be the same as local_element(), - // that we expect to be T::value_type - template - static decltype(std::declval().local_element(0)) - detect(const U &); - - public: - // finally here we check if our detector has non-void return type - // T::value_type. This will happen if compiler can use second detector, - // otherwise SFINAE let it work with the more general first one that is void - static const bool value = - !std::is_same()))>::value; - }; - - // We need to have a separate declaration for static const members - template - const bool has_local_element::value; - - - - // a helper type-trait that leverage SFINAE to figure out if type T has - // void T::add_local_element(const uint, const typename T::value_type) - template - struct has_add_local_element - { - private: - static int - detect(...); - - template - static decltype( - std::declval().add_local_element(0, typename T::value_type())) - detect(const U &); - - public: - static const bool value = - !std::is_same()))>::value; - }; - - // We need to have a separate declaration for static const members - template - const bool has_add_local_element::value; - - - - // a helper type-trait that leverage SFINAE to figure out if type T has - // void T::set_local_element(const uint, const typename T::value_type) - template - struct has_set_local_element - { - private: - static int - detect(...); - - template - static decltype( - std::declval().set_local_element(0, typename T::value_type())) - detect(const U &); - - public: - static const bool value = - !std::is_same()))>::value; - }; - - // We need to have a separate declaration for static const members - template - const bool has_set_local_element::value; - - - - // same as above to check - // bool T::partitioners_are_compatible(const Utilities::MPI::Partitioner &) - // const - template - struct has_partitioners_are_compatible - { - private: - static void - detect(...); - - template - static decltype(std::declval().partitioners_are_compatible( - std::declval())) - detect(const U &); - - public: - static const bool value = - std::is_same()))>::value; - }; - - // We need to have a separate declaration for static const members - template - const bool has_partitioners_are_compatible::value; - - - // same as above to check - // ... T::begin() const - template - struct has_begin - { - private: - static void - detect(...); - - template - static decltype(std::declval().begin()) - detect(const U &); - - public: - static const bool value = - !std::is_same()))>::value; - }; - - // We need to have a separate declaration for static const members - template - const bool has_begin::value; - - - // type trait for vector T and Number to see if - // we can do vectorized load/save. - // for VectorReader and VectorDistributorLocalToGlobal we assume that - // if both begin() and local_element() - // exist, then begin() + offset == local_element(offset) - template - struct is_vectorizable - { - static const bool value = - has_begin::value && - (has_local_element::value || is_serial_vector::value) && - std::is_same::value; - }; - - // We need to have a separate declaration for static const members - template - const bool is_vectorizable::value; - + // below we use type-traits from matrix-free/type_traits.h // access to generic const vectors that have operator (). // FIXME: this is wrong for Trilinos/Petsc MPI vectors diff --git a/include/deal.II/matrix_free/matrix_free.h b/include/deal.II/matrix_free/matrix_free.h index e1d18fc083a7..6397dec747d8 100644 --- a/include/deal.II/matrix_free/matrix_free.h +++ b/include/deal.II/matrix_free/matrix_free.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include diff --git a/include/deal.II/matrix_free/type_traits.h b/include/deal.II/matrix_free/type_traits.h new file mode 100644 index 000000000000..70d784d954d2 --- /dev/null +++ b/include/deal.II/matrix_free/type_traits.h @@ -0,0 +1,328 @@ +// --------------------------------------------------------------------- +// +// 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_matrix_free_type_traits_h +#define dealii_matrix_free_type_traits_h + +// various type-traits used exclusively within the matrix-free framework + +#include + +#include + +#include + + +DEAL_II_NAMESPACE_OPEN + + +namespace internal +{ + // + // type traits for FEEvaluation + // + + // a helper type-trait that leverage SFINAE to figure out if type T has + // ... T::local_element() const + template + struct has_local_element + { + private: + // this will work always. + // we let it be void as we know T::local_element() (if exists) should + // certainly return something + static void + detect(...); + + // this detecter will work only if we have "... T::local_element() const" + // and its return type will be the same as local_element(), + // that we expect to be T::value_type + template + static decltype(std::declval().local_element(0)) + detect(const U &); + + public: + // finally here we check if our detector has non-void return type + // T::value_type. This will happen if compiler can use second detector, + // otherwise SFINAE let it work with the more general first one that is void + static const bool value = + !std::is_same()))>::value; + }; + + // We need to have a separate declaration for static const members + template + const bool has_local_element::value; + + + + // a helper type-trait that leverage SFINAE to figure out if type T has + // void T::add_local_element(const uint, const typename T::value_type) + template + struct has_add_local_element + { + private: + static int + detect(...); + + template + static decltype( + std::declval().add_local_element(0, typename T::value_type())) + detect(const U &); + + public: + static const bool value = + !std::is_same()))>::value; + }; + + // We need to have a separate declaration for static const members + template + const bool has_add_local_element::value; + + + + // a helper type-trait that leverage SFINAE to figure out if type T has + // void T::set_local_element(const uint, const typename T::value_type) + template + struct has_set_local_element + { + private: + static int + detect(...); + + template + static decltype( + std::declval().set_local_element(0, typename T::value_type())) + detect(const U &); + + public: + static const bool value = + !std::is_same()))>::value; + }; + + // We need to have a separate declaration for static const members + template + const bool has_set_local_element::value; + + + + // same as above to check + // bool T::partitioners_are_compatible(const Utilities::MPI::Partitioner &) + // const + template + struct has_partitioners_are_compatible + { + private: + static void + detect(...); + + template + static decltype(std::declval().partitioners_are_compatible( + std::declval())) + detect(const U &); + + public: + static const bool value = + std::is_same()))>::value; + }; + + // We need to have a separate declaration for static const members + template + const bool has_partitioners_are_compatible::value; + + + // same as above to check + // ... T::begin() const + template + struct has_begin + { + private: + static void + detect(...); + + template + static decltype(std::declval().begin()) + detect(const U &); + + public: + static const bool value = + !std::is_same()))>::value; + }; + + // We need to have a separate declaration for static const members + template + const bool has_begin::value; + + + // type trait for vector T and Number to see if + // we can do vectorized load/save. + // for VectorReader and VectorDistributorLocalToGlobal we assume that + // if both begin() and local_element() + // exist, then begin() + offset == local_element(offset) + template + struct is_vectorizable + { + static const bool value = + has_begin::value && + (has_local_element::value || is_serial_vector::value) && + std::is_same::value; + }; + + // We need to have a separate declaration for static const members + template + const bool is_vectorizable::value; + + + // + // type-traits for Matrix-Free + // + // similar to type traits in FEEvaluation, below we add type-traits + // to distinguish between vectors that provide different interface for + // operations like update_ghost_values(), compress(), etc. + // see internal::has_local_element in fe_evaluation.h that documents + // how those type traits work. + + // a helper type-trait that leverage SFINAE to figure out if type T has + // void T::update_ghost_values_start(const uint) const + template + struct has_update_ghost_values_start + { + private: + static bool + detect(...); + + template + static decltype(std::declval().update_ghost_values_start(0)) + detect(const U &); + + public: + static const bool value = + !std::is_same()))>::value; + }; + + // We need to have a separate declaration for static const members + template + const bool has_update_ghost_values_start::value; + + + + // a helper type-trait that leverage SFINAE to figure out if type T has + // void T:: compress_start(const uint, VectorOperation::values) + template + struct has_compress_start + { + private: + static bool + detect(...); + + template + static decltype(std::declval().compress_start(0, VectorOperation::add)) + detect(const U &); + + public: + static const bool value = + !std::is_same()))>::value; + }; + + // We need to have a separate declaration for static const members + template + const bool has_compress_start::value; + + + + // type trait for vector T to see if + // we do a custom data exchange route. + // We assume that if both begin() and local_element() + // exist, then begin() + offset == local_element(offset) + template + struct has_exchange_on_subset + { + static const bool value = + has_begin::value && has_local_element::value; + }; + + // We need to have a separate declaration for static const members + template + const bool has_exchange_on_subset::value; + + + + // a helper type-trait that leverage SFINAE to figure out if type T has + // T::communication_block_size + template + struct has_communication_block_size + { + private: + static void + detect(...); + + template + static decltype(U::communication_block_size) + detect(const U &); + + public: + static const bool value = + !std::is_same()))>::value; + }; + + // We need to have a separate declaration for static const members + template + const bool has_communication_block_size::value; + + + + // type trait for vector T to see if + // we need to do any data exchange for this vector type at all. + // is_serial_vector<> would have been enough, but in some circumstances + // (like calculation of diagonals for matrix-free operators) + // a dummy InVector == unsigned int is provided. + // Thus we have to treat this case as well. + template + struct is_serial_or_dummy + { + private: + // catches all cases including unsigned int + static void + detect(...); + + // catches serial vectors + template < + typename U, + typename std::enable_if::value, U>::type * = nullptr> + static void + detect(const U &); + + // catches parallel vectors + template < + typename U, + typename std::enable_if::value, U>::type * = nullptr> + static bool + detect(const U &); + + public: + static const bool value = + std::is_same()))>::value; + }; + + // We need to have a separate declaration for static const members + template + const bool is_serial_or_dummy::value; + + +} // namespace internal + +DEAL_II_NAMESPACE_CLOSE + +#endif diff --git a/tests/matrix_free/matrix_free_type_traits.cc b/tests/matrix_free/matrix_free_type_traits.cc new file mode 100644 index 000000000000..fb0f597c0c64 --- /dev/null +++ b/tests/matrix_free/matrix_free_type_traits.cc @@ -0,0 +1,94 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + + +// test internal typetraits used in matrix_free.h + +#include +#include +#include + +#include + +#include "../tests.h" + +int +main() +{ + initlog(); + + deallog << "has_update_ghost_values_start:" << std::endl + << "LinearAlgebra::distributed::Vector = " + << internal::has_update_ghost_values_start< + LinearAlgebra::distributed::Vector>::value + << std::endl + << "TrilinosWrappers::MPI::Vector = " + << internal::has_update_ghost_values_start< + TrilinosWrappers::MPI::Vector>::value + << std::endl + << "Vector = " + << internal::has_update_ghost_values_start>::value + << std::endl; + + deallog << "has_compress_start:" << std::endl + << "LinearAlgebra::distributed::Vector = " + << internal::has_compress_start< + LinearAlgebra::distributed::Vector>::value + << std::endl + << "TrilinosWrappers::MPI::Vector = " + << internal::has_compress_start::value + << std::endl + << "Vector = " << internal::has_compress_start>::value + << std::endl; + + deallog + << "has_exchange_on_subset:" << std::endl + << "LinearAlgebra::distributed::Vector = " + << internal::has_exchange_on_subset< + LinearAlgebra::distributed::Vector>::value + << std::endl + << "TrilinosWrappers::MPI::Vector = " + << internal::has_exchange_on_subset::value + << std::endl + << "Vector = " << internal::has_exchange_on_subset>::value + << std::endl; + + + deallog << "has_communication_block_size:" << std::endl + << "LinearAlgebra::distributed::Vector = " + << internal::has_communication_block_size< + LinearAlgebra::distributed::Vector>::value + << std::endl + << "LinearAlgebra::distributed::BlockVector = " + << internal::has_communication_block_size< + LinearAlgebra::distributed::BlockVector>::value + << std::endl; + + deallog << "is_serial_or_dummy:" << std::endl + << "LinearAlgebra::distributed::Vector = " + << internal::is_serial_or_dummy< + LinearAlgebra::distributed::Vector>::value + << std::endl + << "TrilinosWrappers::MPI::Vector = " + << internal::is_serial_or_dummy::value + << std::endl + << "Vector = " << internal::is_serial_or_dummy>::value + << std::endl + << "unsigned int = " + << internal::is_serial_or_dummy::value << std::endl; + + deallog << "OK" << std::endl; +} diff --git a/tests/matrix_free/matrix_free_type_traits.with_trilinos=true.output b/tests/matrix_free/matrix_free_type_traits.with_trilinos=true.output new file mode 100644 index 000000000000..0382073a9358 --- /dev/null +++ b/tests/matrix_free/matrix_free_type_traits.with_trilinos=true.output @@ -0,0 +1,22 @@ + +DEAL::has_update_ghost_values_start: +DEAL::LinearAlgebra::distributed::Vector = 1 +DEAL::TrilinosWrappers::MPI::Vector = 0 +DEAL::Vector = 0 +DEAL::has_compress_start: +DEAL::LinearAlgebra::distributed::Vector = 1 +DEAL::TrilinosWrappers::MPI::Vector = 0 +DEAL::Vector = 0 +DEAL::has_exchange_on_subset: +DEAL::LinearAlgebra::distributed::Vector = 1 +DEAL::TrilinosWrappers::MPI::Vector = 0 +DEAL::Vector = 0 +DEAL::has_communication_block_size: +DEAL::LinearAlgebra::distributed::Vector = 0 +DEAL::LinearAlgebra::distributed::BlockVector = 1 +DEAL::is_serial_or_dummy: +DEAL::LinearAlgebra::distributed::Vector = 0 +DEAL::TrilinosWrappers::MPI::Vector = 0 +DEAL::Vector = 1 +DEAL::unsigned int = 1 +DEAL::OK From 9f980e3688eb7ebd3ec15e2b05191bbf300ed088 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Thu, 7 Mar 2019 09:29:28 +0100 Subject: [PATCH 241/507] use type-traits to generalize VectorDataExchange --- include/deal.II/matrix_free/matrix_free.h | 382 +++++++++++++++++++++- 1 file changed, 367 insertions(+), 15 deletions(-) diff --git a/include/deal.II/matrix_free/matrix_free.h b/include/deal.II/matrix_free/matrix_free.h index 6397dec747d8..19edab9683f6 100644 --- a/include/deal.II/matrix_free/matrix_free.h +++ b/include/deal.II/matrix_free/matrix_free.h @@ -2642,6 +2642,12 @@ namespace internal // set up static constexpr unsigned int channel_shift = 103; + + + /** + * Constructor. Takes MF data, flag for face access in DG and + * number of components. + */ VectorDataExchange( const dealii::MatrixFree &matrix_free, const typename dealii::MatrixFree::DataAccessOnFaces @@ -2667,6 +2673,11 @@ namespace internal 3); } + + + /** + * Destructor. + */ ~VectorDataExchange() // NOLINT { # ifdef DEAL_II_WITH_MPI @@ -2676,9 +2687,16 @@ namespace internal # endif } + + + /** + * Go through all components in MF object and choose the one + * whose partitioner is compatible with the Partitioner in this component. + */ + template unsigned int - find_vector_in_mf(const LinearAlgebra::distributed::Vector &vec, - const bool check_global_compatibility = true) const + find_vector_in_mf(const VectorType &vec, + const bool check_global_compatibility = true) const { unsigned int mf_component = numbers::invalid_unsigned_int; (void)check_global_compatibility; @@ -2698,6 +2716,12 @@ namespace internal return mf_component; } + + + /** + * Get partitioner for the given @p mf_component taking into + * account vector_face_access set in constructor. + */ const Utilities::MPI::Partitioner & get_partitioner(const unsigned int mf_component) const { @@ -2717,13 +2741,87 @@ namespace internal .vector_partitioner_face_variants[2]; } + + + /** + * Start update_ghost_value for serial vectors + */ + template ::value, + VectorType>::type * = nullptr> void - update_ghost_values_start( - const unsigned int component_in_block_vector, - const LinearAlgebra::distributed::Vector &vec) + update_ghost_values_start(const unsigned int /*component_in_block_vector*/, + const VectorType & /*vec*/) + {} + + + /** + * Start update_ghost_value for vectors that do not support + * the split into _start() and finish() stages + */ + template ::value && + !is_serial_or_dummy::value, + VectorType>::type * = nullptr> + void + update_ghost_values_start(const unsigned int component_in_block_vector, + const VectorType & vec) { (void)component_in_block_vector; bool ghosts_set = vec.has_ghost_elements(); + if (ghosts_set) + ghosts_were_set = true; + + vec.update_ghost_values(); + } + + + + /** + * Start update_ghost_value for vectors that _do_ support + * the split into _start() and finish() stages, but don't support + * exchange on a subset of DoFs + */ + template ::value && + !has_exchange_on_subset::value, + VectorType>::type * = nullptr> + void + update_ghost_values_start(const unsigned int component_in_block_vector, + const VectorType & vec) + { + (void)component_in_block_vector; + bool ghosts_set = vec.has_ghost_elements(); + if (ghosts_set) + ghosts_were_set = true; + + vec.update_ghost_values_start(component_in_block_vector + channel_shift); + } + + + + /** + * Finally, start update_ghost_value for vectors that _do_ support + * the split into _start() and finish() stages and also support + * exchange on a subset of DoFs, + * i.e. LinearAlgebra::distributed::Vector + */ + template ::value && + has_exchange_on_subset::value, + VectorType>::type * = nullptr> + void + update_ghost_values_start(const unsigned int component_in_block_vector, + const VectorType & vec) + { + static_assert( + std::is_same::value, + "Type mismatch between VectorType and VectorDataExchange"); + (void)component_in_block_vector; + bool ghosts_set = vec.has_ghost_elements(); if (ghosts_set) ghosts_were_set = true; if (vector_face_access == @@ -2767,11 +2865,67 @@ namespace internal } } + + + /** + * Finish update_ghost_value for vectors that do not support + * the split into _start() and finish() stages and serial vectors + */ + template < + typename VectorType, + typename std::enable_if::value, + VectorType>::type * = nullptr> + void + update_ghost_values_finish(const unsigned int /*component_in_block_vector*/, + const VectorType & /*vec*/) + {} + + + + /** + * Finish update_ghost_value for vectors that _do_ support + * the split into _start() and finish() stages, but don't support + * exchange on a subset of DoFs + */ + template ::value && + !has_exchange_on_subset::value, + VectorType>::type * = nullptr> + void + update_ghost_values_finish(const unsigned int component_in_block_vector, + const VectorType & vec) + { + (void)component_in_block_vector; + Assert( + (vector_face_access == + dealii::MatrixFree::DataAccessOnFaces::unspecified || + vec.size() == 0), + ExcNotImplemented()); + + vec.update_ghost_values_finish(); + } + + + + /** + * Finish update_ghost_value for vectors that _do_ support + * the split into _start() and finish() stages and also support + * exchange on a subset of DoFs, + * i.e. LinearAlgebra::distributed::Vector + */ + template ::value && + has_exchange_on_subset::value, + VectorType>::type * = nullptr> void - update_ghost_values_finish( - const unsigned int component_in_block_vector, - const LinearAlgebra::distributed::Vector &vec) + update_ghost_values_finish(const unsigned int component_in_block_vector, + const VectorType & vec) { + static_assert( + std::is_same::value, + "Type mismatch between VectorType and VectorDataExchange"); (void)component_in_block_vector; if (vector_face_access == dealii::MatrixFree::DataAccessOnFaces::unspecified || @@ -2814,12 +2968,81 @@ namespace internal } } + + + /** + * Start compress for serial vectors + */ + template ::value, + VectorType>::type * = nullptr> + void + compress_start(const unsigned int /*component_in_block_vector*/, + VectorType & /*vec*/) + {} + + + + /** + * Start compress for vectors that do not support + * the split into _start() and finish() stages + */ + template ::value && + !is_serial_or_dummy::value, + VectorType>::type * = nullptr> void compress_start(const unsigned int component_in_block_vector, - LinearAlgebra::distributed::Vector &vec) + VectorType & vec) { (void)component_in_block_vector; Assert(vec.has_ghost_elements() == false, ExcNotImplemented()); + vec.compress(dealii::VectorOperation::add); + } + + + + /** + * Start compress for vectors that _do_ support + * the split into _start() and finish() stages, but don't support + * exchange on a subset of DoFs + */ + template < + typename VectorType, + typename std::enable_if::value && + !has_exchange_on_subset::value, + VectorType>::type * = nullptr> + void + compress_start(const unsigned int component_in_block_vector, + VectorType & vec) + { + (void)component_in_block_vector; + Assert(vec.has_ghost_elements() == false, ExcNotImplemented()); + vec.compress_start(component_in_block_vector + channel_shift); + } + + + + /** + * Start compress for vectors that _do_ support + * the split into _start() and finish() stages and also support + * exchange on a subset of DoFs, + * i.e. LinearAlgebra::distributed::Vector + */ + template < + typename VectorType, + typename std::enable_if::value && + has_exchange_on_subset::value, + VectorType>::type * = nullptr> + void + compress_start(const unsigned int component_in_block_vector, + VectorType & vec) + { + static_assert( + std::is_same::value, + "Type mismatch between VectorType and VectorDataExchange"); + (void)component_in_block_vector; + Assert(vec.has_ghost_elements() == false, ExcNotImplemented()); if (vector_face_access == dealii::MatrixFree::DataAccessOnFaces::unspecified || vec.size() == 0) @@ -2859,10 +3082,60 @@ namespace internal } } + + + /** + * Finish compress for vectors that do not support + * the split into _start() and finish() stages and serial vectors + */ + template ::value, + VectorType>::type * = nullptr> + void + compress_finish(const unsigned int /*component_in_block_vector*/, + VectorType & /*vec*/) + {} + + + + /** + * Finish compress for vectors that _do_ support + * the split into _start() and finish() stages, but don't support + * exchange on a subset of DoFs + */ + template < + typename VectorType, + typename std::enable_if::value && + !has_exchange_on_subset::value, + VectorType>::type * = nullptr> + void + compress_finish(const unsigned int component_in_block_vector, + VectorType & vec) + { + (void)component_in_block_vector; + vec.compress_finish(dealii::VectorOperation::add); + } + + + + /** + * Start compress for vectors that _do_ support + * the split into _start() and finish() stages and also support + * exchange on a subset of DoFs, + * i.e. LinearAlgebra::distributed::Vector + */ + template < + typename VectorType, + typename std::enable_if::value && + has_exchange_on_subset::value, + VectorType>::type * = nullptr> void compress_finish(const unsigned int component_in_block_vector, - LinearAlgebra::distributed::Vector &vec) + VectorType & vec) { + static_assert( + std::is_same::value, + "Type mismatch between VectorType and VectorDataExchange"); (void)component_in_block_vector; if (vector_face_access == dealii::MatrixFree::DataAccessOnFaces::unspecified || @@ -2905,10 +3178,54 @@ namespace internal } } + + + /** + * Reset all ghost values for serial vectors + */ + template ::value, + VectorType>::type * = nullptr> + void + reset_ghost_values(const VectorType & /*vec*/) const + {} + + + + /** + * Reset all ghost values for vector that don't support + * exchange on a subset of DoFs + */ + template < + typename VectorType, + typename std::enable_if::value && + !is_serial_or_dummy::value, + VectorType>::type * = nullptr> + void + reset_ghost_values(const VectorType &vec) const + { + if (ghosts_were_set == true) + return; + + vec.zero_out_ghosts(); + } + + + + /** + * Reset all ghost values for vector that _do_ support + * exchange on a subset of DoFs, i.e. + * LinearAlgebra::distributed::Vector + */ + template ::value, + VectorType>::type * = nullptr> void - reset_ghost_values( - const LinearAlgebra::distributed::Vector &vec) const + reset_ghost_values(const VectorType &vec) const { + static_assert( + std::is_same::value, + "Type mismatch between VectorType and VectorDataExchange"); if (ghosts_were_set == true) return; @@ -2950,10 +3267,22 @@ namespace internal } } + + + /** + * Zero out vector region for vector that _do_ support + * exchange on a subset of DoFs <==> begin() + ind == local_element(ind), + * i.e. LinearAlgebra::distributed::Vector + */ + template ::value, + VectorType>::type * = nullptr> void - zero_vector_region(const unsigned int range_index, - LinearAlgebra::distributed::Vector &vec) const + zero_vector_region(const unsigned int range_index, VectorType &vec) const { + static_assert( + std::is_same::value, + "Type mismatch between VectorType and VectorDataExchange"); if (range_index == numbers::invalid_unsigned_int) vec = Number(); else @@ -2989,6 +3318,29 @@ namespace internal } } + + + /** + * Zero out vector region for vector that do _not_ support + * exchange on a subset of DoFs <==> begin() + ind == local_element(ind) + */ + template < + typename VectorType, + typename std::enable_if::value, + VectorType>::type * = nullptr> + void + zero_vector_region(const unsigned int range_index, VectorType &vec) const + { + if (range_index == numbers::invalid_unsigned_int) + vec = typename VectorType::value_type(); + else + { + Assert(false, ExcNotImplemented()); + } + } + + + const dealii::MatrixFree &matrix_free; const typename dealii::MatrixFree::DataAccessOnFaces vector_face_access; @@ -2997,7 +3349,7 @@ namespace internal std::vector *> tmp_data; std::vector> requests; # endif - }; + }; // VectorDataExchange template unsigned int From 75c9fd3d9ede2fef51846b7314ff4a27da267304 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Thu, 7 Mar 2019 09:33:00 +0100 Subject: [PATCH 242/507] streamline treatment of block and non-block vectors in MatrixFree using updated VectorDataExchange --- include/deal.II/matrix_free/matrix_free.h | 509 +++++++++------------- 1 file changed, 218 insertions(+), 291 deletions(-) diff --git a/include/deal.II/matrix_free/matrix_free.h b/include/deal.II/matrix_free/matrix_free.h index 19edab9683f6..4877be670b78 100644 --- a/include/deal.II/matrix_free/matrix_free.h +++ b/include/deal.II/matrix_free/matrix_free.h @@ -3405,166 +3405,17 @@ namespace internal return components; } - template - void - update_ghost_values_start_block(const VectorStruct &vec, - const unsigned int channel, - std::integral_constant, - VectorDataExchange &exchanger); - template - void - reset_ghost_values_block(const VectorStruct &vec, - std::integral_constant, - VectorDataExchange &exchanger); - template - void - update_ghost_values_finish_block(const VectorStruct &vec, - const unsigned int channel, - std::integral_constant, - VectorDataExchange &exchanger); - template - void - compress_start_block(const VectorStruct &vec, - const unsigned int channel, - std::integral_constant, - VectorDataExchange &exchanger); - template - void - compress_finish_block(const VectorStruct &vec, - const unsigned int channel, - std::integral_constant, - VectorDataExchange &exchanger); - template - void - zero_vector_region_block(const unsigned int range_index, - VectorStruct &, - std::integral_constant, - VectorDataExchange &); - - template - void - update_ghost_values_start_block(const VectorStruct &, - const unsigned int, - std::integral_constant, - VectorDataExchange &) - {} - template - void - reset_ghost_values_block(const VectorStruct &, - std::integral_constant, - VectorDataExchange &) - {} - template - void - update_ghost_values_finish_block(const VectorStruct &, - const unsigned int, - std::integral_constant, - VectorDataExchange &) - {} - template - void - compress_start_block(const VectorStruct &, - const unsigned int, - std::integral_constant, - VectorDataExchange &) - {} - template - void - compress_finish_block(const VectorStruct &, - const unsigned int, - std::integral_constant, - VectorDataExchange &) - {} - template - void - zero_vector_region_block(const unsigned int range_index, - VectorStruct & vec, - std::integral_constant, - VectorDataExchange &) - { - if (range_index == 0 || range_index == numbers::invalid_unsigned_int) - vec = 0; - } - - - - // if the input vector did not have ghosts imported, clear them here again - // in order to avoid subsequent operations e.g. in linear solvers to work - // with ghosts all the time - template - inline void - reset_ghost_values(const VectorStruct & vec, - VectorDataExchange &exchanger) - { - reset_ghost_values_block( - vec, - std::integral_constant::value>(), - exchanger); - } - - - - template - inline void - reset_ghost_values(const LinearAlgebra::distributed::Vector &vec, - VectorDataExchange &exchanger) - { - exchanger.reset_ghost_values(vec); - } - - - - template - inline void - reset_ghost_values(const std::vector &vec, - VectorDataExchange &exchanger) - { - // return immediately if there is nothing to do. - if (exchanger.ghosts_were_set == true) - return; - - for (unsigned int comp = 0; comp < vec.size(); comp++) - reset_ghost_values(vec[comp], exchanger); - } - - - - template - inline void - reset_ghost_values(const std::vector &vec, - VectorDataExchange & exchanger) - { - // return immediately if there is nothing to do. - if (exchanger.ghosts_were_set == true) - return; - - for (unsigned int comp = 0; comp < vec.size(); comp++) - reset_ghost_values(*vec[comp], exchanger); - } - - - - template - inline void - reset_ghost_values_block(const VectorStruct &vec, - std::integral_constant, - VectorDataExchange &exchanger) - { - // return immediately if there is nothing to do. - if (exchanger.ghosts_were_set == true) - return; - - for (unsigned int i = 0; i < vec.n_blocks(); ++i) - reset_ghost_values(vec.block(i), exchanger); - } - // A helper function to identify block vectors with many components where we // should not try to overlap computations and communication because there - // would be too many outstanding communication requests. This is the base case - // for generic vectors - template + // would be too many outstanding communication requests. + + // default value for vectors that do not have communication_block_size + template < + typename VectorStruct, + typename std::enable_if::value, + VectorStruct>::type * = nullptr> constexpr unsigned int get_communication_block_size(const VectorStruct &) { @@ -3573,46 +3424,70 @@ namespace internal - // Specialized case for the block vector which as the additional member - // variable - template + template < + typename VectorStruct, + typename std::enable_if::value, + VectorStruct>::type * = nullptr> constexpr unsigned int - get_communication_block_size( - const LinearAlgebra::distributed::BlockVector &) + get_communication_block_size(const VectorStruct &) { - return LinearAlgebra::distributed::BlockVector< - Number>::communication_block_size; + return VectorStruct::communication_block_size; } - template - inline void + // -------------------------------------------------------------------------- + // below we have wrappers to distinguish between block and non-block vectors. + // -------------------------------------------------------------------------- + + // + // update_ghost_values_start + // + + // update_ghost_values for block vectors + template ::value, + VectorStruct>::type * = nullptr> + void update_ghost_values_start(const VectorStruct & vec, VectorDataExchange &exchanger, const unsigned int channel = 0) { - update_ghost_values_start_block( - vec, - channel, - std::integral_constant::value>(), - exchanger); + if (get_communication_block_size(vec) < vec.n_blocks()) + { + // don't forget to set ghosts_were_set, that otherwise happens + // inside VectorDataExchange::update_ghost_values_start() + exchanger.ghosts_were_set = vec.has_ghost_elements(); + vec.update_ghost_values(); + } + else + { + for (unsigned int i = 0; i < vec.n_blocks(); ++i) + update_ghost_values_start(vec.block(i), exchanger, channel + i); + } } - template - inline void - update_ghost_values_start( - const LinearAlgebra::distributed::Vector &vec, - VectorDataExchange & exchanger, - const unsigned int channel = 0) + // update_ghost_values for non-block vectors + template ::value, + VectorStruct>::type * = nullptr> + void + update_ghost_values_start(const VectorStruct & vec, + VectorDataExchange &exchanger, + const unsigned int channel = 0) { exchanger.update_ghost_values_start(channel, vec); } + // update_ghost_values_start() for vector of vectors template inline void update_ghost_values_start(const std::vector &vec, @@ -3628,6 +3503,7 @@ namespace internal + // update_ghost_values_start() for vector of pointers to vectors template inline void update_ghost_values_start(const std::vector &vec, @@ -3643,56 +3519,50 @@ namespace internal - template - inline void - update_ghost_values_start_block(const VectorStruct &vec, - const unsigned int channel, - std::integral_constant, - VectorDataExchange &exchanger) + // + // update_ghost_values_finish + // + + // for block vectors + template ::value, + VectorStruct>::type * = nullptr> + void + update_ghost_values_finish(const VectorStruct & vec, + VectorDataExchange &exchanger, + const unsigned int channel = 0) { if (get_communication_block_size(vec) < vec.n_blocks()) { - // don't forget to set ghosts_were_set, that otherwise happens - // inside VectorDataExchange::update_ghost_values_start() - exchanger.ghosts_were_set = vec.has_ghost_elements(); - vec.update_ghost_values(); + // do nothing, everything has already been completed in the _start() + // call } else - { - for (unsigned int i = 0; i < vec.n_blocks(); ++i) - update_ghost_values_start(vec.block(i), exchanger, channel + i); - } + for (unsigned int i = 0; i < vec.n_blocks(); ++i) + update_ghost_values_finish(vec.block(i), exchanger, channel + i); } - template - inline void + // for non-block vectors + template ::value, + VectorStruct>::type * = nullptr> + void update_ghost_values_finish(const VectorStruct & vec, VectorDataExchange &exchanger, const unsigned int channel = 0) - { - update_ghost_values_finish_block( - vec, - channel, - std::integral_constant::value>(), - exchanger); - } - - - - template - inline void - update_ghost_values_finish( - const LinearAlgebra::distributed::Vector &vec, - VectorDataExchange & exchanger, - const unsigned int channel = 0) { exchanger.update_ghost_values_finish(channel, vec); } + // for vector of vectors template inline void update_ghost_values_finish(const std::vector &vec, @@ -3708,6 +3578,7 @@ namespace internal + // for vector of pointers to vectors template inline void update_ghost_values_finish(const std::vector &vec, @@ -3723,51 +3594,47 @@ namespace internal - template + // + // compress_start + // + + // for block vectors + template ::value, + VectorStruct>::type * = nullptr> inline void - update_ghost_values_finish_block(const VectorStruct &vec, - const unsigned int channel, - std::integral_constant, - VectorDataExchange &exchanger) + compress_start(VectorStruct & vec, + VectorDataExchange &exchanger, + const unsigned int channel = 0) { if (get_communication_block_size(vec) < vec.n_blocks()) - { - // do nothing, everything has already been completed in the _start() - // call - } + vec.compress(dealii::VectorOperation::add); else for (unsigned int i = 0; i < vec.n_blocks(); ++i) - update_ghost_values_finish(vec.block(i), exchanger, channel + i); + compress_start(vec.block(i), exchanger, channel + i); } - template + // for non-block vectors + template ::value, + VectorStruct>::type * = nullptr> inline void compress_start(VectorStruct & vec, VectorDataExchange &exchanger, const unsigned int channel = 0) - { - compress_start_block( - vec, - channel, - std::integral_constant::value>(), - exchanger); - } - - - - template - inline void - compress_start(LinearAlgebra::distributed::Vector &vec, - VectorDataExchange & exchanger, - const unsigned int channel = 0) { exchanger.compress_start(channel, vec); } + // for std::vector of vectors template inline void compress_start(std::vector & vec, @@ -3783,6 +3650,7 @@ namespace internal + // for std::vector of pointer to vectors template inline void compress_start(std::vector & vec, @@ -3798,48 +3666,50 @@ namespace internal - template + // + // compress_finish + // + + // for block vectors + template ::value, + VectorStruct>::type * = nullptr> inline void - compress_start_block(VectorStruct & vec, - const unsigned int channel, - std::integral_constant, - VectorDataExchange &exchanger) + compress_finish(VectorStruct & vec, + VectorDataExchange &exchanger, + const unsigned int channel = 0) { if (get_communication_block_size(vec) < vec.n_blocks()) - vec.compress(dealii::VectorOperation::add); + { + // do nothing, everything has already been completed in the _start() + // call + } else for (unsigned int i = 0; i < vec.n_blocks(); ++i) - compress_start(vec.block(i), exchanger, channel + i); + compress_finish(vec.block(i), exchanger, channel + i); } - template + // for non-block vectors + template ::value, + VectorStruct>::type * = nullptr> inline void compress_finish(VectorStruct & vec, VectorDataExchange &exchanger, const unsigned int channel = 0) - { - compress_finish_block( - vec, - channel, - std::integral_constant::value>(), - exchanger); - } - - - - template - inline void - compress_finish(LinearAlgebra::distributed::Vector &vec, - VectorDataExchange & exchanger, - const unsigned int channel = 0) { exchanger.compress_finish(channel, vec); } + // for std::vector of vectors template inline void compress_finish(std::vector & vec, @@ -3855,6 +3725,7 @@ namespace internal + // for std::vector of pointer to vectors template inline void compress_finish(std::vector & vec, @@ -3870,51 +3741,119 @@ namespace internal + // + // reset_ghost_values: + // + // if the input vector did not have ghosts imported, clear them here again + // in order to avoid subsequent operations e.g. in linear solvers to work + // with ghosts all the time + // + + // for block vectors + template ::value, + VectorStruct>::type * = nullptr> + inline void + reset_ghost_values(const VectorStruct & vec, + VectorDataExchange &exchanger) + { + // return immediately if there is nothing to do. + if (exchanger.ghosts_were_set == true) + return; + + for (unsigned int i = 0; i < vec.n_blocks(); ++i) + reset_ghost_values(vec.block(i), exchanger); + } + + + + // for non-block vectors + template ::value, + VectorStruct>::type * = nullptr> + inline void + reset_ghost_values(const VectorStruct & vec, + VectorDataExchange &exchanger) + { + exchanger.reset_ghost_values(vec); + } + + + + // for std::vector of vectors template inline void - compress_finish_block(VectorStruct & vec, - const unsigned int channel, - std::integral_constant, - VectorDataExchange &exchanger) + reset_ghost_values(const std::vector &vec, + VectorDataExchange &exchanger) { - if (get_communication_block_size(vec) < vec.n_blocks()) - { - // do nothing, everything has already been completed in the _start() - // call - } - else - for (unsigned int i = 0; i < vec.n_blocks(); ++i) - compress_finish(vec.block(i), exchanger, channel + i); + // return immediately if there is nothing to do. + if (exchanger.ghosts_were_set == true) + return; + + for (unsigned int comp = 0; comp < vec.size(); comp++) + reset_ghost_values(vec[comp], exchanger); } + // for std::vector of pointer to vectors template inline void + reset_ghost_values(const std::vector &vec, + VectorDataExchange & exchanger) + { + // return immediately if there is nothing to do. + if (exchanger.ghosts_were_set == true) + return; + + for (unsigned int comp = 0; comp < vec.size(); comp++) + reset_ghost_values(*vec[comp], exchanger); + } + + + + // + // zero_vector_region + // + + // for block vectors + template ::value, + VectorStruct>::type * = nullptr> + inline void zero_vector_region(const unsigned int range_index, VectorStruct & vec, VectorDataExchange &exchanger) { - zero_vector_region_block( - range_index, - vec, - std::integral_constant::value>(), - exchanger); + for (unsigned int i = 0; i < vec.n_blocks(); ++i) + exchanger.zero_vector_region(range_index, vec.block(i)); } - template + // for non-block vectors + template ::value, + VectorStruct>::type * = nullptr> inline void - zero_vector_region(const unsigned int range_index, - LinearAlgebra::distributed::Vector &vec, - VectorDataExchange & exchanger) + zero_vector_region(const unsigned int range_index, + VectorStruct & vec, + VectorDataExchange &exchanger) { exchanger.zero_vector_region(range_index, vec); } + // for std::vector of vectors template inline void zero_vector_region(const unsigned int range_index, @@ -3927,6 +3866,7 @@ namespace internal + // for std::vector of pointers to vectors template inline void zero_vector_region(const unsigned int range_index, @@ -3939,19 +3879,6 @@ namespace internal - template - inline void - zero_vector_region_block(const unsigned int range_index, - VectorStruct & vec, - std::integral_constant, - VectorDataExchange &exchanger) - { - for (unsigned int i = 0; i < vec.n_blocks(); ++i) - zero_vector_region(range_index, vec.block(i), exchanger); - } - - - namespace MatrixFreeFunctions { // struct to select between a const interface and a non-const interface From 2052911df8eb516594cf6bd2e27d200e0716c07b Mon Sep 17 00:00:00 2001 From: David Wells Date: Sat, 9 Mar 2019 10:26:53 -0500 Subject: [PATCH 243/507] Fix link targets in frames. The first link is currently unclickable and it should have 'target="body"' anyway since it should not be framed. The second link works but it should not be framed. --- doc/documentation.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/documentation.html b/doc/documentation.html index ee8bee879069..9977691eb5fc 100644 --- a/doc/documentation.html +++ b/doc/documentation.html @@ -36,7 +36,7 @@
  • Code gallery
  • Manual
  • Wolfgang's lectures
  • -
  • Technical reports
  • +
  • Technical reports
  • Publications
  • @@ -52,7 +52,7 @@
  • CMake internals
  • Writing documentation
  • Porting
  • -
  • Coding conventions
  • +
  • Coding conventions
  • Testsuite
  • From f6539ceb99759acae824c6286d1f238e6554b6d6 Mon Sep 17 00:00:00 2001 From: Marc Fehling Date: Thu, 21 Feb 2019 08:12:36 +0100 Subject: [PATCH 244/507] Introduced p-refinement and p-coarsening flags. --- doc/news/changes/minor/20190224MarcFehling | 7 + include/deal.II/dofs/dof_accessor.h | 78 ++++ include/deal.II/dofs/dof_accessor.templates.h | 338 ++++++++++++++++++ include/deal.II/hp/dof_handler.h | 16 +- include/deal.II/hp/dof_level.h | 16 + source/hp/dof_handler.cc | 66 +++- source/hp/dof_level.cc | 4 +- tests/hp/refine_and_coarsen_flags.cc | 92 +++++ tests/hp/refine_and_coarsen_flags.output | 16 + tests/serialization/hp_dof_handler_01.cc | 19 + ...f_handler_01.with_64bit_indices=off.output | 28 +- ...of_handler_01.with_64bit_indices=on.output | 28 +- 12 files changed, 670 insertions(+), 38 deletions(-) create mode 100644 doc/news/changes/minor/20190224MarcFehling create mode 100644 tests/hp/refine_and_coarsen_flags.cc create mode 100644 tests/hp/refine_and_coarsen_flags.output 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/include/deal.II/dofs/dof_accessor.h b/include/deal.II/dofs/dof_accessor.h index ae1826087776..98280ee71017 100644 --- a/include/deal.II/dofs/dof_accessor.h +++ b/include/deal.II/dofs/dof_accessor.h @@ -596,6 +596,23 @@ class DoFAccessor DeclExceptionMsg(ExcInvalidObject, "This accessor object has not been " "associated with any DoFHandler object."); + /** + * Exception + * + * @ingroup Exceptions + */ + DeclExceptionMsg(ExcRefinementNotSupported, + "DoFHandler is not of type hp::DoFHandler and " + "does not support p-refinement."); + /** + * Exception + * + * @ingroup Exceptions + */ + DeclExceptionMsg(ExcCoarseningNotSupported, + "DoFHandler is not of type hp::DoFHandler and " + "does not support p-coarsening."); + /** * Exception * @@ -1945,6 +1962,67 @@ class DoFCellAccessor : public DoFAccessor + static bool + p_refine_flag_set(const DoFCellAccessor, + level_dof_access> &accessor) + { + (void)accessor; + // ::DoFHandler does not support p-refinement + Assert(false, + (typename std::decay::type::ExcRefinementNotSupported())); + return false; + } + + + + template + static bool + p_refine_flag_set( + const DoFCellAccessor, + level_dof_access> &accessor) + { + Assert( + accessor.dof_handler != nullptr, + (typename std::decay::type::ExcInvalidObject())); + Assert(static_cast(accessor.level()) < + accessor.dof_handler->levels.size(), + ExcMessage("DoFHandler not initialized")); + + const auto &p_refine_flags = + accessor.dof_handler->levels[accessor.level()]->p_refine_flags; + Assert(static_cast(accessor.present_index) < + p_refine_flags.size(), + ExcIndexRange(accessor.present_index, 0, p_refine_flags.size())); + + return p_refine_flags[accessor.present_index]; + } + + + + template + static void + set_p_refine_flag(const DoFCellAccessor, + level_dof_access> &accessor) + { + (void)accessor; + // ::DoFHandler does not support p-refinement + Assert(false, + (typename std::decay::type::ExcRefinementNotSupported())); + } + + + + template + static void + set_p_refine_flag( + const DoFCellAccessor, + level_dof_access> &accessor) + { + Assert( + accessor.dof_handler != nullptr, + (typename std::decay::type::ExcInvalidObject())); + Assert(static_cast(accessor.level()) < + accessor.dof_handler->levels.size(), + ExcMessage("DoFHandler not initialized")); + + auto &p_refine_flags = + accessor.dof_handler->levels[accessor.level()]->p_refine_flags; + Assert(static_cast(accessor.present_index) < + p_refine_flags.size(), + ExcIndexRange(accessor.present_index, 0, p_refine_flags.size())); + + p_refine_flags[accessor.present_index] = true; + } + + + + template + static void + clear_p_refine_flag(const DoFCellAccessor, + level_dof_access> &accessor) + { + (void)accessor; + // ::DoFHandler does not support p-refinement + Assert(false, + (typename std::decay::type::ExcRefinementNotSupported())); + } + + + + template + static void + clear_p_refine_flag( + const DoFCellAccessor, + level_dof_access> &accessor) + { + Assert( + accessor.dof_handler != nullptr, + (typename std::decay::type::ExcInvalidObject())); + Assert(static_cast(accessor.level()) < + accessor.dof_handler->levels.size(), + ExcMessage("DoFHandler not initialized")); + + auto &p_refine_flags = + accessor.dof_handler->levels[accessor.level()]->p_refine_flags; + Assert(static_cast(accessor.present_index) < + p_refine_flags.size(), + ExcIndexRange(accessor.present_index, 0, p_refine_flags.size())); + + p_refine_flags[accessor.present_index] = false; + } + + + + template + static bool + p_coarsen_flag_set(const DoFCellAccessor, + level_dof_access> &accessor) + { + (void)accessor; + // ::DoFHandler does not support p-coarsening + Assert(false, + (typename std::decay::type::ExcCoarseningNotSupported())); + return false; + } + + + + template + static bool + p_coarsen_flag_set( + const DoFCellAccessor, + level_dof_access> &accessor) + { + Assert( + accessor.dof_handler != nullptr, + (typename std::decay::type::ExcInvalidObject())); + Assert(static_cast(accessor.level()) < + accessor.dof_handler->levels.size(), + ExcMessage("DoFHandler not initialized")); + + const auto &p_coarsen_flags = + accessor.dof_handler->levels[accessor.level()]->p_coarsen_flags; + Assert(static_cast(accessor.present_index) < + p_coarsen_flags.size(), + ExcIndexRange(accessor.present_index, + 0, + p_coarsen_flags.size())); + + return p_coarsen_flags[accessor.present_index]; + } + + + + template + static void + set_p_coarsen_flag(const DoFCellAccessor, + level_dof_access> &accessor) + { + (void)accessor; + // ::DoFHandler does not support p-coarsening + Assert(false, + (typename std::decay::type::ExcCoarseningNotSupported())); + } + + + + template + static void + set_p_coarsen_flag( + const DoFCellAccessor, + level_dof_access> &accessor) + { + Assert( + accessor.dof_handler != nullptr, + (typename std::decay::type::ExcInvalidObject())); + Assert(static_cast(accessor.level()) < + accessor.dof_handler->levels.size(), + ExcMessage("DoFHandler not initialized")); + + auto &p_coarsen_flags = + accessor.dof_handler->levels[accessor.level()]->p_coarsen_flags; + Assert(static_cast(accessor.present_index) < + p_coarsen_flags.size(), + ExcIndexRange(accessor.present_index, + 0, + p_coarsen_flags.size())); + + p_coarsen_flags[accessor.present_index] = true; + } + + + + template + static void + clear_p_coarsen_flag(const DoFCellAccessor, + level_dof_access> &accessor) + { + (void)accessor; + // ::DoFHandler does not support p-coarsening + Assert(false, + (typename std::decay::type::ExcCoarseningNotSupported())); + } + + + + template + static void + clear_p_coarsen_flag( + const DoFCellAccessor, + level_dof_access> &accessor) + { + Assert( + accessor.dof_handler != nullptr, + (typename std::decay::type::ExcInvalidObject())); + Assert(static_cast(accessor.level()) < + accessor.dof_handler->levels.size(), + ExcMessage("DoFHandler not initialized")); + + auto &p_coarsen_flags = + accessor.dof_handler->levels[accessor.level()]->p_coarsen_flags; + Assert(static_cast(accessor.present_index) < + p_coarsen_flags.size(), + ExcIndexRange(accessor.present_index, + 0, + p_coarsen_flags.size())); + + p_coarsen_flags[accessor.present_index] = false; + } + + + template ::distribute_local_to_global( } + +template +inline bool +DoFCellAccessor::p_refine_flag_set() const +{ + Assert(this->used(), TriaAccessorExceptions::ExcCellNotUsed()); + // cells flagged for refinement must be active + // (the @p set_p_refine_flag function checks this, + // but activity may change when refinement is + // executed and for some reason the refine + // flag is not cleared). + Assert(this->active() || !dealii::internal::DoFCellAccessorImplementation:: + Implementation::p_refine_flag_set(*this), + (typename CellAccessor::ExcRefineCellNotActive())); + + return dealii::internal::DoFCellAccessorImplementation::Implementation:: + p_refine_flag_set(*this); +} + + + +template +inline void +DoFCellAccessor::set_p_refine_flag() const +{ + Assert(this->used(), TriaAccessorExceptions::ExcCellNotUsed()); + Assert(this->active(), + (typename CellAccessor::ExcRefineCellNotActive())); + Assert(!dealii::internal::DoFCellAccessorImplementation::Implementation:: + p_coarsen_flag_set(*this), + (typename CellAccessor::ExcCellFlaggedForCoarsening())); + + dealii::internal::DoFCellAccessorImplementation::Implementation:: + set_p_refine_flag(*this); +} + + + +template +inline void +DoFCellAccessor::clear_p_refine_flag() const +{ + Assert(this->used(), TriaAccessorExceptions::ExcCellNotUsed()); + Assert(this->active(), + (typename CellAccessor::ExcRefineCellNotActive())); + + dealii::internal::DoFCellAccessorImplementation::Implementation:: + clear_p_refine_flag(*this); +} + + + +template +inline bool +DoFCellAccessor::p_coarsen_flag_set() const +{ + Assert(this->used(), TriaAccessorExceptions::ExcCellNotUsed()); + // cells flagged for coarsening must be active + // (the @p set_refine_flag function checks this, + // but activity may change when refinement is + // executed and for some reason the refine + // flag is not cleared). + Assert(this->active() || !dealii::internal::DoFCellAccessorImplementation:: + Implementation::p_coarsen_flag_set(*this), + (typename CellAccessor::ExcRefineCellNotActive())); + + return dealii::internal::DoFCellAccessorImplementation::Implementation:: + p_coarsen_flag_set(*this); +} + + + +template +inline void +DoFCellAccessor::set_p_coarsen_flag() const +{ + Assert(this->used(), TriaAccessorExceptions::ExcCellNotUsed()); + Assert(this->active(), + (typename CellAccessor::ExcRefineCellNotActive())); + Assert(!dealii::internal::DoFCellAccessorImplementation::Implementation:: + p_refine_flag_set(*this), + (typename CellAccessor::ExcCellFlaggedForRefinement())); + + dealii::internal::DoFCellAccessorImplementation::Implementation:: + set_p_coarsen_flag(*this); +} + + + +template +inline void +DoFCellAccessor::clear_p_coarsen_flag() const +{ + Assert(this->used(), TriaAccessorExceptions::ExcCellNotUsed()); + Assert(this->active(), + (typename CellAccessor::ExcRefineCellNotActive())); + + dealii::internal::DoFCellAccessorImplementation::Implementation:: + clear_p_coarsen_flag(*this); +} + + DEAL_II_NAMESPACE_CLOSE #endif diff --git a/include/deal.II/hp/dof_handler.h b/include/deal.II/hp/dof_handler.h index a218d8b2a3e2..a35a1f115f21 100644 --- a/include/deal.II/hp/dof_handler.h +++ b/include/deal.II/hp/dof_handler.h @@ -1080,13 +1080,23 @@ namespace hp /** * Create default tables for the active_fe_indices in the * dealii::internal::hp::DoFLevel. They are initialized with a zero - * indicator, meaning that fe[0] is going to be used by default. This - * method is called before refinement and before distribute_dofs is - * called. It ensures each cell has a valid active_fe_index. + * indicator, meaning that fe[0] is going to be used by default. This + * method is called before refinement and while setting the finite elements + * via set_fe(). It ensures each cell has a valid active_fe_index. */ void create_active_fe_table(); + /** + * Create default tables for the p_refine_flags and p_coarsen_flags in the + * dealii::internal::hp::DoFLevel. All of them are initialized with a false + * boolean, meaning that no cell is initially flagged for p-refinement or + * p-coarsening. This method is called while setting the finite elements via + * set_fe(). + */ + void + create_p_adaptation_flags(); + /** * A function that will be triggered through a triangulation * signal just before the triangulation is modified. diff --git a/include/deal.II/hp/dof_level.h b/include/deal.II/hp/dof_level.h index 3af1013c4b33..aa70ce9dea34 100644 --- a/include/deal.II/hp/dof_level.h +++ b/include/deal.II/hp/dof_level.h @@ -184,6 +184,20 @@ namespace internal */ std::vector cell_dof_indices_cache; + /** + * Indicators for p-refinement for different cells on the current level. + * The vector stores one flag per cell, specifying whether the cell is + * scheduled for future p-refinement. + */ + std::vector p_refine_flags; + + /** + * Indicators for p-coarsening for different cells on the current level. + * The vector stores one flag per cell, specifying whether the cell is + * scheduled for future p-coarssening. + */ + std::vector p_coarsen_flags; + public: /** * Set the global index of the @p local_index-th degree of freedom @@ -491,6 +505,8 @@ namespace internal ar & this->cell_dof_indices_cache; ar & this->dof_indices; ar & this->dof_offsets; + ar & this->p_refine_flags; + ar & this->p_coarsen_flags; } } // namespace hp diff --git a/source/hp/dof_handler.cc b/source/hp/dof_handler.cc index 8e9dc7e65a9d..073cbe580438 100644 --- a/source/hp/dof_handler.cc +++ b/source/hp/dof_handler.cc @@ -90,15 +90,25 @@ namespace internal static void reserve_space_release_space(DoFHandler &dof_handler) { - // Release all space except the active_fe_indices field - // which we have to back up before + // Release all space except the fields for active_fe_indices and + // refinement flags which we have to back up before { std::vector> - active_fe_backup(dof_handler.levels.size()); + active_fe_backup(dof_handler.levels.size()); + std::vector> p_refine_flags_backup( + dof_handler.levels.size()); + std::vector> p_coarsen_flags_backup( + dof_handler.levels.size()); for (unsigned int level = 0; level < dof_handler.levels.size(); ++level) - active_fe_backup[level] = - std::move(dof_handler.levels[level]->active_fe_indices); + { + active_fe_backup[level] = + std::move(dof_handler.levels[level]->active_fe_indices); + p_refine_flags_backup[level] = + std::move(dof_handler.levels[level]->p_refine_flags); + p_coarsen_flags_backup[level] = + std::move(dof_handler.levels[level]->p_coarsen_flags); + } // delete all levels and set them up newly, since vectors // are troublesome if you want to change their size @@ -108,8 +118,13 @@ namespace internal ++level) { dof_handler.levels.emplace_back(new internal::hp::DoFLevel); + // recover backups dof_handler.levels[level]->active_fe_indices = std::move(active_fe_backup[level]); + dof_handler.levels[level]->p_refine_flags = + std::move(p_refine_flags_backup[level]); + dof_handler.levels[level]->p_coarsen_flags = + std::move(p_coarsen_flags_backup[level]); } if (dim > 1) @@ -1538,6 +1553,9 @@ namespace hp Assert(cell->active_fe_index() < fe_collection.size(), ExcInvalidFEIndex(cell->active_fe_index(), fe_collection.size())); + + // initialize all p-refinement and p-coarsening flags + create_p_adaptation_flags(); } @@ -1864,6 +1882,38 @@ namespace hp + template + void + DoFHandler::create_p_adaptation_flags() + { + Assert(fe_collection.size() > 0, ExcNoFESelected()); + Assert(tria->n_levels() > 0, + ExcMessage("The current Triangulation must not be empty.")); + Assert(tria->n_levels() == levels.size(), ExcInternalError()); + + for (unsigned int level = 0; level < tria->n_levels(); ++level) + if (levels[level]->p_refine_flags.size() == 0 && + levels[level]->p_coarsen_flags.size() == 0) + { + levels[level]->p_refine_flags.resize(tria->n_raw_cells(level), false); + levels[level]->p_coarsen_flags.resize(tria->n_raw_cells(level), + false); + } + else + { + // Either the p_refine_flags and p_coarsen_flags have size zero + // because they were just created, or the correct size. Other sizes + // indicate that something went wrong. + Assert(levels[level]->p_refine_flags.size() == + tria->n_raw_cells(level) && + levels[level]->p_coarsen_flags.size() == + tria->n_raw_cells(level), + ExcInternalError()); + } + } + + + template void DoFHandler::pre_refinement_action() @@ -1893,7 +1943,11 @@ namespace hp // Resize active_fe_indices vectors. use zero indicator to extend for (unsigned int i = 0; i < levels.size(); ++i) - levels[i]->active_fe_indices.resize(tria->n_raw_cells(i), 0); + { + levels[i]->active_fe_indices.resize(tria->n_raw_cells(i), 0); + levels[i]->p_refine_flags.resize(tria->n_raw_cells(i), false); + levels[i]->p_coarsen_flags.resize(tria->n_raw_cells(i), false); + } } diff --git a/source/hp/dof_level.cc b/source/hp/dof_level.cc index 94982880f5a3..2f2c653a7a21 100644 --- a/source/hp/dof_level.cc +++ b/source/hp/dof_level.cc @@ -248,7 +248,9 @@ namespace internal MemoryConsumption::memory_consumption(dof_indices) + MemoryConsumption::memory_consumption(dof_offsets) + MemoryConsumption::memory_consumption(cell_cache_offsets) + - MemoryConsumption::memory_consumption(cell_dof_indices_cache)); + MemoryConsumption::memory_consumption(cell_dof_indices_cache) + + MemoryConsumption::memory_consumption(p_refine_flags) + + MemoryConsumption::memory_consumption(p_coarsen_flags)); } diff --git a/tests/hp/refine_and_coarsen_flags.cc b/tests/hp/refine_and_coarsen_flags.cc new file mode 100644 index 000000000000..716107f91105 --- /dev/null +++ b/tests/hp/refine_and_coarsen_flags.cc @@ -0,0 +1,92 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2006 - 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. +// +// --------------------------------------------------------------------- + + + +// check if p-adaptive flags will be set correctly + + +#include + +#include +#include + +#include +#include + +#include "../tests.h" + + +template +void +test() +{ + Triangulation tria; + GridGenerator::hyper_cube(tria); + tria.refine_global(1); + + hp::FECollection fe_collection; + fe_collection.push_back(FE_Q(1)); + + hp::DoFHandler dh(tria); + dh.distribute_dofs(fe_collection); + + // check if flags are initialized correctly + for (const auto &cell : dh.active_cell_iterators()) + Assert(!cell->p_refine_flag_set() && !cell->p_coarsen_flag_set(), + ExcInternalError()); + + // set flags at least once + auto cell = dh.begin_active(); + cell->set_p_refine_flag(); + (++cell)->set_p_coarsen_flag(); + + // verify flags + for (const auto &cell : dh.active_cell_iterators()) + deallog << "cell:" << cell->id().to_string() + << ", refine:" << cell->p_refine_flag_set() + << ", coarsen:" << cell->p_coarsen_flag_set() << std::endl; + + // clear all flags and check if all were cleared + for (const auto &cell : dh.active_cell_iterators()) + { + cell->clear_p_refine_flag(); + Assert(!cell->p_refine_flag_set(), ExcInternalError()); + + cell->clear_p_coarsen_flag(); + Assert(!cell->p_coarsen_flag_set(), ExcInternalError()); + } +} + + +int +main() +{ + initlog(); + + deallog.push("1D"); + test<1>(); + deallog.pop(); + + deallog.push("2D"); + test<2>(); + deallog.pop(); + + deallog.push("3D"); + test<3>(); + deallog.pop(); + + deallog << "OK" << std::endl; +} diff --git a/tests/hp/refine_and_coarsen_flags.output b/tests/hp/refine_and_coarsen_flags.output new file mode 100644 index 000000000000..df5baf06f4cf --- /dev/null +++ b/tests/hp/refine_and_coarsen_flags.output @@ -0,0 +1,16 @@ + +DEAL:1D::cell:0_1:0, refine:1, coarsen:0 +DEAL:1D::cell:0_1:1, refine:0, coarsen:1 +DEAL:2D::cell:0_1:0, refine:1, coarsen:0 +DEAL:2D::cell:0_1:1, refine:0, coarsen:1 +DEAL:2D::cell:0_1:2, refine:0, coarsen:0 +DEAL:2D::cell:0_1:3, refine:0, coarsen:0 +DEAL:3D::cell:0_1:0, refine:1, coarsen:0 +DEAL:3D::cell:0_1:1, refine:0, coarsen:1 +DEAL:3D::cell:0_1:2, refine:0, coarsen:0 +DEAL:3D::cell:0_1:3, refine:0, coarsen:0 +DEAL:3D::cell:0_1:4, refine:0, coarsen:0 +DEAL:3D::cell:0_1:5, refine:0, coarsen:0 +DEAL:3D::cell:0_1:6, refine:0, coarsen:0 +DEAL:3D::cell:0_1:7, refine:0, coarsen:0 +DEAL::OK diff --git a/tests/serialization/hp_dof_handler_01.cc b/tests/serialization/hp_dof_handler_01.cc index fb997c9a6328..500a4c83630e 100644 --- a/tests/serialization/hp_dof_handler_01.cc +++ b/tests/serialization/hp_dof_handler_01.cc @@ -92,6 +92,14 @@ namespace dealii c1->active_fe_index() != c2->active_fe_index()) return false; + if (c1->active() && c2->active() && + c1->p_refine_flag_set() != c2->p_refine_flag_set()) + return false; + + if (c1->active() && c2->active() && + c1->p_coarsen_flag_set() != c2->p_coarsen_flag_set()) + return false; + // compare dofs on this cell and then on the faces if (c1->has_children() == false) { @@ -174,13 +182,24 @@ test() hp::FECollection fe_collection; fe_collection.push_back(FESystem( FE_Q(2), dim, FE_Q(1), 1)); + fe_collection.push_back(FESystem( + FE_Q(3), dim, FE_Q(2), 1)); hp::DoFHandler dof_1(tria); hp::DoFHandler dof_2(tria); + dof_1.begin_active()->set_active_fe_index(1); + dof_2.begin_active()->set_active_fe_index(1); + dof_1.distribute_dofs(fe_collection); dof_2.distribute_dofs(fe_collection); + dof_1.begin_active()->set_p_refine_flag(); + dof_2.begin_active()->set_p_refine_flag(); + + (++dof_1.begin_active())->set_p_coarsen_flag(); + (++dof_2.begin_active())->set_p_coarsen_flag(); + // right now, both hp::DoFHandlers are the same. Renumber one of them DoFRenumbering::random(dof_1); diff --git a/tests/serialization/hp_dof_handler_01.with_64bit_indices=off.output b/tests/serialization/hp_dof_handler_01.with_64bit_indices=off.output index 0792fffde608..0f3297458035 100644 --- a/tests/serialization/hp_dof_handler_01.with_64bit_indices=off.output +++ b/tests/serialization/hp_dof_handler_01.with_64bit_indices=off.output @@ -1,19 +1,19 @@ -DEAL::0 0 20 0 0 5 11 4294967295 0 8 7 4294967295 0 2 9 4294967295 0 0 13 4294967295 0 1 6 4294967295 5 0 0 4 8 12 16 0 0 14 14 0 0 0 0 1 0 0 0 0 14 0 1 14 0 1 0 14 0 0 1 0 1 0 0 14 0 1 14 0 0 0 0 0 3 0 0 9 1 0 -0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 9 -1 2 0 0 0 2 0 4294967295 4294967295 0 0 0 0 2 0 4294967295 4294967295 9 -2 4 0 65535 65535 65535 65535 4 0 0 5 10 15 20 0 5 11 0 13 4 0 13 2 9 12 2 9 1 6 3 1 6 8 7 10 4 0 4 12 3 10 4 0 0 1 2 3 1 7 23 Policy::Sequential<1,1> +DEAL::0 0 23 0 1 5 11 4294967295 0 10 0 4294967295 0 12 15 4294967295 0 2 9 1 2 9 4294967295 0 3 8 4294967295 5 0 0 4 8 12 19 0 0 16 16 0 0 0 0 1 0 0 0 0 16 0 1 16 0 1 0 16 0 0 1 0 1 0 0 16 0 1 16 0 0 0 0 0 3 0 0 9 1 0 +0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 1 0 1 0 9 +1 2 0 0 0 2 0 4294967295 4294967295 0 0 0 0 2 0 4294967295 4294967295 2 0 0 2 0 0 9 +2 4 0 1 65535 65535 65535 4 0 0 7 12 17 22 0 5 11 2 9 14 13 4 2 9 12 15 6 12 15 3 8 7 3 8 10 0 1 6 0 14 13 4 6 7 1 4 0 0 3 4 5 4 1 0 0 0 4 0 1 0 0 1 7 23 Policy::Sequential<1,1> -DEAL::0 0 125 0 0 104 43 148 4294967295 0 182 77 159 4294967295 0 80 52 164 4294967295 0 90 124 40 4294967295 0 16 36 75 4294967295 0 147 178 78 4294967295 0 118 165 185 4294967295 0 126 139 0 4294967295 0 110 73 51 4294967295 0 88 86 2 4294967295 0 72 18 11 4294967295 0 69 12 15 4294967295 0 97 66 84 4294967295 0 106 132 57 4294967295 0 4 29 8 4294967295 0 173 175 45 4294967295 0 115 145 48 4294967295 0 24 119 41 4294967295 0 141 79 98 4294967295 0 155 53 93 4294967295 0 112 67 127 4294967295 0 183 82 162 4294967295 0 95 125 50 4294967295 0 103 113 186 4294967295 0 128 123 37 4294967295 25 0 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 0 0 187 187 0 0 0 0 1 0 0 0 0 187 0 1 187 0 1 0 187 0 0 1 0 1 0 0 187 0 1 187 0 0 0 0 0 3 0 0 9 1 0 -0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 9 -1 4 0 0 0 0 0 4 0 4294967295 4294967295 4294967295 4294967295 0 0 0 0 4 0 4294967295 4294967295 4294967295 4294967295 9 -2 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 22 44 66 88 110 132 154 176 198 220 242 264 286 308 330 352 0 104 43 148 88 86 2 69 12 15 183 82 162 7 181 33 1 89 107 135 19 137 134 88 86 2 16 36 75 183 82 162 24 119 41 33 1 101 25 153 138 150 49 42 81 69 12 15 183 82 162 147 178 78 155 53 93 92 61 146 91 135 19 94 22 144 171 183 82 162 24 119 41 155 53 93 110 73 51 146 91 151 14 150 49 130 161 39 76 16 36 75 72 18 11 24 119 41 95 125 50 101 25 184 3 177 174 117 108 58 102 72 18 11 182 77 159 95 125 50 106 132 57 184 3 63 20 100 68 35 17 60 31 24 119 41 95 125 50 110 73 51 112 67 127 151 14 6 121 117 108 167 10 30 180 95 125 50 106 132 57 112 67 127 118 165 185 6 121 176 5 35 17 122 179 70 136 147 178 78 155 53 93 97 66 84 103 113 186 13 9 27 140 94 22 129 71 172 170 155 53 93 110 73 51 103 113 186 141 79 98 27 140 23 168 130 161 116 26 131 44 97 66 84 103 113 186 80 52 164 173 175 45 55 65 163 64 129 71 152 149 85 142 103 113 186 141 79 98 173 175 45 126 139 0 163 64 46 47 116 26 143 120 156 83 110 73 51 112 67 127 141 79 98 128 123 37 23 168 54 169 167 10 28 87 160 99 112 67 127 118 165 185 128 123 37 4 29 8 54 169 32 111 122 179 157 56 38 158 141 79 98 128 123 37 126 139 0 115 145 48 46 47 105 154 28 87 59 96 166 34 128 123 37 4 29 8 115 145 48 90 124 40 105 154 109 133 157 56 74 114 21 62 32 0 137 134 42 81 144 171 39 76 58 102 60 31 30 180 70 136 172 170 131 44 85 142 156 83 160 99 38 158 166 34 21 62 16 0 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 0 0 0 12 1 0 -3 0 0 160 0 0 7 181 4294967295 0 33 1 4294967295 0 89 107 4294967295 0 135 19 4294967295 0 101 25 4294967295 0 153 138 4294967295 0 150 49 4294967295 0 92 61 4294967295 0 146 91 4294967295 0 94 22 4294967295 0 151 14 4294967295 0 130 161 4294967295 0 184 3 4294967295 0 177 174 4294967295 0 117 108 4294967295 0 63 20 4294967295 0 100 68 4294967295 0 35 17 4294967295 0 6 121 4294967295 0 167 10 4294967295 0 176 5 4294967295 0 122 179 4294967295 0 13 9 4294967295 0 27 140 4294967295 0 129 71 4294967295 0 23 168 4294967295 0 116 26 4294967295 0 55 65 4294967295 0 163 64 4294967295 0 152 149 4294967295 0 46 47 4294967295 0 143 120 4294967295 0 54 169 4294967295 0 28 87 4294967295 0 32 111 4294967295 0 157 56 4294967295 0 105 154 4294967295 0 59 96 4294967295 0 109 133 4294967295 0 74 114 4294967295 56 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 8 20 52 64 0 28 88 108 60 80 136 152 116 124 148 156 16 40 100 120 36 44 76 84 4 32 12 24 48 72 56 68 92 112 96 104 128 144 132 140 21 23 Policy::Sequential<2,2> +DEAL::0 0 137 0 1 104 43 197 4294967295 0 118 165 185 4294967295 0 128 123 37 4294967295 0 150 177 8 4294967295 0 81 147 178 4294967295 0 39 76 72 4294967295 0 141 79 98 4294967295 0 157 56 38 4294967295 0 182 77 159 4294967295 0 201 49 209 1 201 49 209 4294967295 0 68 35 17 4294967295 0 14 130 161 1 14 130 161 4294967295 0 80 208 164 4294967295 0 176 5 122 4294967295 0 74 190 21 4294967295 0 54 169 28 4294967295 0 25 186 132 4294967295 0 93 92 61 4294967295 0 126 139 198 4294967295 0 18 11 95 4294967295 0 193 13 9 4294967295 0 78 155 53 1 78 155 53 4294967295 0 60 31 112 4294967295 0 173 175 45 4294967295 0 59 96 166 4294967295 25 0 0 5 10 15 20 25 30 35 40 45 54 59 68 73 78 83 88 93 98 103 108 113 122 127 132 0 0 210 210 0 0 0 0 1 0 0 0 0 210 0 1 210 0 1 0 210 0 0 1 0 1 0 0 210 0 1 210 0 0 0 0 0 3 0 0 9 1 0 +0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 1 0 1 0 9 +1 4 0 0 0 0 0 4 0 4294967295 4294967295 4294967295 4294967295 0 0 0 0 4 0 4294967295 4294967295 4294967295 4294967295 4 0 0 0 0 4 0 0 0 0 9 +2 16 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 41 63 85 107 129 151 173 195 217 239 261 283 305 327 349 371 0 104 43 197 201 49 209 14 130 161 78 155 53 88 86 2 69 12 15 183 82 162 7 181 33 1 89 107 135 19 137 134 16 36 191 24 119 41 101 192 153 138 201 49 209 81 147 178 78 155 53 93 92 61 146 91 94 22 144 171 110 73 51 151 14 130 161 78 155 53 39 76 72 18 11 95 125 205 184 3 199 174 117 108 58 102 78 155 53 93 92 61 18 11 95 182 77 159 184 3 196 194 110 73 200 63 20 100 81 147 178 68 35 17 93 92 61 60 31 112 94 22 67 204 6 121 195 10 30 180 68 35 17 118 165 185 60 31 112 176 5 122 67 204 179 70 136 97 66 84 103 207 93 92 61 60 31 112 182 77 159 193 13 9 196 194 27 140 195 10 129 71 172 170 60 31 112 176 5 122 193 13 9 141 79 98 27 140 23 168 66 84 116 26 131 44 39 76 72 18 11 95 80 208 164 173 175 45 55 65 163 64 117 108 152 149 85 142 18 11 95 182 77 159 173 175 45 126 139 198 163 64 46 187 200 63 143 120 156 83 80 208 164 173 175 45 128 123 37 54 169 28 87 160 99 4 152 149 29 203 32 111 173 175 45 126 139 198 54 169 28 157 56 38 99 4 158 115 143 120 145 48 105 154 182 77 159 193 13 9 126 139 198 59 96 166 46 187 189 206 129 71 124 40 109 133 193 13 9 141 79 98 59 96 166 74 190 21 189 206 62 47 116 26 202 34 114 75 126 139 198 59 96 166 157 56 38 25 186 132 158 115 167 106 124 40 148 0 188 57 59 96 166 74 190 21 25 186 132 150 177 8 167 106 127 50 202 34 90 113 52 42 39 0 36 191 24 119 41 101 192 153 138 51 151 58 102 20 100 30 180 103 207 172 170 131 44 85 142 156 83 32 111 105 154 109 133 114 75 188 57 52 42 16 0 0 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 16 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 0 +3 0 0 178 0 1 88 86 2 69 12 4294967295 0 146 91 1 15 183 82 162 7 4294967295 1 181 33 1 89 107 4294967295 0 199 174 1 135 19 137 134 16 4294967295 0 94 22 4294967295 0 144 171 4294967295 0 110 73 4294967295 0 125 205 4294967295 0 184 3 4294967295 0 117 108 4294967295 0 196 194 4294967295 0 200 63 4294967295 0 67 204 4294967295 0 6 121 4294967295 0 195 10 4294967295 0 179 70 4294967295 0 136 97 4294967295 0 66 84 4294967295 0 27 140 4294967295 0 129 71 4294967295 0 23 168 4294967295 0 116 26 4294967295 0 55 65 4294967295 0 163 64 4294967295 0 152 149 4294967295 0 46 187 4294967295 0 143 120 4294967295 0 87 160 4294967295 0 99 4 4294967295 0 29 203 4294967295 0 158 115 4294967295 0 145 48 4294967295 0 189 206 4294967295 0 124 40 4294967295 0 62 47 4294967295 0 202 34 4294967295 0 167 106 4294967295 0 148 0 4294967295 0 127 50 4294967295 0 90 113 4294967295 56 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 17 38 70 82 0 46 106 126 78 98 154 170 134 142 166 174 34 58 118 138 54 62 94 102 7 50 24 42 66 90 74 86 110 130 114 122 146 162 150 158 21 23 Policy::Sequential<2,2> -DEAL::0 0 750 0 0 1217 903 1574 88 4294967295 0 11 1499 2123 1391 4294967295 0 1551 1531 98 448 4294967295 0 1728 0 931 2022 4294967295 0 324 2143 997 95 4294967295 0 828 907 514 1316 4294967295 0 1464 2291 619 1867 4294967295 0 1294 1727 2173 1197 4294967295 0 2120 751 715 2066 4294967295 0 1059 340 156 298 4294967295 0 479 2046 43 1303 4294967295 0 1696 1337 1108 2108 4294967295 0 972 1293 1934 99 4294967295 0 1042 1005 1891 2204 4294967295 0 1837 316 313 1314 4294967295 0 2167 1991 2171 1903 4294967295 0 1158 1599 922 1967 4294967295 0 458 1792 216 1336 4294967295 0 1362 1388 1532 1866 4294967295 0 282 502 1214 411 4294967295 0 131 1308 1806 2088 4294967295 0 1598 896 1924 462 4294967295 0 1651 660 1646 1616 4294967295 0 1823 891 16 315 4294967295 0 1156 28 1538 1552 4294967295 0 1423 975 220 1148 4294967295 0 1056 1785 1657 807 4294967295 0 86 347 1134 424 4294967295 0 336 311 628 2263 4294967295 0 1990 526 1666 994 4294967295 0 1086 1608 1075 2149 4294967295 0 1668 791 2132 1491 4294967295 0 512 1426 2098 2061 4294967295 0 1684 1805 139 2062 4294967295 0 1798 616 209 1373 4294967295 0 1717 789 705 130 4294967295 0 20 2147 1804 177 4294967295 0 824 618 813 485 4294967295 0 1699 2080 1870 14 4294967295 0 1091 1469 901 1768 4294967295 0 2064 1762 1252 268 4294967295 0 50 1519 2269 1721 4294967295 0 1756 1046 1242 924 4294967295 0 1 306 1311 1144 4294967295 0 928 79 812 407 4294967295 0 1032 1449 226 580 4294967295 0 1034 799 685 958 4294967295 0 535 1535 1121 555 4294967295 0 767 865 1782 1839 4294967295 0 163 9 292 541 4294967295 0 837 1920 1468 1583 4294967295 0 300 795 1414 1763 4294967295 0 152 654 829 1161 4294967295 0 165 1178 2255 285 4294967295 0 1369 2086 664 1490 4294967295 0 1511 2213 724 1567 4294967295 0 464 2013 1280 1849 4294967295 0 570 1630 1675 1774 4294967295 0 2083 1537 788 1476 4294967295 0 634 536 548 776 4294967295 0 1566 905 1500 2178 4294967295 0 673 1663 941 369 4294967295 0 960 1655 967 254 4294967295 0 1771 1932 1795 809 4294967295 0 792 403 1856 816 4294967295 0 1085 2155 264 898 4294967295 0 734 1113 2011 614 4294967295 0 373 1639 1016 635 4294967295 0 1074 1546 1002 546 4294967295 0 1173 764 1473 952 4294967295 0 451 965 1559 971 4294967295 0 1402 859 855 1131 4294967295 0 1918 2278 199 1062 4294967295 0 135 760 1810 1953 4294967295 0 657 4 1788 1244 4294967295 0 2303 2151 125 1718 4294967295 0 869 24 1603 552 4294967295 0 370 2160 61 930 4294967295 0 1096 653 396 1767 4294967295 0 1916 1880 1013 417 4294967295 0 154 889 2218 528 4294967295 0 339 2205 291 721 4294967295 0 1724 1238 1641 2010 4294967295 0 1389 1472 991 854 4294967295 0 36 342 880 269 4294967295 0 7 1743 2280 1543 4294967295 0 910 1420 2243 443 4294967295 0 180 1018 184 308 4294967295 0 85 1700 987 1060 4294967295 0 191 968 119 815 4294967295 0 1243 1813 53 1817 4294967295 0 1104 820 2292 2298 4294967295 0 1952 2207 1135 722 4294967295 0 765 1115 2272 2087 4294967295 0 1467 1561 1610 921 4294967295 0 1796 1645 708 785 4294967295 0 530 1755 431 963 4294967295 0 1975 995 1860 1247 4294967295 0 2222 142 1407 147 4294967295 0 926 1014 1799 1205 4294967295 0 2268 1310 229 215 4294967295 0 39 2254 1846 129 4294967295 0 1611 1193 515 1634 4294967295 0 964 1791 1022 1152 4294967295 0 706 30 468 946 4294967295 0 1029 74 951 1033 4294967295 0 1255 1241 52 201 4294967295 0 2223 682 1850 319 4294967295 0 1451 1441 1100 162 4294967295 0 2099 1669 1824 1422 4294967295 0 955 1126 1534 2153 4294967295 0 2229 2082 1127 983 4294967295 0 1297 1741 1187 1083 4294967295 0 1827 1258 1288 1188 4294967295 0 1734 160 1614 293 4294967295 0 562 1401 338 202 4294967295 0 122 1842 860 1249 4294967295 0 101 1766 1256 329 4294967295 0 872 694 1540 362 4294967295 0 1130 111 1697 1267 4294967295 0 265 325 1106 96 4294967295 0 1665 1917 2163 471 4294967295 0 1155 1571 1330 1979 4294967295 0 1349 2134 1219 1704 4294967295 0 287 1955 1437 1301 4294967295 125 0 0 6 12 18 24 30 36 42 48 54 60 66 72 78 84 90 96 102 108 114 120 126 132 138 144 150 156 162 168 174 180 186 192 198 204 210 216 222 228 234 240 246 252 258 264 270 276 282 288 294 300 306 312 318 324 330 336 342 348 354 360 366 372 378 384 390 396 402 408 414 420 426 432 438 444 450 456 462 468 474 480 486 492 498 504 510 516 522 528 534 540 546 552 558 564 570 576 582 588 594 600 606 612 618 624 630 636 642 648 654 660 666 672 678 684 690 696 702 708 714 720 726 732 738 744 0 0 2312 2312 0 0 0 0 1 0 0 0 0 2312 0 1 2312 0 1 0 2312 0 0 1 0 1 0 0 2312 0 1 2312 0 0 0 0 0 3 0 0 9 1 0 -0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 9 -1 8 0 0 0 0 0 0 0 0 0 8 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 8 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 9 -2 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 89 178 267 356 445 534 623 712 801 890 979 1068 1157 1246 1335 1424 1513 1602 1691 1780 1869 1958 2047 2136 2225 2314 2403 2492 2581 2670 2759 2848 2937 3026 3115 3204 3293 3382 3471 3560 3649 3738 3827 3916 4005 4094 4183 4272 4361 4450 4539 4628 4717 4806 4895 4984 5073 5162 5251 5340 5429 5518 5607 5696 0 1217 903 1574 88 86 347 1134 424 1990 526 1666 994 7 1743 2280 1543 1668 791 2132 1491 339 2205 291 721 191 968 119 815 101 1766 1256 329 919 1942 1808 1400 1988 271 2107 1941 2034 1285 1383 607 2063 1863 356 22 1089 640 2017 225 529 637 1068 1305 817 846 848 879 18 2266 2093 1291 1719 1199 1039 988 371 996 1919 1384 1966 537 1545 803 1409 310 518 1487 341 1591 447 1120 1418 1510 1363 1290 2127 86 347 1134 424 2120 751 715 2066 7 1743 2280 1543 1511 2213 724 1567 339 2205 291 721 165 1178 2255 285 101 1766 1256 329 122 1842 860 1249 1400 1988 271 1878 2154 500 976 1035 1343 641 856 1037 22 1089 640 1406 1200 1593 2110 497 1997 1140 1904 1266 879 18 2266 1525 2279 284 1199 1039 988 1965 713 797 1384 1966 537 1680 849 1416 1642 2124 1368 1940 1748 441 1787 1497 2103 1595 1647 1694 1439 240 187 1990 526 1666 994 7 1743 2280 1543 1059 340 156 298 570 1630 1675 1774 191 968 119 815 101 1766 1256 329 634 536 548 776 1297 1741 1187 1083 1321 219 1577 56 1667 2216 1285 1383 607 387 1112 252 1212 1761 532 382 1679 1607 637 1068 1305 945 2175 1167 2093 1291 1719 1199 1039 988 109 2097 590 190 1828 1895 740 1770 1910 1753 1347 247 310 518 1487 1466 584 167 668 916 1477 1908 476 1028 1579 1592 990 7 1743 2280 1543 1511 2213 724 1567 570 1630 1675 1774 1598 896 1924 462 101 1766 1256 329 122 1842 860 1249 1297 1741 1187 1083 869 24 1603 552 56 1667 2216 161 2076 1928 641 856 1037 140 1737 702 382 1679 1607 402 1714 763 1140 1904 1266 2245 2253 1864 1199 1039 988 1965 713 797 190 1828 1895 1198 1739 2129 1753 1347 247 1354 499 973 1940 1748 441 2275 1861 1169 243 375 1759 223 1350 2200 281 2241 818 1668 791 2132 1491 339 2205 291 721 191 968 119 815 101 1766 1256 329 479 2046 43 1303 300 795 1414 1763 673 1663 941 369 1451 1441 1100 162 2063 1863 356 22 1089 640 2017 225 529 637 1068 1305 401 651 1896 1944 1456 932 1093 1007 1299 1279 886 1004 2128 947 655 1654 2195 1339 1331 914 743 1231 1821 599 565 1484 1292 2015 143 2309 589 1090 757 2121 1911 1825 1120 1418 1510 390 1210 2274 1797 597 25 339 2205 291 721 165 1178 2255 285 101 1766 1256 329 122 1842 860 1249 300 795 1414 1763 131 1308 1806 2088 1451 1441 1100 162 154 889 2218 528 22 1089 640 1406 1200 1593 2110 497 1997 1140 1904 1266 1944 1456 932 2308 194 1901 1000 239 1479 2293 802 929 1654 2195 1339 1949 1705 974 1231 1821 599 1009 636 1882 2015 143 2309 174 397 418 450 203 1783 214 1670 1899 1595 1647 1694 730 579 304 825 793 1236 191 968 119 815 101 1766 1256 329 634 536 548 776 1297 1741 1187 1083 673 1663 941 369 1451 1441 1100 162 1651 660 1646 1616 1096 653 396 1767 1212 1761 532 382 1679 1607 637 1068 1305 945 2175 1167 2 899 513 1937 1228 576 1279 886 1004 1638 573 543 1331 914 743 1231 1821 599 94 843 1604 2033 1485 756 1026 2176 1776 251 736 400 2121 1911 1825 1216 1309 2049 1908 476 1028 486 2021 64 1554 1179 1081 101 1766 1256 329 122 1842 860 1249 1297 1741 1187 1083 869 24 1603 552 1451 1441 1100 162 154 889 2218 528 1096 653 396 1767 1056 1785 1657 807 382 1679 1607 402 1714 763 1140 1904 1266 2245 2253 1864 1937 1228 576 1690 1045 302 2293 802 929 426 1773 842 1231 1821 599 1009 636 1882 2033 1485 756 2125 700 1202 251 736 400 798 1066 857 214 1670 1899 549 169 2233 223 1350 2200 1671 200 1594 1996 892 1893 2120 751 715 2066 336 311 628 2263 1511 2213 724 1567 910 1420 2243 443 165 1178 2255 285 1389 1472 991 854 122 1842 860 1249 872 694 1540 362 1878 2154 500 1387 909 527 1041 1073 228 595 906 826 1406 1200 1593 185 35 1868 992 1052 917 427 2249 1103 1525 2279 284 1570 412 925 1965 713 797 432 259 1392 1680 849 1416 1475 2074 753 1775 861 68 1509 1963 2007 1877 1539 188 1707 2250 2041 170 435 642 336 311 628 2263 11 1499 2123 1391 910 1420 2243 443 1684 1805 139 2062 1389 1472 991 854 1717 789 705 130 872 694 1540 362 765 1115 2272 2087 1387 909 527 2267 2193 1318 1462 525 93 2146 1123 1095 185 35 1868 59 1458 727 1017 1405 1682 1685 171 703 1570 412 925 312 2162 149 432 259 1392 457 2221 1220 1475 2074 753 1507 1936 2196 615 1959 1658 1270 934 249 238 44 334 421 839 1548 569 1174 388 1511 2213 724 1567 910 1420 2243 443 1598 896 1924 462 2083 1537 788 1476 122 1842 860 1249 872 694 1540 362 869 24 1603 552 955 1126 1534 2153 161 2076 1928 183 2231 1326 595 906 826 606 1613 496 402 1714 763 752 1834 367 427 2249 1103 1338 218 1432 1965 713 797 432 259 1392 1198 1739 2129 1360 823 2037 1354 499 973 1865 2058 1224 1509 1963 2007 748 155 1731 289 1482 57 1379 423 1845 210 2008 1122 910 1420 2243 443 1684 1805 139 2062 2083 1537 788 1476 1696 1337 1108 2108 872 694 1540 362 765 1115 2272 2087 955 1126 1534 2153 1771 1932 1795 809 183 2231 1326 557 773 1067 2146 1123 1095 542 2032 608 752 1834 367 970 1448 2081 1685 171 703 250 602 444 432 259 1392 457 2221 1220 1360 823 2037 386 231 1428 1865 2058 1224 2310 217 1286 1270 934 249 126 1001 1488 1836 377 1319 1227 871 1191 902 1195 2052 165 1178 2255 285 1389 1472 991 854 122 1842 860 1249 872 694 1540 362 131 1308 1806 2088 152 654 829 1161 154 889 2218 528 2223 682 1850 319 1406 1200 1593 185 35 1868 992 1052 917 427 2249 1103 2308 194 1901 178 893 1643 808 320 1440 508 625 1588 1949 1705 974 351 794 999 1009 636 1882 2150 1366 566 174 397 418 1275 1843 1246 1565 100 1576 2236 1568 1900 1707 2250 2041 1892 610 1929 1981 1460 1181 1389 1472 991 854 1717 789 705 130 872 694 1540 362 765 1115 2272 2087 152 654 829 1161 972 1293 1934 99 2223 682 1850 319 1085 2155 264 898 185 35 1868 59 1458 727 1017 1405 1682 1685 171 703 178 893 1643 1372 2050 1831 321 372 330 1664 1760 2026 351 794 999 1323 1746 1393 2150 1366 566 1019 1162 2140 1275 1843 1246 1015 1315 667 1672 1049 120 598 1023 1544 421 839 1548 782 1851 1644 1084 1980 2054 122 1842 860 1249 872 694 1540 362 869 24 1603 552 955 1126 1534 2153 154 889 2218 528 2223 682 1850 319 1056 1785 1657 807 370 2160 61 930 402 1714 763 752 1834 367 427 2249 1103 1338 218 1432 1690 1045 302 1203 45 624 508 625 1588 467 2197 1715 1009 636 1882 2150 1366 566 2125 700 1202 1677 442 578 798 1066 857 1459 1970 2036 2236 1568 1900 40 317 1626 1379 423 1845 1964 299 935 1930 198 366 872 694 1540 362 765 1115 2272 2087 955 1126 1534 2153 1771 1932 1795 809 2223 682 1850 319 1085 2155 264 898 370 2160 61 930 1823 891 16 315 752 1834 367 970 1448 2081 1685 171 703 250 602 444 1203 45 624 986 408 510 1664 1760 2026 911 1424 1516 2150 1366 566 1019 1162 2140 1677 442 578 2261 1375 1116 1459 1970 2036 1281 1894 676 598 1023 1544 2003 327 483 1227 871 1191 2055 696 305 1807 915 168 1059 340 156 298 570 1630 1675 1774 1086 1608 1075 2149 180 1018 184 308 634 536 548 776 1297 1741 1187 1083 1243 1813 53 1817 1130 111 1697 1267 211 670 1745 1061 1723 1027 387 1112 252 920 314 208 582 1274 1168 1221 887 2025 945 2175 1167 6 966 1333 109 2097 590 190 1828 1895 1010 1447 749 2185 771 985 422 600 353 2043 611 37 1466 584 167 1522 1517 2265 394 1147 1933 1977 2181 1564 148 1353 1992 570 1630 1675 1774 1598 896 1924 462 180 1018 184 308 464 2013 1280 1849 1297 1741 1187 1083 869 24 1603 552 1130 111 1697 1267 562 1401 338 202 1061 1723 1027 806 1922 1857 140 1737 702 436 2059 2305 1221 887 2025 1586 132 2073 2245 2253 1864 738 1082 374 190 1828 1895 1198 1739 2129 2185 771 985 1859 2152 1047 2043 611 37 1054 103 1935 2275 1861 1169 1194 1661 648 1189 1283 15 54 2126 1051 585 405 863 1086 1608 1075 2149 180 1018 184 308 1551 1531 98 448 824 618 813 485 1243 1813 53 1817 1130 111 1697 1267 1091 1469 901 1768 1975 995 1860 1247 632 759 1711 574 1847 484 920 314 208 2215 1520 3 2012 2090 75 230 270 2056 6 966 1333 73 1736 2142 1010 1447 749 2185 771 985 2019 236 1474 235 355 1335 669 1650 1875 389 70 1957 1522 1517 2265 939 2144 12 5 84 248 1960 1581 1563 844 1184 48 180 1018 184 308 464 2013 1280 1849 824 618 813 485 1042 1005 1891 2204 1130 111 1697 1267 562 1401 338 202 1975 995 1860 1247 1173 764 1473 952 574 1847 484 256 361 1124 436 2059 2305 437 1995 2094 230 270 2056 1673 2161 2277 738 1082 374 1508 520 1890 2185 771 985 1859 2152 1047 235 355 1335 1304 2295 1348 389 70 1957 116 60 1706 1194 1661 648 545 547 1141 245 1395 204 2191 47 278 1758 723 888 634 536 548 776 1297 1741 1187 1083 1243 1813 53 1817 1130 111 1697 1267 1651 660 1646 1616 1096 653 396 1767 960 1655 967 254 1255 1241 52 201 582 1274 1168 1221 887 2025 945 2175 1167 6 966 1333 276 1778 850 104 13 1182 1638 573 543 453 1702 498 94 843 1604 2033 1485 756 399 1751 2102 2164 2192 1730 2130 781 1854 956 592 612 1216 1309 2049 1558 2085 735 1977 2181 1564 1619 206 836 567 273 2016 1297 1741 1187 1083 869 24 1603 552 1130 111 1697 1267 562 1401 338 202 1096 653 396 1767 1056 1785 1657 807 1255 1241 52 201 1916 1880 1013 417 1221 887 2025 1586 132 2073 2245 2253 1864 738 1082 374 104 13 1182 659 1496 1573 426 1773 842 1222 1300 1322 2033 1485 756 2125 700 1202 2164 2192 1730 1521 604 571 956 592 612 1582 1660 279 549 169 2233 1512 197 605 54 2126 1051 1802 1261 783 716 679 747 1243 1813 53 1817 1130 111 1697 1267 1091 1469 901 1768 1975 995 1860 1247 960 1655 967 254 1255 1241 52 201 1837 316 313 1314 373 1639 1016 635 2012 2090 75 230 270 2056 6 966 1333 73 1736 2142 1053 1457 1907 2283 2208 1211 453 1702 498 841 1781 1542 399 1751 2102 2164 2192 1730 105 862 294 2189 1128 1884 1157 1125 1793 473 2060 1020 1558 2085 735 1376 438 1989 1960 1581 1563 775 1886 335 940 391 1927 1130 111 1697 1267 562 1401 338 202 1975 995 1860 1247 1173 764 1473 952 1255 1241 52 201 1916 1880 1013 417 373 1639 1016 635 1156 28 1538 1552 230 270 2056 1673 2161 2277 738 1082 374 1508 520 1890 2283 2208 1211 164 2294 984 1222 1300 1322 1536 227 1201 2164 2192 1730 1521 604 571 2189 1128 1884 1132 883 1031 473 2060 1020 1822 1055 890 1512 197 605 1163 1374 295 2191 47 278 1738 1547 358 2184 1915 261 1598 896 1924 462 2083 1537 788 1476 464 2013 1280 1849 85 1700 987 1060 869 24 1603 552 955 1126 1534 2153 562 1401 338 202 265 325 1106 96 806 1922 1857 323 242 1686 606 1613 496 750 814 884 1586 132 2073 878 2288 137 1338 218 1432 1931 1764 1938 1198 1739 2129 1360 823 2037 1859 2152 1047 1858 1494 112 1054 103 1935 461 962 2227 748 155 1731 272 1659 796 1820 1872 416 638 822 419 2044 687 943 2083 1537 788 1476 1696 1337 1108 2108 85 1700 987 1060 1798 616 209 1373 955 1126 1534 2153 1771 1932 1795 809 265 325 1106 96 1467 1561 1610 921 323 242 1686 280 1506 1143 542 2032 608 352 1526 874 878 2288 137 1284 108 1465 250 602 444 144 744 1601 1360 823 2037 386 231 1428 1858 1494 112 1606 1435 41 461 962 2227 1632 2247 1550 126 1001 1488 2079 77 1962 1826 1150 691 1025 2138 1968 274 2289 1235 464 2013 1280 1849 85 1700 987 1060 1042 1005 1891 2204 1699 2080 1870 14 562 1401 338 202 265 325 1106 96 1173 764 1473 952 926 1014 1799 1205 256 361 1124 2095 501 76 750 814 884 1412 343 1390 1673 2161 2277 534 2113 19 1931 1764 1938 1328 414 2078 1859 2152 1047 1858 1494 112 1304 2295 1348 895 1030 647 116 60 1706 232 923 904 272 1659 796 2159 2220 83 2281 622 1747 707 621 1159 629 1622 900 85 1700 987 1060 1798 616 209 1373 1699 2080 1870 14 1728 0 931 2022 265 325 1106 96 1467 1561 1610 921 926 1014 1799 1205 50 1519 2269 1721 2095 501 76 2031 368 237 352 1526 874 876 384 1602 534 2113 19 742 1589 1575 144 744 1601 26 558 1230 1858 1494 112 1606 1435 41 895 1030 647 69 17 1050 232 923 904 1365 1693 1950 2079 77 1962 1371 1399 1840 1848 72 581 2148 712 847 1527 938 693 869 24 1603 552 955 1126 1534 2153 562 1401 338 202 265 325 1106 96 1056 1785 1657 807 370 2160 61 930 1916 1880 1013 417 1029 74 951 1033 1586 132 2073 878 2288 137 1338 218 1432 1931 1764 1938 659 1496 1573 350 2077 701 467 2197 1715 2169 1186 1403 2125 700 1202 1677 442 578 1521 604 571 1621 277 1215 1582 1660 279 173 787 1069 40 317 1626 192 2296 1092 638 822 419 1735 159 1223 1617 1154 459 955 1126 1534 2153 1771 1932 1795 809 265 325 1106 96 1467 1561 1610 921 370 2160 61 930 1823 891 16 315 1029 74 951 1033 734 1113 2011 614 878 2288 137 1284 108 1465 250 602 444 144 744 1601 350 2077 701 1562 1580 666 911 1424 1516 1869 257 1569 1677 442 578 2261 1375 1116 1621 277 1215 23 1111 875 173 787 1069 588 398 425 2003 327 483 465 1196 1394 1025 2138 1968 1584 58 733 1259 509 1811 562 1401 338 202 265 325 1106 96 1173 764 1473 952 926 1014 1799 1205 1916 1880 1013 417 1029 74 951 1033 1156 28 1538 1552 1074 1546 1002 546 1673 2161 2277 534 2113 19 1931 1764 1938 1328 414 2078 164 2294 984 1974 376 1454 2169 1186 1403 867 80 469 1521 604 571 1621 277 1215 1132 883 1031 1237 1779 357 1822 1055 890 1442 2172 1998 192 2296 1092 1902 1833 2257 707 621 1159 309 504 1175 1332 2001 1357 265 325 1106 96 1467 1561 1610 921 926 1014 1799 1205 50 1519 2269 1721 1029 74 951 1033 734 1113 2011 614 1074 1546 1002 546 2167 1991 2171 1903 534 2113 19 742 1589 1575 144 744 1601 26 558 1230 1974 376 1454 1226 118 472 1869 257 1569 1945 1649 1914 1621 277 1215 23 1111 875 1237 1779 357 1597 1640 107 1442 2172 1998 1367 684 1107 465 1196 1394 2252 671 942 2148 712 847 307 1695 593 561 1889 1888 479 2046 43 1303 300 795 1414 1763 673 1663 941 369 1451 1441 1100 162 512 1426 2098 2061 1724 1238 1641 2010 1104 820 2292 2298 1665 1917 2163 471 401 651 1896 1944 1456 932 1093 1007 1299 1279 886 1004 90 1726 1117 1678 2047 2009 838 586 2131 695 1982 1713 741 89 1683 1590 1969 1502 141 1816 2119 662 1325 491 568 123 697 1461 2186 1012 1818 539 572 1733 1493 2158 390 1210 2274 1909 559 157 1832 2096 761 300 795 1414 1763 131 1308 1806 2088 1451 1441 1100 162 154 889 2218 528 1724 1238 1641 2010 1369 2086 664 1490 1665 1917 2163 471 1734 160 1614 293 1944 1456 932 2308 194 1901 1000 239 1479 2293 802 929 1678 2047 2009 1271 553 1984 2057 1190 1208 897 2018 1709 1590 1969 1502 1265 524 1344 662 1325 491 55 1306 1133 1461 2186 1012 433 2302 1750 92 1317 1361 46 1855 480 730 579 304 420 689 630 1530 1529 1898 673 1663 941 369 1451 1441 1100 162 1651 660 1646 1616 1096 653 396 1767 1104 820 2292 2298 1665 1917 2163 471 1566 905 1500 2178 2229 2082 1127 983 2 899 513 1937 1228 576 1279 886 1004 1638 573 543 1298 1883 1312 601 263 1145 695 1982 1713 1676 1251 1885 141 1816 2119 662 1325 491 1662 858 1421 688 213 790 845 1971 121 1585 1629 1528 1733 1493 2158 1334 674 596 486 2021 64 779 38 957 110 492 1620 1451 1441 1100 162 154 889 2218 528 1096 653 396 1767 1056 1785 1657 807 1665 1917 2163 471 1734 160 1614 293 2229 2082 1127 983 2303 2151 125 1718 1937 1228 576 1690 1045 302 2293 802 929 426 1773 842 601 263 1145 446 1881 2273 897 2018 1709 1556 645 1874 662 1325 491 55 1306 1133 688 213 790 544 494 1879 1585 1629 1528 1268 1204 1518 46 1855 480 2258 784 2109 1671 200 1594 1071 331 1386 1948 1105 1396 512 1426 2098 2061 1724 1238 1641 2010 1104 820 2292 2298 1665 1917 2163 471 324 2143 997 95 1 306 1311 1144 1032 1449 226 580 39 2254 1846 129 90 1726 1117 1678 2047 2009 838 586 2131 695 1982 1713 2232 1612 2157 2023 882 1397 835 1429 470 2300 1961 1410 1024 1415 333 2170 33 1302 1183 345 2053 587 63 2246 1800 2029 521 714 864 2112 913 2286 729 2225 1505 710 1909 559 157 241 681 1463 1206 253 1114 1724 1238 1641 2010 1369 2086 664 1490 1665 1917 2163 471 1734 160 1614 293 1 306 1311 1144 1158 1599 922 1967 39 2254 1846 129 1402 859 855 1131 1678 2047 2009 1271 553 1984 2057 1190 1208 897 2018 1709 2023 882 1397 1355 639 8 380 34 1351 1656 1972 360 2170 33 1302 1057 1812 207 587 63 2246 29 1295 2203 714 864 2112 392 2240 1164 1419 1436 49 365 1443 1378 420 689 630 1618 359 1480 176 2069 1080 1104 820 2292 2298 1665 1917 2163 471 1566 905 1500 2178 2229 2082 1127 983 1032 1449 226 580 39 2254 1846 129 458 1792 216 1336 135 760 1810 1953 1298 1883 1312 601 263 1145 695 1982 1713 1676 1251 1885 554 478 1921 977 1434 378 2300 1961 1410 2048 774 2190 1183 345 2053 587 63 2246 2217 1897 2306 463 1600 2177 303 381 2166 449 1146 474 2225 1505 710 2256 51 505 779 38 957 1624 609 969 1627 1129 1340 1665 1917 2163 471 1734 160 1614 293 2229 2082 1127 983 2303 2151 125 1718 39 2254 1846 129 1402 859 855 1131 135 760 1810 1953 1423 975 220 1148 601 263 1145 446 1881 2273 897 2018 1709 1556 645 1874 977 1434 378 2282 877 650 1656 1972 360 332 1703 1524 587 63 2246 29 1295 2203 463 1600 2177 1234 1829 927 449 1146 474 296 2199 1438 365 1443 1378 1102 1076 718 1071 331 1386 1170 1232 1008 1327 800 2242 131 1308 1806 2088 152 654 829 1161 154 889 2218 528 2223 682 1850 319 1369 2086 664 1490 36 342 880 269 1734 160 1614 293 1155 1571 1330 1979 2308 194 1901 178 893 1643 808 320 1440 508 625 1588 1271 553 1984 1983 1652 222 2219 413 2070 1541 1572 1278 1265 524 1344 2165 699 762 55 1306 1133 1346 1689 1503 433 2302 1750 583 1273 1560 452 1789 885 1342 81 440 1892 610 1929 393 475 2301 1635 1433 801 152 654 829 1161 972 1293 1934 99 2223 682 1850 319 1085 2155 264 898 36 342 880 269 20 2147 1804 177 1155 1571 1330 1979 1796 1645 708 785 178 893 1643 1372 2050 1831 321 372 330 1664 1760 2026 1983 1652 222 633 2111 1151 153 244 2004 246 831 726 2165 699 762 873 1225 1192 1346 1689 1503 665 1533 1486 583 1273 1560 328 672 698 1489 1064 516 1356 1470 563 782 1851 1644 67 2290 2100 2089 1109 1740 154 889 2218 528 2223 682 1850 319 1056 1785 1657 807 370 2160 61 930 1734 160 1614 293 1155 1571 1330 1979 2303 2151 125 1718 2099 1669 1824 1422 1690 1045 302 1203 45 624 508 625 1588 467 2197 1715 446 1881 2273 2248 2311 1623 1541 1572 1278 196 1450 2114 55 1306 1133 1346 1689 1503 544 494 1879 1987 481 1021 1268 1204 1518 1263 1786 166 1342 81 440 1720 62 348 1964 299 935 1445 1905 2211 2027 777 2002 2223 682 1850 319 1085 2155 264 898 370 2160 61 930 1823 891 16 315 1155 1571 1330 1979 1796 1645 708 785 2099 1669 1824 1422 792 403 1856 816 1203 45 624 986 408 510 1664 1760 2026 911 1424 1516 2248 2311 1623 1455 1119 71 246 831 726 2237 1478 1427 1346 1689 1503 665 1533 1486 1987 481 1021 434 840 78 1263 1786 166 755 2201 804 1356 1470 563 2106 1320 953 2055 696 305 27 255 1906 1160 1296 1999 1369 2086 664 1490 36 342 880 269 1734 160 1614 293 1155 1571 1330 1979 1158 1599 922 1967 928 79 812 407 1402 859 855 1131 1611 1193 515 1634 1271 553 1984 1983 1652 222 2219 413 2070 1541 1572 1278 1355 639 8 1523 758 2174 2259 686 853 1742 1732 1277 1057 1812 207 1498 993 2244 29 1295 2203 322 1790 2156 392 2240 1164 1048 680 66 117 1166 1358 1411 1976 383 393 475 2301 1504 1958 2304 1079 1681 1065 36 342 880 269 20 2147 1804 177 1155 1571 1330 1979 1796 1645 708 785 928 79 812 407 828 907 514 1316 1611 1193 515 1634 535 1535 1121 555 1983 1652 222 633 2111 1151 153 244 2004 246 831 726 1523 758 2174 1801 1359 1452 1674 1815 134 2262 1954 719 1498 993 2244 456 1324 1871 322 1790 2156 1712 2224 1492 1048 680 66 1943 1862 1951 950 1257 490 488 1852 1245 67 2290 2100 1631 577 2038 1844 1078 675 1734 160 1614 293 1155 1571 1330 1979 2303 2151 125 1718 2099 1669 1824 1422 1402 859 855 1131 1611 1193 515 1634 1423 975 220 1148 657 4 1788 1244 446 1881 2273 2248 2311 1623 1541 1572 1278 196 1450 2114 2282 877 650 506 768 1947 1742 1732 1277 1691 810 42 29 1295 2203 322 1790 2156 1234 1829 927 1213 1398 870 296 2199 1438 772 1913 1495 1411 1976 383 1097 517 1381 1445 1905 2211 2260 1553 1653 745 428 720 1155 1571 1330 1979 1796 1645 708 785 2099 1669 1824 1422 792 403 1856 816 1611 1193 515 1634 535 1535 1121 555 657 4 1788 1244 1362 1388 1532 1866 2248 2311 1623 1455 1119 71 246 831 726 2237 1478 1427 506 768 1947 2230 326 1555 2262 1954 719 1729 959 717 322 1790 2156 1712 2224 1492 1213 1398 870 2238 1710 1752 772 1913 1495 495 260 1772 488 1852 1245 318 477 2006 27 255 1906 1413 2235 2287 2028 404 692 1651 660 1646 1616 1096 653 396 1767 960 1655 967 254 1255 1241 52 201 1566 905 1500 2178 2229 2082 1127 983 1952 2207 1135 722 1349 2134 1219 1704 276 1778 850 104 13 1182 1638 573 543 453 1702 498 1137 2168 2226 646 550 2284 1676 1251 1885 1138 406 1754 1662 858 1421 688 213 790 1513 364 982 87 2065 623 1072 179 10 2039 1118 32 1334 674 596 834 1036 301 1619 206 836 1180 556 575 2136 1993 766 1096 653 396 1767 1056 1785 1657 807 1255 1241 52 201 1916 1880 1013 417 2229 2082 1127 983 2303 2151 125 1718 1349 2134 1219 1704 1827 1258 1288 1188 104 13 1182 659 1496 1573 426 1773 842 1222 1300 1322 646 550 2284 379 1587 2117 1556 645 1874 1431 1240 1229 688 213 790 544 494 1879 87 2065 623 1887 21 1609 2039 1118 32 267 1172 1239 2258 784 2109 1417 221 1404 1802 1261 783 1139 1153 1515 656 1688 2092 960 1655 967 254 1255 1241 52 201 1837 316 313 1314 373 1639 1016 635 1952 2207 1135 722 1349 2134 1219 1704 2064 1762 1252 268 2222 142 1407 147 1053 1457 1907 2283 2208 1211 453 1702 498 841 1781 1542 1838 1769 181 769 1596 1352 1138 406 1754 82 1716 2187 1513 364 982 87 2065 623 65 649 1176 948 819 1341 1248 1254 138 2035 643 1382 834 1036 301 1307 175 678 775 1886 335 1819 711 617 1040 1149 2122 1255 1241 52 201 1916 1880 1013 417 373 1639 1016 635 1156 28 1538 1552 1349 2134 1219 1704 1827 1258 1288 1188 2222 142 1407 147 451 965 1559 971 2283 2208 1211 164 2294 984 1222 1300 1322 1536 227 1201 769 1596 1352 2188 102 2198 1431 1240 1229 385 136 1501 87 2065 623 1887 21 1609 948 819 1341 2212 1784 91 2035 643 1382 531 1253 1615 1417 221 1404 1446 2105 258 1738 1547 358 106 868 746 998 2276 2182 1566 905 1500 2178 2229 2082 1127 983 1952 2207 1135 722 1349 2134 1219 1704 458 1792 216 1336 135 760 1810 1953 1034 799 685 958 964 1791 1022 1152 1137 2168 2226 646 550 2284 1676 1251 1885 1138 406 1754 2030 912 172 658 2014 2005 2048 774 2190 1058 564 1708 2217 1897 2306 463 1600 2177 1250 652 2133 1088 981 262 778 275 1557 1207 1725 1370 2256 51 505 663 31 2251 1180 556 575 1628 2234 2068 466 661 1185 2229 2082 1127 983 2303 2151 125 1718 1349 2134 1219 1704 1827 1258 1288 1188 135 760 1810 1953 1423 975 220 1148 964 1791 1022 1152 1918 2278 199 1062 646 550 2284 379 1587 2117 1556 645 1874 1431 1240 1229 658 2014 2005 1136 519 1994 332 1703 1524 1605 811 1329 463 1600 2177 1234 1829 927 1088 981 262 1218 1578 1165 1207 1725 1370 1835 2209 2020 1102 1076 718 937 894 151 1139 1153 1515 2228 415 933 1377 2116 1514 1952 2207 1135 722 1349 2134 1219 1704 2064 1762 1252 268 2222 142 1407 147 1034 799 685 958 964 1791 1022 1152 1464 2291 619 1867 163 9 292 541 1838 1769 181 769 1596 1352 1138 406 1754 82 1716 2187 830 1003 2271 439 739 2091 1058 564 1708 146 1444 603 1250 652 2133 1088 981 262 2051 1313 1425 349 737 1408 533 1986 833 936 182 1625 663 31 2251 1830 2101 1038 1819 711 617 97 523 2214 158 1926 881 1349 2134 1219 1704 1827 1258 1288 1188 2222 142 1407 147 451 965 1559 971 964 1791 1022 1152 1918 2278 199 1062 163 9 292 541 282 502 1214 411 769 1596 1352 2188 102 2198 1431 1240 1229 385 136 1501 439 739 2091 1289 2202 2239 1605 811 1329 2024 1637 949 1088 981 262 1218 1578 1165 349 737 1408 133 1087 2071 936 182 1625 1094 354 2118 937 894 151 1648 1794 511 106 868 746 2139 1364 193 445 2299 2067 1056 1785 1657 807 370 2160 61 930 1916 1880 1013 417 1029 74 951 1033 2303 2151 125 1718 2099 1669 1824 1422 1827 1258 1288 1188 287 1955 1437 1301 659 1496 1573 350 2077 701 467 2197 1715 2169 1186 1403 379 1587 2117 538 978 409 196 1450 2114 1481 2145 2183 544 494 1879 1987 481 1021 1887 21 1609 683 522 1809 267 1172 1239 115 1101 1698 1720 62 348 1471 2040 1549 1735 159 1223 2297 344 832 286 1262 1701 370 2160 61 930 1823 891 16 315 1029 74 951 1033 734 1113 2011 614 2099 1669 1824 1422 792 403 1856 816 287 1955 1437 1301 530 1755 431 963 350 2077 701 1562 1580 666 911 1424 1516 1869 257 1569 538 978 409 1912 1780 805 2237 1478 1427 1006 626 1692 1987 481 1021 434 840 78 683 522 1809 1345 954 410 115 1101 1698 1233 189 1077 2106 1320 953 297 1483 2042 1584 58 733 709 631 455 1011 2307 195 1916 1880 1013 417 1029 74 951 1033 1156 28 1538 1552 1074 1546 1002 546 1827 1258 1288 1188 287 1955 1437 1301 451 965 1559 971 2268 1310 229 215 164 2294 984 1974 376 1454 2169 1186 1403 867 80 469 2188 102 2198 821 1749 627 1481 2145 2183 283 1070 2179 1887 21 1609 683 522 1809 2212 1784 91 1142 1722 460 531 1253 1615 2045 429 1985 1471 2040 1549 770 1973 1939 309 504 1175 1876 1430 780 1853 2135 1043 1029 74 951 1033 734 1113 2011 614 1074 1546 1002 546 2167 1991 2171 1903 287 1955 1437 1301 530 1755 431 963 2268 1310 229 215 1756 1046 1242 924 1974 376 1454 1226 118 472 1869 257 1569 1945 1649 1914 821 1749 627 1380 2072 395 1006 626 1692 363 503 613 683 522 1809 1345 954 410 1142 1722 460 827 704 128 2045 429 1985 851 1110 224 297 1483 2042 1282 2137 1269 307 1695 593 1744 866 290 1453 489 1978 2303 2151 125 1718 2099 1669 1824 1422 1827 1258 1288 1188 287 1955 1437 1301 1423 975 220 1148 657 4 1788 1244 1918 2278 199 1062 706 30 468 946 379 1587 2117 538 978 409 196 1450 2114 1481 2145 2183 1136 519 1994 2084 234 1803 1691 810 42 487 1636 551 1234 1829 927 1213 1398 870 1218 1578 1165 288 1633 145 1835 2209 2020 1177 430 591 1097 517 1381 212 979 2000 2297 344 832 1276 731 1099 266 989 961 2099 1669 1824 1422 792 403 1856 816 287 1955 1437 1301 530 1755 431 963 657 4 1788 1244 1362 1388 1532 1866 706 30 468 946 767 865 1782 1839 538 978 409 1912 1780 805 2237 1478 1427 1006 626 1692 2084 234 1803 493 754 114 1729 959 717 1873 1757 337 1213 1398 870 2238 1710 1752 288 1633 145 1841 786 205 1177 430 591 2210 1272 2075 318 477 2006 852 482 1063 709 631 455 908 677 1923 1946 644 1209 1827 1258 1288 1188 287 1955 1437 1301 451 965 1559 971 2268 1310 229 215 1918 2278 199 1062 706 30 468 946 282 502 1214 411 837 1920 1468 1583 2188 102 2198 821 1749 627 1481 2145 2183 283 1070 2179 1289 2202 2239 2206 1171 2180 487 1636 551 2194 454 732 1218 1578 1165 288 1633 145 133 1087 2071 1956 1814 1765 1094 354 2118 1925 113 150 212 979 2000 2141 540 2285 1876 1430 780 124 1777 1260 2115 944 980 287 1955 1437 1301 530 1755 431 963 2268 1310 229 215 1756 1046 1242 924 706 30 468 946 767 865 1782 1839 837 1920 1468 1583 1294 1727 2173 1197 821 1749 627 1380 2072 395 1006 626 1692 363 503 613 2206 1171 2180 346 1098 233 1873 1757 337 1687 728 127 288 1633 145 1841 786 205 1956 1814 1765 620 1385 507 1925 113 150 2104 2264 725 852 482 1063 1264 594 1287 1744 866 290 186 690 2270 560 1044 918 192 0 1363 1290 2127 1439 240 187 1579 1592 990 281 2241 818 1797 597 25 825 793 1236 1554 1179 1081 1996 892 1893 170 435 642 569 1174 388 210 2008 1122 902 1195 2052 1981 1460 1181 1084 1980 2054 1930 198 366 1807 915 168 148 1353 1992 585 405 863 844 1184 48 1758 723 888 567 273 2016 716 679 747 940 391 1927 2184 1915 261 2044 687 943 274 2289 1235 629 1622 900 1527 938 693 1617 1154 459 1259 509 1811 1332 2001 1357 561 1889 1888 1832 2096 761 1530 1529 1898 110 492 1620 1948 1105 1396 1206 253 1114 176 2069 1080 1627 1129 1340 1327 800 2242 1635 1433 801 2089 1109 1740 2027 777 2002 1160 1296 1999 1079 1681 1065 1844 1078 675 745 428 720 2028 404 692 2136 1993 766 656 1688 2092 1040 1149 2122 998 2276 2182 466 661 1185 1377 2116 1514 158 1926 881 445 2299 2067 286 1262 1701 1011 2307 195 1853 2135 1043 1453 489 1978 266 989 961 1946 644 1209 2115 944 980 560 1044 918 64 0 0 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120 123 126 129 132 135 138 141 144 147 150 153 156 159 162 165 168 171 174 177 180 183 186 189 0 0 0 12 1 0 -3 0 0 1500 0 0 2107 1941 2034 4294967295 0 976 1035 1343 4294967295 0 1041 1073 228 4294967295 0 1462 525 93 4294967295 0 919 1942 1808 4294967295 0 1321 219 1577 4294967295 0 211 670 1745 4294967295 0 632 759 1711 4294967295 0 817 846 848 4294967295 0 2128 947 655 4294967295 0 741 89 1683 4294967295 0 1024 1415 333 4294967295 0 2267 2193 1318 4294967295 0 557 773 1067 4294967295 0 280 1506 1143 4294967295 0 2031 368 237 4294967295 0 312 2162 149 4294967295 0 1323 1746 1393 4294967295 0 873 1225 1192 4294967295 0 456 1324 1871 4294967295 0 2215 1520 3 4294967295 0 437 1995 2094 4294967295 0 1412 343 1390 4294967295 0 876 384 1602 4294967295 0 2019 236 1474 4294967295 0 105 862 294 4294967295 0 65 649 1176 4294967295 0 2051 1313 1425 4294967295 0 69 17 1050 4294967295 0 1597 1640 107 4294967295 0 827 704 128 4294967295 0 620 1385 507 4294967295 0 835 1429 470 4294967295 0 380 34 1351 4294967295 0 2259 686 853 4294967295 0 1674 1815 134 4294967295 0 2232 1612 2157 4294967295 0 554 478 1921 4294967295 0 2030 912 172 4294967295 0 830 1003 2271 4294967295 0 1801 1359 1452 4294967295 0 2230 326 1555 4294967295 0 493 754 114 4294967295 0 346 1098 233 4294967295 0 146 1444 603 4294967295 0 2024 1637 949 4294967295 0 2194 454 732 4294967295 0 1687 728 127 4294967295 0 1093 1007 1299 4294967295 0 1000 239 1479 4294967295 0 808 320 1440 4294967295 0 321 372 330 4294967295 0 1525 2279 284 4294967295 0 1949 1705 974 4294967295 0 1265 524 1344 4294967295 0 1057 1812 207 4294967295 0 1878 2154 500 4294967295 0 161 2076 1928 4294967295 0 806 1922 1857 4294967295 0 256 361 1124 4294967295 0 387 1112 252 4294967295 0 140 1737 702 4294967295 0 606 1613 496 4294967295 0 542 2032 608 4294967295 0 109 2097 590 4294967295 0 94 843 1604 4294967295 0 1662 858 1421 4294967295 0 2217 1897 2306 4294967295 0 401 651 1896 4294967295 0 2 899 513 4294967295 0 276 1778 850 4294967295 0 1053 1457 1907 4294967295 0 386 231 1428 4294967295 0 2261 1375 1116 4294967295 0 434 840 78 4294967295 0 2238 1710 1752 4294967295 0 1372 2050 1831 4294967295 0 986 408 510 4294967295 0 1562 1580 666 4294967295 0 1226 118 472 4294967295 0 841 1781 1542 4294967295 0 1536 227 1201 4294967295 0 867 80 469 4294967295 0 1945 1649 1914 4294967295 0 1304 2295 1348 4294967295 0 1132 883 1031 4294967295 0 2212 1784 91 4294967295 0 133 1087 2071 4294967295 0 1355 639 8 4294967295 0 2282 877 650 4294967295 0 1136 519 1994 4294967295 0 1289 2202 2239 4294967295 0 2048 774 2190 4294967295 0 332 1703 1524 4294967295 0 1691 810 42 4294967295 0 1729 959 717 4294967295 0 544 494 1879 4294967295 0 1234 1829 927 4294967295 0 1198 1739 2129 4294967295 0 2125 700 1202 4294967295 0 467 2197 1715 4294967295 0 911 1424 1516 4294967295 0 1638 573 543 4294967295 0 426 1773 842 4294967295 0 659 1496 1573 4294967295 0 164 2294 984 4294967295 0 2308 194 1901 4294967295 0 1690 1045 302 4294967295 0 2017 225 529 4294967295 0 2110 497 1997 4294967295 0 879 18 2266 4294967295 0 1654 2195 1339 4294967295 0 838 586 2131 4294967295 0 2057 1190 1208 4294967295 0 1590 1969 1502 4294967295 0 2170 33 1302 4294967295 0 992 1052 917 4294967295 0 1017 1405 1682 4294967295 0 1570 412 925 4294967295 0 351 794 999 4294967295 0 2219 413 2070 4294967295 0 153 244 2004 4294967295 0 2165 699 762 4294967295 0 1498 993 2244 4294967295 0 1400 1988 271 4294967295 0 56 1667 2216 4294967295 0 1285 1383 607 4294967295 0 641 856 1037 4294967295 0 1387 909 527 4294967295 0 183 2231 1326 4294967295 0 595 906 826 4294967295 0 2146 1123 1095 4294967295 0 1061 1723 1027 4294967295 0 574 1847 484 4294967295 0 920 314 208 4294967295 0 436 2059 2305 4294967295 0 323 242 1686 4294967295 0 2095 501 76 4294967295 0 750 814 884 4294967295 0 352 1526 874 4294967295 0 2093 1291 1719 4294967295 0 1331 914 743 4294967295 0 2063 1863 356 4294967295 0 1212 1761 532 4294967295 0 1010 1447 749 4294967295 0 399 1751 2102 4294967295 0 582 1274 1168 4294967295 0 2012 2090 75 4294967295 0 141 1816 2119 4294967295 0 1183 345 2053 4294967295 0 90 1726 1117 4294967295 0 1298 1883 1312 4294967295 0 1513 364 982 4294967295 0 1250 652 2133 4294967295 0 1137 2168 2226 4294967295 0 1838 1769 181 4294967295 0 457 2221 1220 4294967295 0 1019 1162 2140 4294967295 0 59 1458 727 4294967295 0 970 1448 2081 4294967295 0 1606 1435 41 4294967295 0 23 1111 875 4294967295 0 1284 108 1465 4294967295 0 742 1589 1575 4294967295 0 665 1533 1486 4294967295 0 1712 2224 1492 4294967295 0 633 2111 1151 4294967295 0 1455 1119 71 4294967295 0 1345 954 410 4294967295 0 1841 786 205 4294967295 0 1912 1780 805 4294967295 0 1380 2072 395 4294967295 0 73 1736 2142 4294967295 0 1508 520 1890 4294967295 0 235 355 1335 4294967295 0 2189 1128 1884 4294967295 0 82 1716 2187 4294967295 0 385 136 1501 4294967295 0 948 819 1341 4294967295 0 349 737 1408 4294967295 0 1328 414 2078 4294967295 0 26 558 1230 4294967295 0 895 1030 647 4294967295 0 1237 1779 357 4294967295 0 283 1070 2179 4294967295 0 363 503 613 4294967295 0 1142 1722 460 4294967295 0 1956 1814 1765 4294967295 0 2023 882 1397 4294967295 0 977 1434 378 4294967295 0 2300 1961 1410 4294967295 0 1656 1972 360 4294967295 0 1523 758 2174 4294967295 0 506 768 1947 4294967295 0 1742 1732 1277 4294967295 0 2262 1954 719 4294967295 0 658 2014 2005 4294967295 0 439 739 2091 4294967295 0 1058 564 1708 4294967295 0 1605 811 1329 4294967295 0 2084 234 1803 4294967295 0 2206 1171 2180 4294967295 0 487 1636 551 4294967295 0 1873 1757 337 4294967295 0 350 2077 701 4294967295 0 1974 376 1454 4294967295 0 2169 1186 1403 4294967295 0 1869 257 1569 4294967295 0 104 13 1182 4294967295 0 2283 2208 1211 4294967295 0 453 1702 498 4294967295 0 1222 1300 1322 4294967295 0 178 893 1643 4294967295 0 1203 45 624 4294967295 0 508 625 1588 4294967295 0 1664 1760 2026 4294967295 0 1944 1456 932 4294967295 0 1937 1228 576 4294967295 0 1279 886 1004 4294967295 0 2293 802 929 4294967295 0 196 1450 2114 4294967295 0 2237 1478 1427 4294967295 0 1987 481 1021 4294967295 0 1213 1398 870 4294967295 0 1338 218 1432 4294967295 0 250 602 444 4294967295 0 1360 823 2037 4294967295 0 1677 442 578 4294967295 0 1676 1251 1885 4294967295 0 1556 645 1874 4294967295 0 688 213 790 4294967295 0 463 1600 2177 4294967295 0 945 2175 1167 4294967295 0 2245 2253 1864 4294967295 0 190 1828 1895 4294967295 0 2033 1485 756 4294967295 0 1887 21 1609 4294967295 0 1218 1578 1165 4294967295 0 379 1587 2117 4294967295 0 2188 102 2198 4294967295 0 55 1306 1133 4294967295 0 29 1295 2203 4294967295 0 1271 553 1984 4294967295 0 446 1881 2273 4294967295 0 1859 2152 1047 4294967295 0 1521 604 571 4294967295 0 1586 132 2073 4294967295 0 1673 2161 2277 4294967295 0 1965 713 797 4294967295 0 1009 636 1882 4294967295 0 1406 1200 1593 4294967295 0 402 1714 763 4294967295 0 288 1633 145 4294967295 0 683 522 1809 4294967295 0 1006 626 1692 4294967295 0 1481 2145 2183 4294967295 0 821 1749 627 4294967295 0 538 978 409 4294967295 0 1088 981 262 4294967295 0 87 2065 623 4294967295 0 1431 1240 1229 4294967295 0 1138 406 1754 4294967295 0 769 1596 1352 4294967295 0 646 550 2284 4294967295 0 322 1790 2156 4294967295 0 1346 1689 1503 4294967295 0 246 831 726 4294967295 0 1541 1572 1278 4294967295 0 2248 2311 1623 4294967295 0 1983 1652 222 4294967295 0 587 63 2246 4294967295 0 662 1325 491 4294967295 0 897 2018 1709 4294967295 0 695 1982 1713 4294967295 0 601 263 1145 4294967295 0 1678 2047 2009 4294967295 0 1621 277 1215 4294967295 0 1858 1494 112 4294967295 0 144 744 1601 4294967295 0 1931 1764 1938 4294967295 0 534 2113 19 4294967295 0 878 2288 137 4294967295 0 2164 2192 1730 4294967295 0 2185 771 985 4294967295 0 738 1082 374 4294967295 0 6 966 1333 4294967295 0 230 270 2056 4294967295 0 1221 887 2025 4294967295 0 2150 1366 566 4294967295 0 432 259 1392 4294967295 0 1685 171 703 4294967295 0 427 2249 1103 4294967295 0 752 1834 367 4294967295 0 185 35 1868 4294967295 0 1231 1821 599 4294967295 0 1199 1039 988 4294967295 0 1140 1904 1266 4294967295 0 637 1068 1305 4294967295 0 382 1679 1607 4294967295 0 22 1089 640 4294967295 366 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160 165 170 175 180 185 190 195 200 205 210 215 220 225 230 235 240 245 250 255 260 265 270 275 280 285 290 295 300 305 310 315 320 325 330 335 340 345 350 355 360 365 370 375 380 385 390 395 400 405 410 415 420 425 430 435 440 445 450 455 460 465 470 475 480 485 490 495 500 505 510 515 520 525 530 535 540 545 550 555 560 565 570 575 580 585 590 595 600 605 610 615 620 625 630 635 640 645 650 655 660 665 670 675 680 685 690 695 700 705 710 715 720 725 730 735 740 745 750 755 760 765 770 775 780 785 790 795 800 805 810 815 820 825 830 835 840 845 850 855 860 865 870 875 880 885 890 895 900 905 910 915 920 925 930 935 940 945 950 955 960 965 970 975 980 985 990 995 1000 1005 1010 1015 1020 1025 1030 1035 1040 1045 1050 1055 1060 1065 1070 1075 1080 1085 1090 1095 1100 1105 1110 1115 1120 1125 1130 1135 1140 1145 1150 1155 1160 1165 1170 1175 1180 1185 1190 1195 1200 1205 1210 1215 1220 1225 1230 1235 1240 1245 1250 1255 1260 1265 1270 1275 1280 1285 1290 1295 1300 1305 1310 1315 1320 1325 1330 1335 1340 1345 1350 1355 1360 1365 1370 1375 1380 1385 1390 1395 1400 1405 1410 1415 1420 1425 1430 1435 1440 1445 1450 1455 1460 1465 1470 1475 1480 1485 1490 1495 0 0 1200 0 0 371 996 1919 4294967295 0 1384 1966 537 4294967295 0 1545 803 1409 4294967295 0 310 518 1487 4294967295 0 341 1591 447 4294967295 0 1120 1418 1510 4294967295 0 1680 849 1416 4294967295 0 1642 2124 1368 4294967295 0 1940 1748 441 4294967295 0 1787 1497 2103 4294967295 0 1595 1647 1694 4294967295 0 740 1770 1910 4294967295 0 1753 1347 247 4294967295 0 1466 584 167 4294967295 0 668 916 1477 4294967295 0 1908 476 1028 4294967295 0 1354 499 973 4294967295 0 2275 1861 1169 4294967295 0 243 375 1759 4294967295 0 223 1350 2200 4294967295 0 565 1484 1292 4294967295 0 2015 143 2309 4294967295 0 589 1090 757 4294967295 0 2121 1911 1825 4294967295 0 390 1210 2274 4294967295 0 174 397 418 4294967295 0 450 203 1783 4294967295 0 214 1670 1899 4294967295 0 730 579 304 4294967295 0 1026 2176 1776 4294967295 0 251 736 400 4294967295 0 1216 1309 2049 4294967295 0 486 2021 64 4294967295 0 798 1066 857 4294967295 0 549 169 2233 4294967295 0 1671 200 1594 4294967295 0 1475 2074 753 4294967295 0 1775 861 68 4294967295 0 1509 1963 2007 4294967295 0 1877 1539 188 4294967295 0 1707 2250 2041 4294967295 0 1507 1936 2196 4294967295 0 615 1959 1658 4294967295 0 1270 934 249 4294967295 0 238 44 334 4294967295 0 421 839 1548 4294967295 0 1865 2058 1224 4294967295 0 748 155 1731 4294967295 0 289 1482 57 4294967295 0 1379 423 1845 4294967295 0 2310 217 1286 4294967295 0 126 1001 1488 4294967295 0 1836 377 1319 4294967295 0 1227 871 1191 4294967295 0 1275 1843 1246 4294967295 0 1565 100 1576 4294967295 0 2236 1568 1900 4294967295 0 1892 610 1929 4294967295 0 1015 1315 667 4294967295 0 1672 1049 120 4294967295 0 598 1023 1544 4294967295 0 782 1851 1644 4294967295 0 1459 1970 2036 4294967295 0 40 317 1626 4294967295 0 1964 299 935 4294967295 0 1281 1894 676 4294967295 0 2003 327 483 4294967295 0 2055 696 305 4294967295 0 422 600 353 4294967295 0 2043 611 37 4294967295 0 1522 1517 2265 4294967295 0 394 1147 1933 4294967295 0 1977 2181 1564 4294967295 0 1054 103 1935 4294967295 0 1194 1661 648 4294967295 0 1189 1283 15 4294967295 0 54 2126 1051 4294967295 0 669 1650 1875 4294967295 0 389 70 1957 4294967295 0 939 2144 12 4294967295 0 5 84 248 4294967295 0 1960 1581 1563 4294967295 0 116 60 1706 4294967295 0 545 547 1141 4294967295 0 245 1395 204 4294967295 0 2191 47 278 4294967295 0 2130 781 1854 4294967295 0 956 592 612 4294967295 0 1558 2085 735 4294967295 0 1619 206 836 4294967295 0 1582 1660 279 4294967295 0 1512 197 605 4294967295 0 1802 1261 783 4294967295 0 1157 1125 1793 4294967295 0 473 2060 1020 4294967295 0 1376 438 1989 4294967295 0 775 1886 335 4294967295 0 1822 1055 890 4294967295 0 1163 1374 295 4294967295 0 1738 1547 358 4294967295 0 461 962 2227 4294967295 0 272 1659 796 4294967295 0 1820 1872 416 4294967295 0 638 822 419 4294967295 0 1632 2247 1550 4294967295 0 2079 77 1962 4294967295 0 1826 1150 691 4294967295 0 1025 2138 1968 4294967295 0 232 923 904 4294967295 0 2159 2220 83 4294967295 0 2281 622 1747 4294967295 0 707 621 1159 4294967295 0 1365 1693 1950 4294967295 0 1371 1399 1840 4294967295 0 1848 72 581 4294967295 0 2148 712 847 4294967295 0 173 787 1069 4294967295 0 192 2296 1092 4294967295 0 1735 159 1223 4294967295 0 588 398 425 4294967295 0 465 1196 1394 4294967295 0 1584 58 733 4294967295 0 1442 2172 1998 4294967295 0 1902 1833 2257 4294967295 0 309 504 1175 4294967295 0 1367 684 1107 4294967295 0 2252 671 942 4294967295 0 307 1695 593 4294967295 0 568 123 697 4294967295 0 1461 2186 1012 4294967295 0 1818 539 572 4294967295 0 1733 1493 2158 4294967295 0 1909 559 157 4294967295 0 433 2302 1750 4294967295 0 92 1317 1361 4294967295 0 46 1855 480 4294967295 0 420 689 630 4294967295 0 845 1971 121 4294967295 0 1585 1629 1528 4294967295 0 1334 674 596 4294967295 0 779 38 957 4294967295 0 1268 1204 1518 4294967295 0 2258 784 2109 4294967295 0 1071 331 1386 4294967295 0 1800 2029 521 4294967295 0 714 864 2112 4294967295 0 913 2286 729 4294967295 0 2225 1505 710 4294967295 0 241 681 1463 4294967295 0 392 2240 1164 4294967295 0 1419 1436 49 4294967295 0 365 1443 1378 4294967295 0 1618 359 1480 4294967295 0 303 381 2166 4294967295 0 449 1146 474 4294967295 0 2256 51 505 4294967295 0 1624 609 969 4294967295 0 296 2199 1438 4294967295 0 1102 1076 718 4294967295 0 1170 1232 1008 4294967295 0 583 1273 1560 4294967295 0 452 1789 885 4294967295 0 1342 81 440 4294967295 0 393 475 2301 4294967295 0 328 672 698 4294967295 0 1489 1064 516 4294967295 0 1356 1470 563 4294967295 0 67 2290 2100 4294967295 0 1263 1786 166 4294967295 0 1720 62 348 4294967295 0 1445 1905 2211 4294967295 0 755 2201 804 4294967295 0 2106 1320 953 4294967295 0 27 255 1906 4294967295 0 1048 680 66 4294967295 0 117 1166 1358 4294967295 0 1411 1976 383 4294967295 0 1504 1958 2304 4294967295 0 1943 1862 1951 4294967295 0 950 1257 490 4294967295 0 488 1852 1245 4294967295 0 1631 577 2038 4294967295 0 772 1913 1495 4294967295 0 1097 517 1381 4294967295 0 2260 1553 1653 4294967295 0 495 260 1772 4294967295 0 318 477 2006 4294967295 0 1413 2235 2287 4294967295 0 1072 179 10 4294967295 0 2039 1118 32 4294967295 0 834 1036 301 4294967295 0 1180 556 575 4294967295 0 267 1172 1239 4294967295 0 1417 221 1404 4294967295 0 1139 1153 1515 4294967295 0 1248 1254 138 4294967295 0 2035 643 1382 4294967295 0 1307 175 678 4294967295 0 1819 711 617 4294967295 0 531 1253 1615 4294967295 0 1446 2105 258 4294967295 0 106 868 746 4294967295 0 778 275 1557 4294967295 0 1207 1725 1370 4294967295 0 663 31 2251 4294967295 0 1628 2234 2068 4294967295 0 1835 2209 2020 4294967295 0 937 894 151 4294967295 0 2228 415 933 4294967295 0 533 1986 833 4294967295 0 936 182 1625 4294967295 0 1830 2101 1038 4294967295 0 97 523 2214 4294967295 0 1094 354 2118 4294967295 0 1648 1794 511 4294967295 0 2139 1364 193 4294967295 0 115 1101 1698 4294967295 0 1471 2040 1549 4294967295 0 2297 344 832 4294967295 0 1233 189 1077 4294967295 0 297 1483 2042 4294967295 0 709 631 455 4294967295 0 2045 429 1985 4294967295 0 770 1973 1939 4294967295 0 1876 1430 780 4294967295 0 851 1110 224 4294967295 0 1282 2137 1269 4294967295 0 1744 866 290 4294967295 0 1177 430 591 4294967295 0 212 979 2000 4294967295 0 1276 731 1099 4294967295 0 2210 1272 2075 4294967295 0 852 482 1063 4294967295 0 908 677 1923 4294967295 0 1925 113 150 4294967295 0 2141 540 2285 4294967295 0 124 1777 1260 4294967295 0 2104 2264 725 4294967295 0 1264 594 1287 4294967295 0 186 690 2270 4294967295 282 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 10 110 35 130 650 730 670 750 185 275 210 295 805 875 825 895 20 45 70 90 195 220 240 260 355 375 400 420 510 530 550 570 0 55 100 145 340 385 430 465 640 685 720 765 940 975 1010 1045 205 250 290 325 520 560 595 625 820 855 890 925 1095 1125 1155 1185 395 475 415 490 985 1055 1000 1070 545 615 565 630 1115 1175 1130 1190 740 760 780 795 885 905 920 935 1025 1040 1060 1075 1150 1165 1180 1195 590 605 620 635 445 460 480 495 285 305 320 335 120 140 160 175 845 915 860 930 235 315 255 330 695 775 710 790 65 155 85 170 960 995 1030 1065 665 705 745 785 365 410 450 485 30 80 125 165 1135 1120 1105 1090 1160 1100 1145 1085 1170 1140 1110 1080 1005 990 970 955 1035 965 1020 950 1050 1015 980 945 865 850 835 815 900 830 880 810 910 870 840 800 715 700 680 660 755 675 735 655 770 725 690 645 575 555 535 515 600 525 585 505 610 580 540 500 425 405 380 360 455 370 440 350 470 435 390 345 265 245 225 200 300 215 280 190 310 270 230 180 95 75 50 25 135 40 115 15 150 105 60 5 73 23 Policy::Sequential<3,3> +DEAL::0 0 785 0 1 1217 903 1574 88 4294967295 0 1892 610 1929 1981 4294967295 0 635 2463 1457 2441 4294967295 0 741 89 1683 1590 4294967295 0 1979 1983 1652 222 4294967295 0 1716 2321 65 649 4294967295 0 946 2084 234 1803 4294967295 0 355 1538 2443 1283 4294967295 0 167 668 916 1477 4294967295 0 1484 1292 2015 143 4294967295 0 892 1893 336 311 4294967295 0 1075 2149 180 1018 4294967295 0 1859 2320 1047 1054 4294967295 0 987 1060 265 325 4294967295 0 2220 83 2281 622 4294967295 0 1556 645 1874 544 4294967295 0 1064 516 2422 1470 4294967295 0 1856 816 1455 1119 4294967295 0 2391 1708 1250 652 4294967295 0 852 482 1063 908 4294967295 0 2062 1717 789 705 4294967295 0 1604 2033 1485 756 4294967295 0 1658 1270 2428 249 4294967295 0 1957 939 2144 12 4294967295 0 1399 1840 1848 72 4294967295 0 2446 1277 1498 2392 4294967295 0 1224 2363 155 1731 4294967295 0 1347 247 1466 584 1 1347 247 1466 584 4294967295 0 2032 608 970 1448 4294967295 0 1231 1821 599 565 1 1231 1821 599 565 4294967295 0 1995 2094 1673 2161 4294967295 0 1671 200 1594 1996 1 1671 200 1594 1996 4294967295 0 1144 1032 1449 226 4294967295 0 1460 2447 972 1293 4294967295 0 1002 546 1974 376 4294967295 0 1934 2330 1085 2155 4294967295 0 1788 1244 506 768 4294967295 0 2283 2208 1211 841 4294967295 0 1107 2252 671 942 4294967295 0 1781 1542 105 862 4294967295 0 1214 411 1289 2202 4294967295 0 1969 1502 141 2466 4294967295 0 2384 1164 803 575 4294967295 0 2219 413 2070 1541 4294967295 0 1288 1188 379 1587 4294967295 0 1572 1278 2165 2334 4294967295 0 1077 297 1483 2042 4294967295 0 1176 948 819 1341 4294967295 0 1693 32 2299 707 4294967295 0 487 1636 551 288 4294967295 0 934 2212 1087 356 4294967295 0 628 2263 2352 1420 4294967295 0 422 600 353 2043 4294967295 0 1603 552 161 2076 4294967295 0 1131 1355 639 8 4294967295 0 1592 2433 1598 896 4294967295 0 1619 206 836 567 4294967295 0 2309 589 1090 757 4294967295 0 1970 2036 2322 317 4294967295 0 1210 2274 2455 597 4294967295 0 1953 554 478 1921 4294967295 0 2243 443 1389 1472 4294967295 0 209 1373 1467 1561 4294967295 0 184 308 1243 1813 4294967295 0 406 1754 1513 364 4294967295 0 103 1935 1194 1661 4294967295 0 689 630 1530 1529 4294967295 0 1747 2402 621 1159 4294967295 0 688 213 790 2395 4294967295 0 2390 96 323 242 4294967295 0 1698 1471 2040 1549 4294967295 0 563 67 2290 2100 4294967295 0 924 1380 2072 395 4294967295 0 71 2237 1478 1427 4294967295 0 1615 1446 2105 258 4294967295 0 332 1703 1524 1234 4294967295 0 1026 2176 1776 251 4294967295 0 1847 484 2215 1520 4294967295 0 238 44 334 421 4294967295 0 1870 14 926 1014 4294967295 0 130 765 1115 2272 4294967295 0 1924 2360 869 24 1 1924 2360 869 24 4294967295 0 580 39 2254 1846 4294967295 0 386 231 1428 2310 4294967295 0 514 1316 535 1535 4294967295 0 1908 476 1028 1579 1 1908 476 1028 1579 4294967295 0 2081 2379 602 444 4294967295 0 2277 1508 520 1890 4294967295 0 787 1069 192 2296 4294967295 0 2121 1911 1825 390 1 2121 1911 1825 390 4294967295 0 1304 2295 1348 116 4294967295 0 129 2418 1612 2157 4294967295 0 199 1062 1136 519 4294967295 0 264 898 1372 2050 4294967295 0 1454 867 80 469 4294967295 0 1947 2469 810 42 4294967295 0 1264 594 1287 186 4294967295 0 294 2189 1128 1884 4294967295 0 2239 2024 1637 949 4294967295 0 2325 1695 593 561 4294967295 0 1818 684 99 1147 4294967295 0 762 2343 1689 1503 4294967295 0 2117 1431 1240 1229 4294967295 0 709 631 455 1011 4294967295 0 2052 250 60 1445 4294967295 0 1271 553 1984 2057 4294967295 0 1610 2409 280 1506 4294967295 0 2440 37 2312 2372 4294967295 0 991 854 872 694 4294967295 0 1772 318 477 2006 4294967295 0 1626 1964 2344 935 4294967295 0 977 1434 378 2048 4294967295 0 25 131 1308 1806 4294967295 0 1444 603 2051 1313 4294967295 0 380 34 1351 1656 4294967295 0 273 2016 1916 1880 4294967295 0 402 1714 763 2245 4294967295 0 1928 140 1737 702 1 1928 140 1737 702 4294967295 0 217 1286 126 1001 4294967295 0 2380 1706 545 547 4294967295 0 1092 1735 2401 1223 4294967295 0 2023 882 1397 835 4294967295 0 1121 555 1801 2468 4294967295 0 1994 1605 811 1329 4294967295 0 2141 2327 2285 124 4294967295 125 0 0 6 12 18 24 30 36 42 48 54 60 66 72 78 84 90 96 102 108 114 120 126 132 138 144 150 156 162 173 179 190 196 207 213 219 225 231 237 243 249 255 261 267 273 279 285 291 297 303 309 315 321 327 333 339 345 351 357 363 369 375 381 387 393 399 405 411 417 423 429 435 441 447 453 459 465 471 477 483 489 495 501 512 518 524 530 541 547 553 559 570 576 582 588 594 600 606 612 618 624 630 636 642 648 654 660 666 672 678 684 690 696 702 708 714 720 726 732 743 749 755 761 767 773 779 0 0 2478 2478 0 0 0 0 1 0 0 0 0 2478 0 1 2478 0 1 0 2478 0 0 1 0 1 0 0 2478 0 1 2478 0 0 0 0 0 3 0 0 9 1 0 +0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 1 0 1 0 9 +1 8 0 0 0 0 0 0 0 0 0 8 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 8 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 8 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 9 +2 64 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 219 308 397 486 575 664 753 842 931 1020 1109 1198 1287 1376 1465 1554 1643 1732 1821 1910 1999 2088 2177 2266 2355 2444 2533 2622 2711 2800 2889 2978 3067 3156 3245 3334 3423 3512 3601 3690 3779 3868 3957 4046 4135 4224 4313 4402 4491 4580 4669 4758 4847 4936 5025 5114 5203 5292 5381 5470 5559 5648 5737 5826 0 1217 903 1574 88 1347 247 1466 584 1231 1821 599 565 1908 476 1028 1579 1671 200 1594 1996 1924 2360 869 24 2121 1911 1825 390 1928 140 1737 702 86 347 1134 424 1990 2346 1666 994 7 1743 2280 1543 1668 791 2132 1491 339 2205 291 721 191 968 119 815 101 1766 1256 329 919 1942 1808 1400 1988 271 2107 1941 2034 1285 1383 607 2063 1863 2431 22 1089 2436 2017 225 529 637 1068 1305 817 846 848 879 18 2266 2093 1291 1719 2410 1039 988 371 996 1919 1384 1966 537 1545 2355 1409 310 518 1487 341 1591 447 1120 1418 1510 1363 1290 2127 2120 751 715 2066 1511 2213 724 1567 165 1178 2255 285 122 2413 860 1249 1878 2154 500 976 1035 1343 641 2373 2416 1406 1200 2465 2110 497 1997 1140 1904 1266 1525 2279 284 1965 713 797 1680 849 1416 1642 2124 1368 1940 1748 441 1787 1497 2103 1595 1647 1694 1439 240 187 1059 340 156 298 570 1630 1675 1774 634 536 548 776 1297 1741 1187 1083 1321 219 1577 56 1667 2216 387 1112 252 1212 1761 532 382 1679 1607 945 2175 1167 109 2097 590 190 1828 1895 740 1770 1910 1753 1347 247 1466 584 167 668 916 1477 1908 476 1028 1579 1592 2433 1598 896 1924 2360 869 24 1603 552 161 2076 1928 140 1737 702 402 1714 763 2245 2253 1864 1198 1739 2129 1354 499 973 2459 1861 1169 243 375 1759 223 1350 2200 281 2241 818 2382 2046 43 1303 300 795 2340 1763 673 2476 941 369 1451 1441 1100 162 401 651 1896 1944 1456 932 1093 1007 1299 1279 886 1004 2128 947 655 1654 2195 1339 1331 914 743 1231 1821 599 565 1908 476 1028 1579 1484 1292 2015 143 2309 589 1090 757 2121 1911 1825 390 1928 140 1737 702 1210 2274 2455 597 25 131 1308 1806 2400 154 889 2218 2448 2308 194 1901 1000 239 1479 2293 802 929 1949 1705 974 1009 636 1882 2348 2338 418 450 203 2389 214 941 369 1451 2393 1899 730 579 304 825 793 1236 1651 660 1646 1616 1096 653 396 1767 2 899 513 1937 1228 576 1638 573 543 94 843 1908 476 1028 1579 1592 2433 1598 896 2309 589 1090 757 1604 2033 1485 756 1928 140 1737 702 402 1714 763 2245 25 131 1308 1806 1026 2176 1776 251 2218 2448 2308 736 400 1216 1861 1169 243 1309 2332 486 1705 974 1009 2021 2451 1554 2046 43 1303 1179 1081 1056 941 369 1451 1441 1100 162 579 304 825 1785 1657 807 660 1646 1616 1690 1045 302 1279 886 1004 426 1773 842 2125 700 1202 798 1066 857 549 169 2233 1671 200 1594 1996 1924 2360 869 24 2121 1911 1825 390 1928 140 1737 702 892 1893 336 311 628 2263 2352 1420 2243 443 1389 1472 991 854 872 694 1540 362 1387 375 1759 223 909 527 1041 636 1882 2348 1073 228 2314 906 826 185 35 1868 2374 1052 917 427 2249 1103 1570 412 925 432 259 1392 1475 2074 753 1775 861 68 1509 1963 2007 1877 2336 188 1707 2250 2041 2417 435 642 11 1499 2123 1391 1684 1805 139 1924 2360 869 24 1603 552 161 2076 1928 140 1737 702 402 1714 763 2245 628 2263 2352 1420 2062 1717 789 705 991 854 872 694 130 765 1115 2272 375 1759 223 1350 2200 281 2241 818 2382 2046 43 1303 906 826 185 2087 2267 2193 1318 1462 525 93 2146 1123 412 925 432 1095 59 1458 2074 753 1775 2426 1017 1405 1963 2007 1877 1682 1685 171 703 312 2162 149 457 2221 1654 2195 1339 1220 1507 1936 2196 615 1959 2121 1911 1825 390 1928 140 1737 702 1210 2274 2455 597 25 131 1308 1806 2243 443 1389 1472 991 854 872 694 1658 1270 2428 249 238 44 334 421 802 929 1949 1705 974 1009 636 1882 2348 2338 418 450 839 1548 569 1174 388 2083 1052 917 427 1537 788 1476 259 1392 1475 2074 753 1775 955 1126 1534 2153 183 2231 1326 606 1613 496 752 1834 2250 2041 2417 367 1338 218 576 1638 573 1432 1360 823 2037 1865 2058 1928 140 1737 702 402 1714 763 2245 25 131 1308 1806 1026 2176 1776 251 991 854 872 694 130 765 1115 2272 238 44 334 421 1224 2363 155 1731 1705 974 1009 2021 2451 1554 2046 43 1303 1179 1081 1056 1174 388 2083 289 1482 57 93 2146 1123 1379 423 1845 2074 753 1775 2426 1017 1405 2153 183 2231 210 2008 1122 496 752 1834 1696 1337 1108 149 457 2221 2108 1771 1932 798 1066 857 1795 809 2439 773 1067 542 167 668 916 1477 2032 608 970 1448 1592 2433 1598 896 2081 2379 602 444 1603 552 161 2076 386 231 1428 2310 402 1714 763 2245 217 1286 126 1001 1739 2129 1354 1488 1836 377 1319 1227 871 1191 902 1195 1350 2200 281 2378 152 654 829 1161 2223 682 1850 319 1763 673 2476 178 893 2386 1441 1100 162 808 320 1440 1944 1456 932 508 625 1588 351 794 999 2150 1366 566 1275 1843 1246 1565 100 1576 2236 1568 1900 2032 608 970 1448 1892 610 1929 1981 2081 2379 602 444 1460 2447 972 1293 386 231 1428 2310 1934 2330 1085 2155 217 1286 126 1001 264 898 1372 2050 1488 1836 377 1831 321 372 330 1664 1760 2026 1323 1746 2378 152 654 1393 1019 1162 2140 1015 2445 667 1672 1049 178 893 2386 120 598 1023 808 320 1440 1544 2361 1851 508 625 1588 1644 1084 1980 2054 370 2385 61 930 1203 45 624 467 2197 1715 1677 442 578 1459 1592 2433 1598 896 2081 2379 602 444 1604 2033 1485 756 1970 2036 2322 317 402 1714 763 2245 217 1286 126 1001 1026 2176 1776 251 1626 1964 2344 935 736 400 1216 1930 198 366 1191 902 1195 1823 891 16 2021 2451 1554 315 986 408 682 1850 319 510 911 1424 1441 1100 162 808 320 1440 1785 1657 807 1516 2261 1375 1690 1045 302 2396 2342 1894 2150 1366 566 676 2003 327 483 2055 696 305 1807 915 168 1086 1608 2081 2379 602 444 1460 2447 972 1293 1970 2036 2322 317 1075 2149 180 1018 217 1286 126 1001 264 898 1372 2050 1626 1964 2344 935 184 308 1243 1813 1930 198 366 53 1817 1130 2026 1323 1746 111 1697 1267 315 986 408 211 670 1745 667 1672 1049 1061 1723 1027 808 320 1440 1544 2361 1851 1516 2261 1375 920 314 208 2396 2342 1894 582 1274 1168 61 930 1203 1221 2323 2025 6 966 1333 1010 1447 749 2185 771 985 1603 552 161 2076 386 231 1428 2310 402 1714 763 2245 217 1286 126 1001 2062 1717 789 705 422 600 353 2043 130 765 1115 2272 2440 37 2312 2372 1350 2200 281 2378 152 654 829 1161 2223 682 1850 319 2087 2267 2193 2265 2347 2331 1933 2460 2181 1564 148 1353 1095 59 1458 1992 464 2013 2426 1017 1405 1280 1849 562 1682 1685 171 1401 338 202 806 1922 1857 436 2059 2305 1565 100 1576 1586 132 2073 738 1082 374 386 231 1428 2310 1934 2330 1085 2155 217 1286 126 1001 264 898 1372 2050 422 600 353 2043 1859 2320 1047 1054 2440 37 2312 2372 103 1935 1194 1661 2378 152 654 1393 1019 1162 2140 1015 2445 667 1672 1049 2265 2347 2331 648 1189 2456 15 2414 2452 2449 585 405 1992 464 2013 863 1551 1531 1280 1849 562 98 448 824 1401 338 202 618 813 485 1091 1469 901 1768 2375 995 2197 1715 1677 1860 1247 632 759 1711 574 402 1714 763 2245 217 1286 126 1001 1026 2176 1776 251 1626 1964 2344 935 130 765 1115 2272 2440 37 2312 2372 1224 2363 155 1731 1847 484 2215 1520 2021 2451 1554 315 986 408 682 1850 319 510 911 1424 289 1482 57 3 2357 2335 1564 148 1353 75 2467 270 2426 1017 1405 1280 1849 562 210 2008 1122 2056 73 1736 1696 1337 1108 2142 2407 236 436 2059 2305 1474 235 2453 305 1807 915 1335 669 1650 1875 389 70 217 1286 126 1001 264 898 1372 2050 1626 1964 2344 935 184 308 1243 1813 2440 37 2312 2372 103 1935 1194 1661 1847 484 2215 1520 1957 939 2144 12 315 986 408 211 670 1745 667 1672 1049 1061 1723 1027 3 2357 2335 5 84 248 2449 585 405 1960 1581 1563 1280 1849 562 98 448 824 2056 73 1736 844 1184 48 2142 2407 236 1042 2425 1891 1768 2375 995 2204 2397 764 1010 1447 749 1473 952 256 361 1124 437 1484 1292 2015 143 2309 589 1090 757 1995 2094 1673 2161 2277 1508 520 1890 1210 2274 2455 597 25 131 1308 1806 1304 2295 1348 116 2380 1706 545 547 1141 245 1395 204 2191 47 239 1479 2293 278 1758 723 888 960 2438 967 254 1255 2338 418 450 1241 52 2394 2393 1899 730 579 304 825 276 1778 850 2317 13 1182 453 1702 498 399 1751 2102 1767 2 899 2164 2192 1730 2130 781 1854 956 592 612 1558 2085 735 2309 589 1090 757 1604 2033 1485 756 2277 1508 520 1890 1619 206 836 567 25 131 1308 1806 1026 2176 1776 251 2380 1706 545 547 273 2016 1916 1880 204 2191 47 1013 417 659 1309 2332 486 1496 1573 1222 967 254 1255 1300 1322 1521 1179 1081 1056 604 571 1582 579 304 825 1785 1657 807 2317 13 1182 1660 279 1512 399 1751 2102 197 2339 1802 426 1773 842 1261 783 716 679 747 1837 316 313 1314 373 1639 1016 1995 2094 1673 2161 2277 1508 520 1890 635 2463 1457 2441 2283 2208 1211 841 1304 2295 1348 116 2380 1706 545 547 1781 1542 105 862 294 2189 1128 1884 2388 1125 1793 473 2060 1020 278 1758 723 1376 438 1989 775 1886 335 940 391 1927 1241 52 2394 1156 28 2454 276 1778 850 2317 13 1182 1552 164 2294 984 1536 227 1201 1132 883 1031 1822 1055 2164 2192 1730 890 1163 1374 295 1738 1547 358 2184 1915 261 85 1700 2277 1508 520 1890 1619 206 836 567 2283 2208 1211 841 987 1060 265 325 2380 1706 545 547 273 2016 1916 1880 294 2189 1128 1884 2390 96 323 242 473 2060 1020 1686 750 814 1496 1573 1222 884 878 2288 940 391 1927 137 1931 1764 604 571 1582 1938 1858 1494 2317 13 1182 1660 279 1512 984 1536 227 112 461 962 1031 1822 1055 2227 272 1659 1261 783 716 796 1820 1872 416 638 822 419 2377 687 943 1798 2366 1210 2274 2455 597 25 131 1308 1806 1304 2295 1348 116 2380 1706 545 547 1658 1270 2428 249 238 44 334 421 209 1373 1467 1561 1610 2409 280 1506 888 960 2438 967 254 1255 2338 418 450 1241 52 2394 1143 352 1526 874 1284 108 1537 788 1476 1465 144 744 955 1126 1534 2153 183 2231 1601 1606 1435 41 1632 2247 1550 2079 77 1962 1826 1150 367 1338 218 691 2326 2138 956 592 612 1968 274 2289 1235 1699 2080 25 131 1308 1806 1026 2176 1776 251 2380 1706 545 547 273 2016 1916 1880 238 44 334 421 1224 2363 155 1731 1610 2409 280 1506 1870 14 926 1014 967 254 1255 1300 1322 1521 1179 1081 1056 604 571 1582 874 1284 108 1799 1205 2095 1379 423 1845 501 76 1412 2153 183 2231 210 2008 1122 41 1632 2247 343 1390 534 1962 1826 1150 2113 19 1328 2108 1771 1932 414 2078 895 316 313 1314 1030 647 232 923 904 2159 1304 2295 1348 116 2380 1706 545 547 1781 1542 105 862 294 2189 1128 1884 209 1373 1467 1561 1610 2409 280 1506 2220 83 2281 622 1747 2402 621 1159 775 1886 335 940 391 1927 1241 52 2394 1156 28 2454 629 1622 900 1728 2341 931 1465 144 744 2022 50 1519 1601 1606 1435 41 1632 2247 2269 1721 2031 368 237 876 384 1602 742 1589 1575 26 691 2326 2138 558 1230 69 358 2184 1915 17 1050 1365 2403 1950 1371 2380 1706 545 547 273 2016 1916 1880 294 2189 1128 1884 2390 96 323 242 1610 2409 280 1506 1870 14 926 1014 1747 2402 621 1159 1399 1840 1848 72 940 391 1927 137 1931 1764 604 571 1582 1938 1858 1494 1728 2341 931 581 2148 712 501 76 1412 847 1527 938 41 1632 2247 343 1390 534 368 237 876 693 1029 74 1589 1575 26 951 1033 350 414 2078 895 2077 701 2169 419 2377 687 1186 1403 1621 277 1215 173 1604 2033 1485 756 1970 2036 2322 317 1619 206 836 567 787 1069 192 2296 1026 2176 1776 251 1626 1964 2344 935 273 2016 1916 1880 1092 1735 2401 1223 1013 417 659 1617 1154 459 1823 891 16 734 1113 2442 1300 1322 1521 614 1562 1580 510 911 1424 666 1869 257 1785 1657 807 1516 2261 1375 1660 279 1512 2358 23 1111 197 2339 1802 875 588 398 676 2003 327 425 465 1196 1394 1584 58 733 1259 509 1811 1074 1546 1970 2036 2322 317 1075 2149 180 1018 787 1069 192 2296 1002 546 1974 376 1626 1964 2344 935 184 308 1243 1813 1092 1735 2401 1223 1454 867 80 469 1617 1154 459 1237 1779 357 111 1697 1267 1442 2172 1998 614 1562 1580 1902 1833 2257 1061 1723 1027 309 504 2370 1516 2261 1375 920 314 208 2358 23 1111 1332 2001 1357 875 588 398 2167 1991 2171 1221 2323 2025 1903 1226 118 472 1945 1649 1914 1597 1640 107 1367 2329 1619 206 836 567 787 1069 192 2296 987 1060 265 325 1107 2252 671 942 273 2016 1916 1880 1092 1735 2401 1223 2390 96 323 242 2325 1695 593 561 1686 750 814 1889 1888 512 734 1113 2442 1426 2098 2061 137 1931 1764 1724 1238 1641 666 1869 257 2010 1104 820 1660 279 1512 2358 23 1111 112 461 962 2292 2298 1665 2227 272 1659 1917 2163 471 425 465 1196 90 1726 1117 1678 2047 2009 838 586 2131 695 1982 1713 787 1069 192 2296 1002 546 1974 376 1107 2252 671 942 741 89 1683 1590 1092 1735 2401 1223 1454 867 80 469 2325 1695 593 561 1969 1502 141 2466 1889 1888 512 2119 662 1325 1442 2172 1998 2376 568 123 1724 1238 1641 697 1461 2186 309 504 2370 1012 2328 539 2358 23 1111 1332 2001 1357 2292 2298 1665 572 1733 1493 1917 2163 471 2158 1909 559 1903 1226 118 157 1832 2096 761 2473 2086 664 1490 1734 160 1614 293 1026 2176 1776 251 1626 1964 2344 935 273 2016 1916 1880 1092 1735 2401 1223 1224 2363 155 1731 1847 484 2215 1520 1870 14 926 1014 1271 553 1984 2057 1300 1322 1521 614 1562 1580 510 911 1424 666 1869 257 1799 1205 2095 1190 1208 897 75 2467 270 2018 1709 1265 210 2008 1122 2056 73 1736 343 1390 534 524 1344 55 2113 19 1328 1306 1133 433 1474 235 2453 2302 1750 92 733 1259 509 1317 1361 46 1855 2316 420 1626 1964 2344 935 184 308 1243 1813 1092 1735 2401 1223 1454 867 80 469 1847 484 2215 1520 1957 939 2144 12 1271 553 1984 2057 689 630 1530 1529 614 1562 1580 1902 1833 2257 1061 1723 1027 309 504 2370 1190 1208 897 1898 1566 905 1960 1581 1563 1500 2178 2229 2056 73 1736 844 1184 48 524 1344 55 2082 1127 983 1306 1133 433 1298 1883 1312 2204 2397 764 601 263 2369 1914 1597 1640 1676 1251 1885 1662 858 1421 273 2016 1916 1880 1092 1735 2401 1223 2390 96 323 242 2325 1695 593 561 1870 14 926 1014 1271 553 1984 2057 1399 1840 1848 72 688 213 790 2395 137 1931 1764 1724 1238 1641 666 1869 257 2010 1104 820 581 2148 712 1971 121 1585 2018 1709 1265 1629 1528 1334 343 1390 534 524 1344 55 693 1029 74 674 596 779 951 1033 350 38 2421 110 2302 1750 92 492 1620 2303 838 586 2131 2151 125 1718 446 1881 2273 1092 1735 2401 1223 1454 867 80 469 2325 1695 593 561 1969 1502 141 2466 1271 553 1984 2057 689 630 1530 1529 688 213 790 2395 1556 645 1874 544 1724 1238 1641 697 1461 2186 309 504 2370 1012 2328 539 1971 121 1585 494 1879 1268 1500 2178 2229 1204 1518 2258 524 1344 55 2082 1127 983 674 596 779 784 2109 1071 38 2421 110 331 2333 1948 601 263 2369 1105 1396 324 664 1490 1734 2143 997 95 1 306 1311 892 1893 336 311 628 2263 2352 1420 2243 443 1389 1472 991 854 872 694 1144 1032 1449 226 580 39 2254 1846 129 2418 1612 2157 2023 882 1397 835 1073 228 2314 906 826 185 35 1868 2374 1052 917 427 1429 470 2300 1961 1410 1024 2367 333 2170 33 1302 1183 345 2053 587 63 2246 1800 2029 521 714 864 2112 2313 2286 729 2225 1505 710 241 681 1463 1206 253 2427 1158 1499 2123 1391 1599 922 1967 1402 859 2458 628 2263 2352 1420 2062 1717 789 705 991 854 872 694 130 765 1115 2272 580 39 2254 1846 1131 1355 639 8 2023 882 1397 835 380 34 1351 1656 906 826 185 2087 2267 2193 1318 1462 525 93 2146 1123 1961 1410 1024 1972 360 1057 1812 207 29 1295 2203 392 63 2246 1800 2240 2354 1419 864 2112 2313 1436 49 365 1505 710 241 1443 1378 1618 359 1480 176 2069 1080 458 1220 1507 1936 1792 216 1336 135 760 1810 2243 443 1389 1472 991 854 872 694 1658 1270 2428 249 238 44 334 421 129 2418 1612 2157 2023 882 1397 835 1953 554 478 1921 977 1434 378 2048 839 1548 569 1174 388 2083 1052 917 427 1537 788 1476 774 2190 2217 2359 2306 463 33 1302 1183 2371 2177 303 2029 521 714 864 2112 2313 381 2166 449 1146 474 2474 51 505 1624 609 969 1627 253 2427 1158 2472 1340 1423 1432 1360 823 975 220 1148 2437 877 650 991 854 872 694 130 765 1115 2272 238 44 334 421 1224 2363 155 1731 2023 882 1397 835 380 34 1351 1656 977 1434 378 2048 332 1703 1524 1234 1174 388 2083 289 1482 57 93 2146 1123 1379 423 1845 2359 2306 463 1829 927 296 1295 2203 392 2199 1438 1102 864 2112 2313 1436 49 365 1146 474 2474 1076 718 1170 609 969 1627 1232 1008 1327 2069 1080 458 800 2242 36 1795 809 2439 342 880 269 1155 1571 2419 1144 1032 1449 226 580 39 2254 1846 129 2418 1612 2157 2023 882 1397 835 1979 1983 1652 222 2219 413 2070 1541 1572 1278 2165 2334 762 2343 1689 1503 1429 470 2300 1961 1410 1024 2367 333 2170 33 1302 1183 583 1273 1560 452 2424 2423 1342 81 440 393 475 2301 1635 1433 801 20 2362 1804 177 1796 1645 2464 785 633 2111 1151 153 244 2004 246 831 726 873 1225 1192 665 1599 922 1967 1533 1486 328 672 698 1489 580 39 2254 1846 1131 1355 639 8 2023 882 1397 835 380 34 1351 1656 2219 413 2070 1541 1064 516 2422 1470 762 2343 1689 1503 563 67 2290 2100 1961 1410 1024 1972 360 1057 1812 207 29 1295 2203 392 452 2424 2423 2089 2365 1740 2099 1669 1824 1422 2248 2311 20 2362 1804 1623 196 1450 2464 785 633 2114 1987 481 244 2004 246 1021 1263 1786 2475 1720 62 348 2381 1905 1792 216 1336 2211 2027 777 2002 792 403 129 2418 1612 2157 2023 882 1397 835 1953 554 478 1921 977 1434 378 2048 1572 1278 2165 2334 762 2343 1689 1503 1856 816 1455 1119 71 2237 1478 1427 774 2190 2217 2359 2306 463 33 1302 1183 2371 2177 303 434 840 78 755 2201 804 393 475 2301 2106 1320 953 177 1796 1645 2464 785 633 27 255 1906 1160 1296 1999 928 79 812 407 2351 2319 1225 1192 665 515 1634 1523 975 220 1148 758 2174 2387 686 853 1742 2023 882 1397 835 380 34 1351 1656 977 1434 378 2048 332 1703 1524 1234 762 2343 1689 1503 563 67 2290 2100 71 2237 1478 1427 2446 1277 1498 2392 2359 2306 463 1829 927 296 1295 2203 392 2199 1438 1102 755 2201 804 2244 322 2434 1422 2248 2311 2156 1048 680 2464 785 633 2114 1987 481 1160 1296 1999 66 117 1166 407 2351 2319 1358 1411 1976 348 2381 1905 383 1504 1958 342 880 269 2337 1079 1681 1065 828 907 2062 1717 789 705 422 600 353 2043 130 765 1115 2272 2440 37 2312 2372 1131 1355 639 8 514 1316 535 1535 380 34 1351 1656 1121 555 1801 2468 2087 2267 2193 2265 2347 2331 1933 2460 2181 1564 148 1353 1972 360 1057 2444 1674 1815 134 2262 1954 719 456 1324 2240 2354 1419 1871 1712 2224 1436 49 365 1492 2318 1862 1443 1378 1618 1951 950 1257 490 488 1852 2470 1631 577 1586 132 2073 2038 1844 1078 675 657 4 422 600 353 2043 1859 2320 1047 1054 2440 37 2312 2372 103 1935 1194 1661 514 1316 535 1535 1788 1244 506 768 1121 555 1801 2468 1947 2469 810 42 2265 2347 2331 648 1189 2456 15 2414 2452 2449 585 405 2444 1674 1815 1213 1398 870 772 1913 1495 1097 517 1381 1871 1712 2224 2260 1553 1653 1492 2318 1862 745 428 720 1951 950 1257 1362 1388 1532 1866 2230 326 1555 1729 959 1860 1247 632 717 2238 1710 1752 495 260 130 765 1115 2272 2440 37 2312 2372 1224 2363 155 1731 1847 484 2215 1520 380 34 1351 1656 1121 555 1801 2468 332 1703 1524 1234 1772 318 477 2006 289 1482 57 3 2357 2335 1564 148 1353 75 2467 270 1829 927 296 1413 2235 2287 719 456 1324 2028 404 692 1436 49 365 1492 2318 1862 1076 718 1170 1952 2207 1135 1232 1008 1327 722 1349 2134 2470 1631 577 1219 1704 1137 1335 669 1650 2168 2226 646 550 2284 1138 2440 37 2312 2372 103 1935 1194 1661 1847 484 2215 1520 1957 939 2144 12 1121 555 1801 2468 1947 2469 810 42 1772 318 477 2006 406 1754 1513 364 3 2357 2335 5 84 248 2449 585 405 1960 1581 1563 1413 2235 2287 982 87 2065 1097 517 1381 623 1072 179 1492 2318 1862 745 428 720 1952 2207 1135 10 2039 1118 722 1349 2134 2404 834 1036 1555 1729 959 301 1180 556 1473 952 256 2356 2136 1993 766 1827 1258 1131 1355 639 8 514 1316 535 1535 380 34 1351 1656 1121 555 1801 2468 1064 516 2422 1470 1288 1188 379 1587 563 67 2290 2100 2117 1431 1240 1229 1972 360 1057 2444 1674 1815 134 2262 1954 719 456 1324 2089 2365 1740 1887 21 1609 267 1172 2408 1417 221 1404 1623 196 1450 1139 1153 1515 2114 1987 481 656 1688 2092 1021 1263 1786 2064 1762 1252 268 2222 142 2315 2462 1838 2038 1844 1078 1769 181 769 1596 2399 82 514 1316 535 1535 1788 1244 506 768 1121 555 1801 2468 1947 2469 810 42 1288 1188 379 1587 1716 2321 65 649 2117 1431 1240 1229 1176 948 819 1341 2444 1674 1815 1213 1398 870 772 1913 1495 1097 517 1381 1887 21 1609 1248 1254 138 2035 643 1382 1307 175 678 1139 1153 1515 1819 711 617 656 1688 2092 1040 1149 2122 2064 1762 1252 451 2450 1559 2471 2188 102 2198 2349 136 717 2238 1710 1501 2429 1784 91 531 1253 380 34 1351 1656 1121 555 1801 2468 332 1703 1524 1234 1772 318 477 2006 563 67 2290 2100 2117 1431 1240 1229 2446 1277 1498 2392 1615 1446 2105 258 1829 927 296 1413 2235 2287 719 456 1324 2028 404 692 2244 322 2434 106 868 746 1417 221 1404 998 2276 2182 2114 1987 481 656 1688 2092 66 117 1166 1034 799 685 1358 1411 1976 958 964 1791 2315 2462 1838 1022 1152 2030 2168 2226 646 912 172 658 2014 2005 1058 1121 555 1801 2468 1947 2469 810 42 1772 318 477 2006 406 1754 1513 364 2117 1431 1240 1229 1176 948 819 1341 1615 1446 2105 258 2391 1708 1250 652 1413 2235 2287 982 87 2065 1097 517 1381 623 1072 179 106 868 746 2133 1088 981 1307 175 678 262 778 275 656 1688 2092 1040 1149 2122 1034 799 685 1557 1207 1725 958 964 1791 1370 663 31 2198 2349 136 2251 1628 2234 2356 2136 1993 2068 466 661 1185 1918 2278 1658 1270 2428 249 238 44 334 421 209 1373 1467 1561 1610 2409 280 1506 1953 554 478 1921 977 1434 378 2048 199 1062 1136 519 1994 1605 811 1329 1143 352 1526 874 1284 108 1537 788 1476 1465 144 744 1218 1578 2398 1835 2209 2020 2371 2177 303 937 2383 151 381 2166 449 1146 474 2474 2228 415 2364 1377 2116 1514 1464 2291 619 1867 163 9 2472 1340 1423 292 541 830 1968 274 2289 1003 2271 439 739 2091 146 238 44 334 421 1224 2363 155 1731 1610 2409 280 1506 1870 14 926 1014 977 1434 378 2048 332 1703 1524 1234 1994 1605 811 1329 1444 603 2051 1313 874 1284 108 1799 1205 2095 1379 423 1845 501 76 1412 1835 2209 2020 1425 349 737 2199 1438 1102 1408 533 1986 1146 474 2474 1076 718 1170 1377 2116 1514 833 936 182 1867 163 9 1625 1830 2101 800 2242 36 1038 97 523 1030 647 232 2214 158 1926 881 282 502 209 1373 1467 1561 1610 2409 280 1506 2220 83 2281 622 1747 2402 621 1159 199 1062 1136 519 1994 1605 811 1329 1214 411 1289 2202 2239 2024 1637 949 629 1622 900 1728 2341 931 1465 144 744 2022 50 1519 133 2430 2071 1094 2324 2118 937 2383 151 1648 1794 2432 2228 415 2364 1377 2116 1514 2368 1364 193 445 2405 2067 287 1955 1437 1301 538 978 292 541 830 409 1481 2145 17 1050 1365 2183 683 522 1809 115 1101 1610 2409 280 1506 1870 14 926 1014 1747 2402 621 1159 1399 1840 1848 72 1994 1605 811 1329 1444 603 2051 1313 2239 2024 1637 949 1698 1471 2040 1549 1728 2341 931 581 2148 712 501 76 1412 847 1527 938 1094 2324 2118 2297 344 832 1408 533 1986 286 1262 1701 1377 2116 1514 833 936 182 445 2405 2067 530 1755 431 1301 538 978 963 1912 1780 1038 97 523 805 1006 626 1186 1403 1621 1692 1345 954 410 1233 189 1953 554 478 1921 977 1434 378 2048 199 1062 1136 519 1994 1605 811 1329 1856 816 1455 1119 71 2237 1478 1427 1077 297 1483 2042 709 631 455 1011 1218 1578 2398 1835 2209 2020 2371 2177 303 937 2383 151 2307 195 2268 1310 229 215 2106 1320 953 821 1749 627 27 255 1906 1160 1296 1999 283 1070 2179 1142 2457 460 2045 429 1985 770 1973 1939 515 1634 1523 1876 1430 780 1003 2271 439 1853 2135 1043 1756 1046 1242 977 1434 378 2048 332 1703 1524 1234 1994 1605 811 1329 1444 603 2051 1313 71 2237 1478 1427 2446 1277 1498 2392 709 631 455 1011 924 1380 2072 395 1835 2209 2020 1425 349 737 2199 1438 1102 1408 533 1986 1310 229 215 363 503 613 2156 1048 680 827 704 128 1160 1296 1999 66 117 1166 1142 2457 460 851 1110 224 770 1973 1939 1282 2137 1269 383 1504 1958 1744 866 290 2214 158 1926 1453 489 1978 706 30 2477 199 1062 1136 519 1994 1605 811 1329 1214 411 1289 2202 2239 2024 1637 949 1077 297 1483 2042 709 631 455 1011 946 2084 234 1803 487 1636 551 288 133 2430 2071 1094 2324 2118 937 2383 151 1648 1794 2432 1633 145 1177 430 591 212 821 1749 627 979 2000 1276 283 1070 2179 1142 2457 460 731 1099 266 989 961 767 865 1782 1839 493 754 114 1876 1430 780 1873 1757 2353 2183 683 522 1841 786 205 2210 1272 2075 1994 1605 811 1329 1444 603 2051 1313 2239 2024 1637 949 1698 1471 2040 1549 709 631 455 1011 924 1380 2072 395 487 1636 551 288 852 482 1063 908 1094 2324 2118 2297 344 832 1408 533 1986 286 1262 1701 430 591 212 677 1923 1946 827 704 128 644 1209 837 1142 2457 460 851 1110 224 989 961 767 1920 1468 1583 493 754 114 2206 1171 2180 1744 866 290 2194 454 732 1692 1345 954 1956 1814 1765 1925 113 150 1224 2363 155 1731 1847 484 2215 1520 1870 14 926 1014 1271 553 1984 2057 332 1703 1524 1234 1772 318 477 2006 1444 603 2051 1313 2141 2327 2285 124 1799 1205 2095 1190 1208 897 75 2467 270 2018 1709 1265 1425 349 737 2345 1260 2115 2028 404 692 944 980 1294 1076 718 1170 1952 2207 1135 833 936 182 1727 2461 1197 1625 1830 2101 346 1098 233 1219 1704 1137 1687 728 127 1317 1361 46 620 1385 507 2104 2264 725 1847 484 2215 1520 1957 939 2144 12 1271 553 1984 2057 689 630 1530 1529 1772 318 477 2006 406 1754 1513 364 2141 2327 2285 124 1264 594 1287 186 1190 1208 897 1898 1566 905 1960 1581 1563 1500 2178 2229 2345 1260 2115 690 2270 560 623 1072 179 1044 918 1522 1952 2207 1135 10 2039 1118 1727 2461 1197 913 2412 1407 346 1098 233 480 104 1943 301 1180 556 1193 2152 2187 1676 1251 1885 40 887 2411 307 1025 540 1870 14 926 1014 1271 553 1984 2057 1399 1840 1848 72 688 213 790 2395 1444 603 2051 1313 2141 2327 2285 124 1698 1471 2040 1549 1818 684 99 1147 581 2148 712 1971 121 1585 2018 1709 1265 1629 1528 1334 2297 344 832 2049 1386 699 944 980 1294 2090 1539 2304 833 936 182 1727 2461 1197 530 1755 431 397 605 1414 963 1912 1780 0 1281 1346 1687 728 127 299 1777 526 2151 125 1718 394 174 385 2415 1611 910 1271 553 1984 2057 689 630 1530 1529 688 213 790 2395 1556 645 1874 544 2141 2327 2285 124 1264 594 1287 186 1818 684 99 1147 2384 1164 803 575 1971 121 1585 494 1879 1268 1500 2178 2229 1204 1518 2258 2049 1386 699 2012 2420 1897 1044 918 1522 462 782 2147 1727 2461 1197 913 2412 1407 397 605 1414 748 933 1109 0 1281 1346 616 1415 2139 1193 2152 2187 1145 1175 1600 2143 997 95 1517 856 2435 1975 491 2044 332 1703 1524 1234 1772 318 477 2006 1444 603 2051 1313 2141 2327 2285 124 2446 1277 1498 2392 1615 1446 2105 258 924 1380 2072 395 2052 250 60 1445 1425 349 737 2345 1260 2115 2028 404 692 944 980 1294 363 503 613 479 894 337 998 2276 2182 2160 1643 2259 66 117 1166 1034 799 685 851 1110 224 1157 1783 1106 1282 2137 1269 564 993 1670 1022 1152 2030 201 845 1116 620 1385 507 1173 1165 1352 2088 159 2406 1772 318 477 2006 406 1754 1513 364 2141 2327 2285 124 1264 594 1287 186 1615 1446 2105 258 2391 1708 1250 652 2052 250 60 1445 1693 32 2299 707 2345 1260 2115 690 2270 560 623 1072 179 1044 918 1522 479 894 337 2019 1239 921 262 778 275 1199 354 595 1034 799 685 1557 1207 1725 1157 1783 1106 1842 54 1732 564 993 1670 1037 170 2232 2251 1628 2234 1330 1569 957 40 887 2411 1356 885 1789 1005 727 1114 1444 603 2051 1313 2141 2327 2285 124 1698 1471 2040 1549 1818 684 99 1147 924 1380 2072 395 2052 250 60 1445 852 482 1063 908 934 2212 1087 356 2297 344 832 2049 1386 699 944 980 1294 2090 1539 2304 677 1923 1946 511 990 1790 2160 1643 2259 992 640 2282 851 1110 224 1157 1783 1106 1920 1468 1583 1655 557 611 2206 1171 2180 1907 2011 1797 201 845 1116 1452 1315 2350 394 174 385 1181 528 1051 965 64 2126 2141 2327 2285 124 1264 594 1287 186 1818 684 99 1147 2384 1164 803 575 2052 250 60 1445 1693 32 2299 707 934 2212 1087 356 355 1538 2443 1283 2049 1386 699 2012 2420 1897 1044 918 1522 462 782 2147 511 990 1790 1722 855 2275 1199 354 595 1977 2173 147 1157 1783 1106 1842 54 1732 1655 557 611 1053 708 1593 1907 2011 1797 1816 230 1359 1330 1569 957 1691 1245 971 1517 856 2435 1129 1369 2256 166 1663 468 214 0 56 1667 2216 387 1112 252 1212 1761 532 382 1679 1607 945 2175 1167 109 2097 590 190 1828 1895 740 1770 1910 1753 1331 914 743 543 94 843 549 169 2233 1684 1805 139 2196 615 1959 2037 1865 2058 773 1067 542 2236 1568 1900 442 578 1459 168 1086 1608 2185 771 985 738 1082 374 759 1711 574 1875 389 70 361 1124 437 1558 2085 735 373 1639 1016 261 85 1700 943 1798 2366 1235 1699 2080 923 904 2159 2403 1950 1371 277 1215 173 1811 1074 1546 107 1367 2329 695 1982 1713 160 1614 293 1855 2316 420 1662 858 1421 446 1881 2273 1 306 1311 1402 859 2458 135 760 1810 2437 877 650 1155 1571 2419 672 698 1489 2002 792 403 686 853 1742 1065 828 907 675 657 4 1752 495 260 550 2284 1138 766 1827 1258 1596 2399 82 91 531 1253 2014 2005 1058 1185 1918 2278 739 2091 146 881 282 502 1809 115 1101 410 1233 189 1756 1046 1242 706 30 2477 2210 1272 2075 1925 113 150 2104 2264 725 307 1025 540 2415 1611 910 1975 491 2044 2088 159 2406 1005 727 1114 965 64 2126 166 1663 468 64 0 0 25 28 31 34 37 40 43 46 49 52 55 58 61 64 67 70 73 76 79 82 85 88 91 94 97 100 103 106 109 112 115 118 121 124 127 130 133 136 139 142 145 148 151 154 157 160 163 166 169 172 175 178 181 184 187 190 193 196 199 202 205 208 211 64 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 0 +3 0 0 1584 0 1 2132 1491 339 2205 291 721 191 4294967295 0 499 973 2459 4294967295 0 1319 1227 871 4294967295 0 330 1664 1760 4294967295 1 86 347 1134 424 1990 2346 1666 4294967295 0 2400 154 889 4294967295 0 1141 245 1395 4294967295 0 2388 1125 1793 4294967295 1 18 2266 2093 1291 1719 2410 1039 4294967295 0 2249 1103 1570 4294967295 0 345 2053 587 4294967295 0 1635 1433 801 4294967295 0 1831 321 372 4294967295 0 53 1817 1130 4294967295 0 1237 1779 357 4294967295 0 2119 662 1325 4294967295 0 120 598 1023 4294967295 0 863 1551 1531 4294967295 0 2260 1553 1653 4294967295 0 1819 711 617 4294967295 0 1376 438 1989 4294967295 0 884 878 2288 4294967295 0 1426 2098 2061 4294967295 0 2376 568 123 4294967295 0 1552 164 2294 4294967295 0 2269 1721 2031 4294967295 0 2368 1364 193 4294967295 0 731 1099 266 4294967295 0 572 1733 1493 4294967295 0 784 2109 1071 4294967295 0 748 933 1109 4294967295 0 1053 708 1593 4294967295 0 1342 81 440 4294967295 0 2099 1669 1824 4294967295 0 267 1172 2408 4294967295 0 2035 643 1382 4294967295 0 583 1273 1560 4294967295 0 434 840 78 4294967295 0 2307 195 2268 4294967295 0 1633 145 1177 4294967295 0 1248 1254 138 4294967295 0 2133 1088 981 4294967295 0 2019 1239 921 4294967295 0 1722 855 2275 4294967295 0 979 2000 1276 4294967295 0 644 1209 837 4294967295 0 992 640 2282 4294967295 0 1977 2173 147 4294967295 0 35 1868 2374 4294967295 0 1318 1462 525 4294967295 0 1933 2460 2181 4294967295 0 15 2414 2452 4294967295 0 1763 673 2476 4294967295 0 1095 59 1458 4294967295 0 2240 2354 1419 4294967295 0 1623 196 1450 4294967295 0 1739 2129 1354 4294967295 0 736 400 1216 4294967295 0 1013 417 659 4294967295 0 1686 750 814 4294967295 0 239 1479 2293 4294967295 0 1309 2332 486 4294967295 0 1823 891 16 4294967295 0 111 1697 1267 4294967295 0 2393 1899 730 4294967295 0 955 1126 1534 4294967295 0 381 2166 449 4294967295 0 27 255 1906 4294967295 0 1073 228 2314 4294967295 0 839 1548 569 4294967295 0 1143 352 1526 4294967295 0 629 1622 900 4294967295 0 920 314 208 4294967295 0 844 1184 48 4294967295 0 10 2039 1118 4294967295 0 1557 1207 1725 4294967295 0 648 1189 2456 4294967295 0 5 84 248 4294967295 0 1898 1566 905 4294967295 0 494 1879 1268 4294967295 0 2022 50 1519 4294967295 0 847 1527 938 4294967295 0 1629 1528 1334 4294967295 0 1204 1518 2258 4294967295 0 112 461 962 4294967295 0 693 1029 74 4294967295 0 530 1755 431 4294967295 0 1920 1468 1583 4294967295 0 2089 2365 1740 4294967295 0 2244 322 2434 4294967295 0 363 503 613 4294967295 0 677 1923 1946 4294967295 0 2106 1320 953 4294967295 0 2156 1048 680 4294967295 0 998 2276 2182 4294967295 0 262 778 275 4294967295 0 1076 718 1170 4294967295 0 66 117 1166 4294967295 0 1785 1657 807 4294967295 0 210 2008 1122 4294967295 0 75 2467 270 4294967295 0 1960 1581 1563 4294967295 0 1537 788 1476 4294967295 0 1379 423 1845 4294967295 0 1799 1205 2095 4294967295 0 581 2148 712 4294967295 0 2087 2267 2193 4294967295 0 289 1482 57 4294967295 0 909 527 1041 1 2431 22 1089 2436 2017 225 529 4294967295 0 2241 818 2382 4294967295 0 300 795 2340 1 988 371 996 1919 1384 1966 537 4294967295 0 412 925 432 4294967295 0 2367 333 2170 4294967295 0 1812 207 29 4294967295 0 63 2246 1800 4294967295 0 20 2362 1804 4294967295 0 829 1161 2223 4294967295 0 2140 1015 2445 4294967295 0 178 893 2386 4294967295 0 1992 464 2013 4294967295 0 134 2262 1954 4294967295 0 772 1913 1495 4294967295 0 1871 1712 2224 4294967295 0 1139 1153 1515 4294967295 0 2253 1864 1198 1 994 7 1743 2280 1543 1668 791 4294967295 0 2218 2448 2308 4294967295 0 194 1901 1000 1 968 119 815 101 1766 1256 329 4294967295 0 1861 1169 243 4294967295 0 1488 1836 377 4294967295 0 1930 198 366 4294967295 0 1191 902 1195 4294967295 0 2026 1323 1746 4294967295 0 204 2191 47 4294967295 0 473 2060 1020 4294967295 0 278 1758 723 4294967295 0 1496 1573 1222 4294967295 0 1617 1154 459 4294967295 0 1889 1888 512 4294967295 0 734 1113 2442 4294967295 0 1442 2172 1998 4294967295 0 203 2389 214 1 1545 2355 1409 310 518 1487 341 4294967295 0 259 1392 1475 4294967295 0 1540 362 1387 1 919 1942 1808 1400 1988 271 2107 4294967295 0 802 929 1949 4294967295 0 276 1778 850 4294967295 0 1601 1606 1435 4294967295 0 888 960 2438 4294967295 0 775 1886 335 4294967295 0 2029 521 714 4294967295 0 177 1796 1645 4294967295 0 1429 470 2300 4294967295 0 774 2190 2217 4294967295 0 2228 415 2364 4294967295 0 283 1070 2179 4294967295 0 1218 1578 2398 4294967295 0 133 2430 2071 4294967295 0 1544 2361 1851 4294967295 0 98 448 824 4294967295 0 1393 1019 1162 4294967295 0 211 670 1745 4294967295 0 1332 2001 1357 4294967295 0 2082 1127 983 4294967295 0 1902 1833 2257 4294967295 0 697 1461 2186 4294967295 0 745 428 720 4294967295 0 1040 1149 2122 4294967295 0 1213 1398 870 4294967295 0 982 87 2065 4294967295 0 913 2412 1407 4294967295 0 1842 54 1732 4294967295 0 690 2270 560 4294967295 0 2012 2420 1897 4294967295 0 1156 28 2454 4294967295 0 1938 1858 1494 4294967295 0 984 1536 227 4294967295 0 368 237 876 4294967295 0 1648 1794 2432 4294967295 0 286 1262 1701 4294967295 0 445 2405 2067 4294967295 0 989 961 767 4294967295 0 2010 1104 820 4294967295 0 1012 2328 539 4294967295 0 2292 2298 1665 4294967295 0 674 596 779 4294967295 0 2090 1539 2304 4294967295 0 462 782 2147 4294967295 0 397 605 1414 4294967295 0 1655 557 611 4294967295 0 452 2424 2423 4294967295 0 755 2201 804 4294967295 0 393 475 2301 4294967295 0 1422 2248 2311 4294967295 0 1887 21 1609 4294967295 0 106 868 746 4294967295 0 1417 221 1404 4294967295 0 1307 175 678 4294967295 0 1310 229 215 4294967295 0 430 591 212 4294967295 0 821 1749 627 4294967295 0 827 704 128 4294967295 0 479 894 337 4294967295 0 511 990 1790 4294967295 0 2160 1643 2259 4294967295 0 1199 354 595 4294967295 0 1190 1208 897 4294967295 0 1971 121 1585 4294967295 0 2018 1709 1265 4294967295 0 1500 2178 2229 4294967295 0 874 1284 108 4294967295 0 1728 2341 931 4294967295 0 1465 144 744 4294967295 0 501 76 1412 4294967295 0 2265 2347 2331 4294967295 0 3 2357 2335 4294967295 0 1564 148 1353 4294967295 0 2449 585 405 4294967295 0 906 826 185 4294967295 0 1174 388 2083 4294967295 0 1052 917 427 4294967295 0 93 2146 1123 4294967295 0 2028 404 692 4294967295 0 623 1072 179 4294967295 0 1952 2207 1135 4294967295 0 1034 799 685 4294967295 0 510 911 1424 4294967295 0 1061 1723 1027 4294967295 0 1516 2261 1375 4294967295 0 2056 73 1736 4294967295 0 2371 2177 303 4294967295 0 2199 1438 1102 4294967295 0 1146 474 2474 4294967295 0 1160 1296 1999 4294967295 0 2338 418 450 4294967295 0 1179 1081 1056 4294967295 0 579 304 825 4294967295 0 2153 183 2231 4294967295 0 833 936 182 4294967295 0 851 1110 224 4294967295 0 1425 349 737 4294967295 0 2297 344 832 4294967295 0 1436 49 365 4294967295 0 2114 1987 481 4294967295 0 1972 360 1057 4294967295 0 1829 927 296 4294967295 0 1660 279 1512 4294967295 0 343 1390 534 4294967295 0 1300 1322 1521 4294967295 0 137 1931 1764 4294967295 0 1441 1100 162 4294967295 0 2426 1017 1405 4294967295 0 1350 2200 281 4294967295 0 2021 2451 1554 4294967295 0 1157 1783 1106 4294967295 0 1727 2461 1197 4294967295 0 1044 918 1522 4294967295 0 944 980 1294 4294967295 0 2049 1386 699 4294967295 0 2345 1260 2115 4294967295 0 1142 2457 460 4294967295 0 1377 2116 1514 4294967295 0 1408 533 1986 4294967295 0 937 2383 151 4294967295 0 1094 2324 2118 4294967295 0 1835 2209 2020 4294967295 0 656 1688 2092 4294967295 0 1492 2318 1862 4294967295 0 1097 517 1381 4294967295 0 719 456 1324 4294967295 0 1413 2235 2287 4294967295 0 2444 1674 1815 4294967295 0 2464 785 633 4294967295 0 864 2112 2313 4294967295 0 1295 2203 392 4294967295 0 33 1302 1183 4294967295 0 2359 2306 463 4294967295 0 1961 1410 1024 4294967295 0 524 1344 55 4294967295 0 2358 23 1111 4294967295 0 309 504 2370 4294967295 0 666 1869 257 4294967295 0 1724 1238 1641 4294967295 0 614 1562 1580 4294967295 0 41 1632 2247 4294967295 0 2317 13 1182 4294967295 0 604 571 1582 4294967295 0 1241 52 2394 4294967295 0 940 391 1927 4294967295 0 967 254 1255 4294967295 0 1280 1849 562 4294967295 0 808 320 1440 4294967295 0 667 1672 1049 4294967295 0 682 1850 319 4294967295 0 315 986 408 4294967295 0 2378 152 654 4294967295 0 2074 753 1775 4294967295 0 941 369 1451 1 1591 447 1120 1418 1510 1363 1290 4294967295 0 2046 43 1303 4294967295 0 636 1882 2348 1 637 1068 1305 817 846 848 879 4294967295 0 1705 974 1009 4294967295 0 375 1759 223 1 1941 2034 1285 1383 607 2063 1863 4294967295 366 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 9 14 19 24 33 38 43 48 57 62 67 72 77 82 87 92 97 102 107 112 117 122 127 132 137 142 147 152 157 162 167 172 177 182 187 192 197 202 207 212 217 222 227 232 237 242 247 252 257 262 267 272 277 282 287 292 297 302 307 312 317 322 327 332 337 342 347 352 357 362 367 372 377 382 387 392 397 402 407 412 417 422 427 432 437 442 447 452 457 462 467 472 477 482 487 492 497 502 507 512 517 522 527 532 537 542 547 552 565 570 583 588 593 598 603 608 613 618 623 628 633 638 643 648 661 666 679 684 689 694 699 704 709 714 719 724 729 734 739 744 757 762 775 780 785 790 795 800 805 810 815 820 825 830 835 840 845 850 855 860 865 870 875 880 885 890 895 900 905 910 915 920 925 930 935 940 945 950 955 960 965 970 975 980 985 990 995 1000 1005 1010 1015 1020 1025 1030 1035 1040 1045 1050 1055 1060 1065 1070 1075 1080 1085 1090 1095 1100 1105 1110 1115 1120 1125 1130 1135 1140 1145 1150 1155 1160 1165 1170 1175 1180 1185 1190 1195 1200 1205 1210 1215 1220 1225 1230 1235 1240 1245 1250 1255 1260 1265 1270 1275 1280 1285 1290 1295 1300 1305 1310 1315 1320 1325 1330 1335 1340 1345 1350 1355 1360 1365 1370 1375 1380 1385 1390 1395 1400 1405 1410 1415 1420 1425 1430 1435 1440 1445 1450 1455 1460 1465 1470 1475 1480 1485 1490 1495 1500 1505 1510 1515 1520 1525 1530 1535 1548 1553 1566 1571 0 0 1272 0 1 2127 2120 751 715 2066 1511 2213 724 1567 165 1178 2255 285 4294967295 0 401 651 1896 1 122 2413 860 1249 1878 2154 500 976 1035 1343 641 2373 2416 4294967295 1 1406 1200 2465 2110 497 1997 1140 1904 1266 1525 2279 284 1965 4294967295 0 1096 653 396 1 713 797 1680 849 1416 1642 2124 1368 1940 1748 441 1787 1497 4294967295 1 2103 1595 1647 1694 1439 240 187 1059 340 156 298 570 1630 4294967295 0 435 642 11 1 1675 1774 634 536 548 776 1297 1741 1187 1083 1321 219 1577 4294967295 0 1944 1456 932 4294967295 0 1093 1007 1299 4294967295 0 1279 886 1004 4294967295 0 2128 947 655 4294967295 0 1654 2195 1339 4294967295 0 793 1236 1651 4294967295 0 660 1646 1616 4294967295 0 1767 2 899 4294967295 0 513 1937 1228 4294967295 0 576 1638 573 4294967295 0 1690 1045 302 4294967295 0 426 1773 842 4294967295 0 2125 700 1202 4294967295 0 798 1066 857 4294967295 0 861 68 1509 4294967295 0 1963 2007 1877 4294967295 0 2336 188 1707 4294967295 0 2250 2041 2417 4294967295 0 1499 2123 1391 4294967295 0 1682 1685 171 4294967295 0 703 312 2162 4294967295 0 149 457 2221 4294967295 0 1220 1507 1936 4294967295 0 1326 606 1613 4294967295 0 496 752 1834 4294967295 0 367 1338 218 4294967295 0 1432 1360 823 4294967295 0 1696 1337 1108 4294967295 0 2108 1771 1932 4294967295 0 1795 809 2439 4294967295 0 508 625 1588 4294967295 0 351 794 999 4294967295 0 2150 1366 566 4294967295 0 1275 1843 1246 4294967295 0 1565 100 1576 4294967295 0 1644 1084 1980 4294967295 0 2054 370 2385 4294967295 0 61 930 1203 4294967295 0 45 624 467 4294967295 0 2197 1715 1677 4294967295 0 2396 2342 1894 4294967295 0 676 2003 327 4294967295 0 483 2055 696 4294967295 0 305 1807 915 4294967295 0 582 1274 1168 4294967295 0 1221 2323 2025 4294967295 0 6 966 1333 4294967295 0 1010 1447 749 4294967295 0 1401 338 202 4294967295 0 806 1922 1857 4294967295 0 436 2059 2305 4294967295 0 1586 132 2073 4294967295 0 618 813 485 4294967295 0 1091 1469 901 4294967295 0 1768 2375 995 4294967295 0 1860 1247 632 4294967295 0 2142 2407 236 4294967295 0 1474 235 2453 4294967295 0 1335 669 1650 4294967295 0 1042 2425 1891 4294967295 0 2204 2397 764 4294967295 0 1473 952 256 4294967295 0 453 1702 498 4294967295 0 399 1751 2102 4294967295 0 2164 2192 1730 4294967295 0 2130 781 1854 4294967295 0 956 592 612 4294967295 0 197 2339 1802 4294967295 0 1261 783 716 4294967295 0 679 747 1837 4294967295 0 316 313 1314 4294967295 0 1201 1132 883 4294967295 0 1031 1822 1055 4294967295 0 890 1163 1374 4294967295 0 295 1738 1547 4294967295 0 358 2184 1915 4294967295 0 2227 272 1659 4294967295 0 796 1820 1872 4294967295 0 416 638 822 4294967295 0 419 2377 687 4294967295 0 1550 2079 77 4294967295 0 1962 1826 1150 4294967295 0 691 2326 2138 4294967295 0 1968 274 2289 4294967295 0 2113 19 1328 4294967295 0 414 2078 895 4294967295 0 1030 647 232 4294967295 0 384 1602 742 4294967295 0 1589 1575 26 4294967295 0 558 1230 69 4294967295 0 17 1050 1365 4294967295 0 951 1033 350 4294967295 0 2077 701 2169 4294967295 0 1186 1403 1621 4294967295 0 875 588 398 4294967295 0 425 465 1196 4294967295 0 1394 1584 58 4294967295 0 733 1259 509 4294967295 0 2167 1991 2171 4294967295 0 1903 1226 118 4294967295 0 472 1945 1649 4294967295 0 1914 1597 1640 4294967295 0 1917 2163 471 4294967295 0 90 1726 1117 4294967295 0 1678 2047 2009 4294967295 0 838 586 2131 4294967295 0 2158 1909 559 4294967295 0 157 1832 2096 4294967295 0 761 2473 2086 4294967295 0 664 1490 1734 4294967295 0 1306 1133 433 4294967295 0 2302 1750 92 4294967295 0 1317 1361 46 4294967295 0 1298 1883 1312 4294967295 0 601 263 2369 4294967295 0 1676 1251 1885 4294967295 0 38 2421 110 4294967295 0 492 1620 2303 4294967295 0 2151 125 1718 4294967295 0 331 2333 1948 4294967295 0 1105 1396 324 4294967295 0 2143 997 95 4294967295 0 2286 729 2225 4294967295 0 1505 710 241 4294967295 0 681 1463 1206 4294967295 0 253 2427 1158 4294967295 0 1599 922 1967 4294967295 0 1443 1378 1618 4294967295 0 359 1480 176 4294967295 0 2069 1080 458 4294967295 0 1792 216 1336 4294967295 0 51 505 1624 4294967295 0 609 969 1627 4294967295 0 2472 1340 1423 4294967295 0 975 220 1148 4294967295 0 1232 1008 1327 4294967295 0 800 2242 36 4294967295 0 342 880 269 4294967295 0 2111 1151 153 4294967295 0 244 2004 246 4294967295 0 831 726 873 4294967295 0 1225 1192 665 4294967295 0 1533 1486 328 4294967295 0 1021 1263 1786 4294967295 0 2475 1720 62 4294967295 0 348 2381 1905 4294967295 0 2211 2027 777 4294967295 0 928 79 812 4294967295 0 407 2351 2319 4294967295 0 515 1634 1523 4294967295 0 758 2174 2387 4294967295 0 1358 1411 1976 4294967295 0 383 1504 1958 4294967295 0 2337 1079 1681 4294967295 0 1951 950 1257 4294967295 0 490 488 1852 4294967295 0 2470 1631 577 4294967295 0 2038 1844 1078 4294967295 0 1362 1388 1532 4294967295 0 1866 2230 326 4294967295 0 1555 1729 959 4294967295 0 717 2238 1710 4294967295 0 722 1349 2134 4294967295 0 1219 1704 1137 4294967295 0 2168 2226 646 4294967295 0 2404 834 1036 4294967295 0 301 1180 556 4294967295 0 2356 2136 1993 4294967295 0 2064 1762 1252 4294967295 0 268 2222 142 4294967295 0 2315 2462 1838 4294967295 0 1769 181 769 4294967295 0 451 2450 1559 4294967295 0 2471 2188 102 4294967295 0 2198 2349 136 4294967295 0 1501 2429 1784 4294967295 0 958 964 1791 4294967295 0 1022 1152 2030 4294967295 0 912 172 658 4294967295 0 1370 663 31 4294967295 0 2251 1628 2234 4294967295 0 2068 466 661 4294967295 0 1464 2291 619 4294967295 0 1867 163 9 4294967295 0 292 541 830 4294967295 0 1003 2271 439 4294967295 0 1625 1830 2101 4294967295 0 1038 97 523 4294967295 0 2214 158 1926 4294967295 0 287 1955 1437 4294967295 0 1301 538 978 4294967295 0 409 1481 2145 4294967295 0 2183 683 522 4294967295 0 963 1912 1780 4294967295 0 805 1006 626 4294967295 0 1692 1345 954 4294967295 0 2045 429 1985 4294967295 0 770 1973 1939 4294967295 0 1876 1430 780 4294967295 0 1853 2135 1043 4294967295 0 1282 2137 1269 4294967295 0 1744 866 290 4294967295 0 1453 489 1978 4294967295 0 865 1782 1839 4294967295 0 493 754 114 4294967295 0 1873 1757 2353 4294967295 0 1841 786 205 4294967295 0 2206 1171 2180 4294967295 0 2194 454 732 4294967295 0 1956 1814 1765 4294967295 0 346 1098 233 4294967295 0 1687 728 127 4294967295 0 620 1385 507 4294967295 0 480 104 1943 4294967295 0 1193 2152 2187 4294967295 0 40 887 2411 4294967295 0 0 1281 1346 4294967295 0 299 1777 526 4294967295 0 394 174 385 4294967295 0 616 1415 2139 4294967295 0 1145 1175 1600 4294967295 0 1517 856 2435 4294967295 0 564 993 1670 4294967295 0 201 845 1116 4294967295 0 1173 1165 1352 4294967295 0 1037 170 2232 4294967295 0 1330 1569 957 4294967295 0 1356 885 1789 4294967295 0 1907 2011 1797 4294967295 0 1452 1315 2350 4294967295 0 1181 528 1051 4294967295 0 1816 230 1359 4294967295 0 1691 1245 971 4294967295 0 1129 1369 2256 4294967295 282 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 34 182 107 202 722 802 742 822 257 347 282 367 877 947 897 967 68 117 142 162 267 292 312 332 427 447 472 492 582 602 622 642 0 127 172 217 412 457 502 537 712 757 792 837 1012 1047 1082 1117 277 322 362 397 592 632 667 697 892 927 962 997 1167 1197 1227 1257 467 547 487 562 1057 1127 1072 1142 617 687 637 702 1187 1247 1202 1262 812 832 852 867 957 977 992 1007 1097 1112 1132 1147 1222 1237 1252 1267 662 677 692 707 517 532 552 567 357 377 392 407 192 212 232 247 917 987 932 1002 307 387 327 402 767 847 782 862 137 227 157 242 1032 1067 1102 1137 737 777 817 857 437 482 522 557 102 152 197 237 1207 1192 1177 1162 1232 1172 1217 1157 1242 1212 1182 1152 1077 1062 1042 1027 1107 1037 1092 1022 1122 1087 1052 1017 937 922 907 887 972 902 952 882 982 942 912 872 787 772 752 732 827 747 807 727 842 797 762 717 647 627 607 587 672 597 657 577 682 652 612 572 497 477 452 432 527 442 512 422 542 507 462 417 337 317 297 272 372 287 352 262 382 342 302 252 167 147 122 83 207 112 187 49 222 177 132 15 73 23 Policy::Sequential<3,3> DEAL::OK diff --git a/tests/serialization/hp_dof_handler_01.with_64bit_indices=on.output b/tests/serialization/hp_dof_handler_01.with_64bit_indices=on.output index 0c1e987c5a53..f189f05a4d12 100644 --- a/tests/serialization/hp_dof_handler_01.with_64bit_indices=on.output +++ b/tests/serialization/hp_dof_handler_01.with_64bit_indices=on.output @@ -1,19 +1,19 @@ -DEAL::0 0 20 0 0 5 11 18446744073709551615 0 8 7 18446744073709551615 0 2 9 18446744073709551615 0 0 13 18446744073709551615 0 1 6 18446744073709551615 5 0 0 4 8 12 16 0 0 14 14 0 0 0 0 1 0 0 0 0 14 0 1 14 0 1 0 14 0 0 1 0 1 0 0 14 0 1 14 0 0 0 0 0 3 0 0 10 1 0 -0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 10 -1 2 0 0 0 2 0 4294967295 4294967295 0 0 0 0 2 0 4294967295 4294967295 10 -2 4 0 65535 65535 65535 65535 4 0 0 5 10 15 20 0 5 11 0 13 4 0 13 2 9 12 2 9 1 6 3 1 6 8 7 10 4 0 4 12 3 10 4 0 0 1 2 3 1 7 23 Policy::Sequential<1,1> +DEAL::0 0 23 0 1 5 11 18446744073709551615 0 10 0 18446744073709551615 0 12 15 18446744073709551615 0 2 9 1 2 9 18446744073709551615 0 3 8 18446744073709551615 5 0 0 4 8 12 19 0 0 16 16 0 0 0 0 1 0 0 0 0 16 0 1 16 0 1 0 16 0 0 1 0 1 0 0 16 0 1 16 0 0 0 0 0 3 0 0 10 1 0 +0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 1 0 1 0 10 +1 2 0 0 0 2 0 4294967295 4294967295 0 0 0 0 2 0 4294967295 4294967295 2 0 0 2 0 0 10 +2 4 0 1 65535 65535 65535 4 0 0 7 12 17 22 0 5 11 2 9 14 13 4 2 9 12 15 6 12 15 3 8 7 3 8 10 0 1 6 0 14 13 4 6 7 1 4 0 0 3 4 5 4 1 0 0 0 4 0 1 0 0 1 7 23 Policy::Sequential<1,1> -DEAL::0 0 125 0 0 104 43 148 18446744073709551615 0 182 77 159 18446744073709551615 0 80 52 164 18446744073709551615 0 90 124 40 18446744073709551615 0 16 36 75 18446744073709551615 0 147 178 78 18446744073709551615 0 118 165 185 18446744073709551615 0 126 139 0 18446744073709551615 0 110 73 51 18446744073709551615 0 88 86 2 18446744073709551615 0 72 18 11 18446744073709551615 0 69 12 15 18446744073709551615 0 97 66 84 18446744073709551615 0 106 132 57 18446744073709551615 0 4 29 8 18446744073709551615 0 173 175 45 18446744073709551615 0 115 145 48 18446744073709551615 0 24 119 41 18446744073709551615 0 141 79 98 18446744073709551615 0 155 53 93 18446744073709551615 0 112 67 127 18446744073709551615 0 183 82 162 18446744073709551615 0 95 125 50 18446744073709551615 0 103 113 186 18446744073709551615 0 128 123 37 18446744073709551615 25 0 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 0 0 187 187 0 0 0 0 1 0 0 0 0 187 0 1 187 0 1 0 187 0 0 1 0 1 0 0 187 0 1 187 0 0 0 0 0 3 0 0 10 1 0 -0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 10 -1 4 0 0 0 0 0 4 0 4294967295 4294967295 4294967295 4294967295 0 0 0 0 4 0 4294967295 4294967295 4294967295 4294967295 10 -2 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 22 44 66 88 110 132 154 176 198 220 242 264 286 308 330 352 0 104 43 148 88 86 2 69 12 15 183 82 162 7 181 33 1 89 107 135 19 137 134 88 86 2 16 36 75 183 82 162 24 119 41 33 1 101 25 153 138 150 49 42 81 69 12 15 183 82 162 147 178 78 155 53 93 92 61 146 91 135 19 94 22 144 171 183 82 162 24 119 41 155 53 93 110 73 51 146 91 151 14 150 49 130 161 39 76 16 36 75 72 18 11 24 119 41 95 125 50 101 25 184 3 177 174 117 108 58 102 72 18 11 182 77 159 95 125 50 106 132 57 184 3 63 20 100 68 35 17 60 31 24 119 41 95 125 50 110 73 51 112 67 127 151 14 6 121 117 108 167 10 30 180 95 125 50 106 132 57 112 67 127 118 165 185 6 121 176 5 35 17 122 179 70 136 147 178 78 155 53 93 97 66 84 103 113 186 13 9 27 140 94 22 129 71 172 170 155 53 93 110 73 51 103 113 186 141 79 98 27 140 23 168 130 161 116 26 131 44 97 66 84 103 113 186 80 52 164 173 175 45 55 65 163 64 129 71 152 149 85 142 103 113 186 141 79 98 173 175 45 126 139 0 163 64 46 47 116 26 143 120 156 83 110 73 51 112 67 127 141 79 98 128 123 37 23 168 54 169 167 10 28 87 160 99 112 67 127 118 165 185 128 123 37 4 29 8 54 169 32 111 122 179 157 56 38 158 141 79 98 128 123 37 126 139 0 115 145 48 46 47 105 154 28 87 59 96 166 34 128 123 37 4 29 8 115 145 48 90 124 40 105 154 109 133 157 56 74 114 21 62 32 0 137 134 42 81 144 171 39 76 58 102 60 31 30 180 70 136 172 170 131 44 85 142 156 83 160 99 38 158 166 34 21 62 16 0 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 0 0 0 13 1 0 -3 0 0 160 0 0 7 181 18446744073709551615 0 33 1 18446744073709551615 0 89 107 18446744073709551615 0 135 19 18446744073709551615 0 101 25 18446744073709551615 0 153 138 18446744073709551615 0 150 49 18446744073709551615 0 92 61 18446744073709551615 0 146 91 18446744073709551615 0 94 22 18446744073709551615 0 151 14 18446744073709551615 0 130 161 18446744073709551615 0 184 3 18446744073709551615 0 177 174 18446744073709551615 0 117 108 18446744073709551615 0 63 20 18446744073709551615 0 100 68 18446744073709551615 0 35 17 18446744073709551615 0 6 121 18446744073709551615 0 167 10 18446744073709551615 0 176 5 18446744073709551615 0 122 179 18446744073709551615 0 13 9 18446744073709551615 0 27 140 18446744073709551615 0 129 71 18446744073709551615 0 23 168 18446744073709551615 0 116 26 18446744073709551615 0 55 65 18446744073709551615 0 163 64 18446744073709551615 0 152 149 18446744073709551615 0 46 47 18446744073709551615 0 143 120 18446744073709551615 0 54 169 18446744073709551615 0 28 87 18446744073709551615 0 32 111 18446744073709551615 0 157 56 18446744073709551615 0 105 154 18446744073709551615 0 59 96 18446744073709551615 0 109 133 18446744073709551615 0 74 114 18446744073709551615 56 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 8 20 52 64 0 28 88 108 60 80 136 152 116 124 148 156 16 40 100 120 36 44 76 84 4 32 12 24 48 72 56 68 92 112 96 104 128 144 132 140 21 23 Policy::Sequential<2,2> +DEAL::0 0 137 0 1 104 43 197 18446744073709551615 0 118 165 185 18446744073709551615 0 128 123 37 18446744073709551615 0 150 177 8 18446744073709551615 0 81 147 178 18446744073709551615 0 39 76 72 18446744073709551615 0 141 79 98 18446744073709551615 0 157 56 38 18446744073709551615 0 182 77 159 18446744073709551615 0 201 49 209 1 201 49 209 18446744073709551615 0 68 35 17 18446744073709551615 0 14 130 161 1 14 130 161 18446744073709551615 0 80 208 164 18446744073709551615 0 176 5 122 18446744073709551615 0 74 190 21 18446744073709551615 0 54 169 28 18446744073709551615 0 25 186 132 18446744073709551615 0 93 92 61 18446744073709551615 0 126 139 198 18446744073709551615 0 18 11 95 18446744073709551615 0 193 13 9 18446744073709551615 0 78 155 53 1 78 155 53 18446744073709551615 0 60 31 112 18446744073709551615 0 173 175 45 18446744073709551615 0 59 96 166 18446744073709551615 25 0 0 5 10 15 20 25 30 35 40 45 54 59 68 73 78 83 88 93 98 103 108 113 122 127 132 0 0 210 210 0 0 0 0 1 0 0 0 0 210 0 1 210 0 1 0 210 0 0 1 0 1 0 0 210 0 1 210 0 0 0 0 0 3 0 0 10 1 0 +0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 1 0 1 0 10 +1 4 0 0 0 0 0 4 0 4294967295 4294967295 4294967295 4294967295 0 0 0 0 4 0 4294967295 4294967295 4294967295 4294967295 4 0 0 0 0 4 0 0 0 0 10 +2 16 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 41 63 85 107 129 151 173 195 217 239 261 283 305 327 349 371 0 104 43 197 201 49 209 14 130 161 78 155 53 88 86 2 69 12 15 183 82 162 7 181 33 1 89 107 135 19 137 134 16 36 191 24 119 41 101 192 153 138 201 49 209 81 147 178 78 155 53 93 92 61 146 91 94 22 144 171 110 73 51 151 14 130 161 78 155 53 39 76 72 18 11 95 125 205 184 3 199 174 117 108 58 102 78 155 53 93 92 61 18 11 95 182 77 159 184 3 196 194 110 73 200 63 20 100 81 147 178 68 35 17 93 92 61 60 31 112 94 22 67 204 6 121 195 10 30 180 68 35 17 118 165 185 60 31 112 176 5 122 67 204 179 70 136 97 66 84 103 207 93 92 61 60 31 112 182 77 159 193 13 9 196 194 27 140 195 10 129 71 172 170 60 31 112 176 5 122 193 13 9 141 79 98 27 140 23 168 66 84 116 26 131 44 39 76 72 18 11 95 80 208 164 173 175 45 55 65 163 64 117 108 152 149 85 142 18 11 95 182 77 159 173 175 45 126 139 198 163 64 46 187 200 63 143 120 156 83 80 208 164 173 175 45 128 123 37 54 169 28 87 160 99 4 152 149 29 203 32 111 173 175 45 126 139 198 54 169 28 157 56 38 99 4 158 115 143 120 145 48 105 154 182 77 159 193 13 9 126 139 198 59 96 166 46 187 189 206 129 71 124 40 109 133 193 13 9 141 79 98 59 96 166 74 190 21 189 206 62 47 116 26 202 34 114 75 126 139 198 59 96 166 157 56 38 25 186 132 158 115 167 106 124 40 148 0 188 57 59 96 166 74 190 21 25 186 132 150 177 8 167 106 127 50 202 34 90 113 52 42 39 0 36 191 24 119 41 101 192 153 138 51 151 58 102 20 100 30 180 103 207 172 170 131 44 85 142 156 83 32 111 105 154 109 133 114 75 188 57 52 42 16 0 0 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 16 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 1 0 +3 0 0 178 0 1 88 86 2 69 12 18446744073709551615 0 146 91 1 15 183 82 162 7 18446744073709551615 1 181 33 1 89 107 18446744073709551615 0 199 174 1 135 19 137 134 16 18446744073709551615 0 94 22 18446744073709551615 0 144 171 18446744073709551615 0 110 73 18446744073709551615 0 125 205 18446744073709551615 0 184 3 18446744073709551615 0 117 108 18446744073709551615 0 196 194 18446744073709551615 0 200 63 18446744073709551615 0 67 204 18446744073709551615 0 6 121 18446744073709551615 0 195 10 18446744073709551615 0 179 70 18446744073709551615 0 136 97 18446744073709551615 0 66 84 18446744073709551615 0 27 140 18446744073709551615 0 129 71 18446744073709551615 0 23 168 18446744073709551615 0 116 26 18446744073709551615 0 55 65 18446744073709551615 0 163 64 18446744073709551615 0 152 149 18446744073709551615 0 46 187 18446744073709551615 0 143 120 18446744073709551615 0 87 160 18446744073709551615 0 99 4 18446744073709551615 0 29 203 18446744073709551615 0 158 115 18446744073709551615 0 145 48 18446744073709551615 0 189 206 18446744073709551615 0 124 40 18446744073709551615 0 62 47 18446744073709551615 0 202 34 18446744073709551615 0 167 106 18446744073709551615 0 148 0 18446744073709551615 0 127 50 18446744073709551615 0 90 113 18446744073709551615 56 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 17 38 70 82 0 46 106 126 78 98 154 170 134 142 166 174 34 58 118 138 54 62 94 102 7 50 24 42 66 90 74 86 110 130 114 122 146 162 150 158 21 23 Policy::Sequential<2,2> -DEAL::0 0 750 0 0 1217 903 1574 88 18446744073709551615 0 11 1499 2123 1391 18446744073709551615 0 1551 1531 98 448 18446744073709551615 0 1728 0 931 2022 18446744073709551615 0 324 2143 997 95 18446744073709551615 0 828 907 514 1316 18446744073709551615 0 1464 2291 619 1867 18446744073709551615 0 1294 1727 2173 1197 18446744073709551615 0 2120 751 715 2066 18446744073709551615 0 1059 340 156 298 18446744073709551615 0 479 2046 43 1303 18446744073709551615 0 1696 1337 1108 2108 18446744073709551615 0 972 1293 1934 99 18446744073709551615 0 1042 1005 1891 2204 18446744073709551615 0 1837 316 313 1314 18446744073709551615 0 2167 1991 2171 1903 18446744073709551615 0 1158 1599 922 1967 18446744073709551615 0 458 1792 216 1336 18446744073709551615 0 1362 1388 1532 1866 18446744073709551615 0 282 502 1214 411 18446744073709551615 0 131 1308 1806 2088 18446744073709551615 0 1598 896 1924 462 18446744073709551615 0 1651 660 1646 1616 18446744073709551615 0 1823 891 16 315 18446744073709551615 0 1156 28 1538 1552 18446744073709551615 0 1423 975 220 1148 18446744073709551615 0 1056 1785 1657 807 18446744073709551615 0 86 347 1134 424 18446744073709551615 0 336 311 628 2263 18446744073709551615 0 1990 526 1666 994 18446744073709551615 0 1086 1608 1075 2149 18446744073709551615 0 1668 791 2132 1491 18446744073709551615 0 512 1426 2098 2061 18446744073709551615 0 1684 1805 139 2062 18446744073709551615 0 1798 616 209 1373 18446744073709551615 0 1717 789 705 130 18446744073709551615 0 20 2147 1804 177 18446744073709551615 0 824 618 813 485 18446744073709551615 0 1699 2080 1870 14 18446744073709551615 0 1091 1469 901 1768 18446744073709551615 0 2064 1762 1252 268 18446744073709551615 0 50 1519 2269 1721 18446744073709551615 0 1756 1046 1242 924 18446744073709551615 0 1 306 1311 1144 18446744073709551615 0 928 79 812 407 18446744073709551615 0 1032 1449 226 580 18446744073709551615 0 1034 799 685 958 18446744073709551615 0 535 1535 1121 555 18446744073709551615 0 767 865 1782 1839 18446744073709551615 0 163 9 292 541 18446744073709551615 0 837 1920 1468 1583 18446744073709551615 0 300 795 1414 1763 18446744073709551615 0 152 654 829 1161 18446744073709551615 0 165 1178 2255 285 18446744073709551615 0 1369 2086 664 1490 18446744073709551615 0 1511 2213 724 1567 18446744073709551615 0 464 2013 1280 1849 18446744073709551615 0 570 1630 1675 1774 18446744073709551615 0 2083 1537 788 1476 18446744073709551615 0 634 536 548 776 18446744073709551615 0 1566 905 1500 2178 18446744073709551615 0 673 1663 941 369 18446744073709551615 0 960 1655 967 254 18446744073709551615 0 1771 1932 1795 809 18446744073709551615 0 792 403 1856 816 18446744073709551615 0 1085 2155 264 898 18446744073709551615 0 734 1113 2011 614 18446744073709551615 0 373 1639 1016 635 18446744073709551615 0 1074 1546 1002 546 18446744073709551615 0 1173 764 1473 952 18446744073709551615 0 451 965 1559 971 18446744073709551615 0 1402 859 855 1131 18446744073709551615 0 1918 2278 199 1062 18446744073709551615 0 135 760 1810 1953 18446744073709551615 0 657 4 1788 1244 18446744073709551615 0 2303 2151 125 1718 18446744073709551615 0 869 24 1603 552 18446744073709551615 0 370 2160 61 930 18446744073709551615 0 1096 653 396 1767 18446744073709551615 0 1916 1880 1013 417 18446744073709551615 0 154 889 2218 528 18446744073709551615 0 339 2205 291 721 18446744073709551615 0 1724 1238 1641 2010 18446744073709551615 0 1389 1472 991 854 18446744073709551615 0 36 342 880 269 18446744073709551615 0 7 1743 2280 1543 18446744073709551615 0 910 1420 2243 443 18446744073709551615 0 180 1018 184 308 18446744073709551615 0 85 1700 987 1060 18446744073709551615 0 191 968 119 815 18446744073709551615 0 1243 1813 53 1817 18446744073709551615 0 1104 820 2292 2298 18446744073709551615 0 1952 2207 1135 722 18446744073709551615 0 765 1115 2272 2087 18446744073709551615 0 1467 1561 1610 921 18446744073709551615 0 1796 1645 708 785 18446744073709551615 0 530 1755 431 963 18446744073709551615 0 1975 995 1860 1247 18446744073709551615 0 2222 142 1407 147 18446744073709551615 0 926 1014 1799 1205 18446744073709551615 0 2268 1310 229 215 18446744073709551615 0 39 2254 1846 129 18446744073709551615 0 1611 1193 515 1634 18446744073709551615 0 964 1791 1022 1152 18446744073709551615 0 706 30 468 946 18446744073709551615 0 1029 74 951 1033 18446744073709551615 0 1255 1241 52 201 18446744073709551615 0 2223 682 1850 319 18446744073709551615 0 1451 1441 1100 162 18446744073709551615 0 2099 1669 1824 1422 18446744073709551615 0 955 1126 1534 2153 18446744073709551615 0 2229 2082 1127 983 18446744073709551615 0 1297 1741 1187 1083 18446744073709551615 0 1827 1258 1288 1188 18446744073709551615 0 1734 160 1614 293 18446744073709551615 0 562 1401 338 202 18446744073709551615 0 122 1842 860 1249 18446744073709551615 0 101 1766 1256 329 18446744073709551615 0 872 694 1540 362 18446744073709551615 0 1130 111 1697 1267 18446744073709551615 0 265 325 1106 96 18446744073709551615 0 1665 1917 2163 471 18446744073709551615 0 1155 1571 1330 1979 18446744073709551615 0 1349 2134 1219 1704 18446744073709551615 0 287 1955 1437 1301 18446744073709551615 125 0 0 6 12 18 24 30 36 42 48 54 60 66 72 78 84 90 96 102 108 114 120 126 132 138 144 150 156 162 168 174 180 186 192 198 204 210 216 222 228 234 240 246 252 258 264 270 276 282 288 294 300 306 312 318 324 330 336 342 348 354 360 366 372 378 384 390 396 402 408 414 420 426 432 438 444 450 456 462 468 474 480 486 492 498 504 510 516 522 528 534 540 546 552 558 564 570 576 582 588 594 600 606 612 618 624 630 636 642 648 654 660 666 672 678 684 690 696 702 708 714 720 726 732 738 744 0 0 2312 2312 0 0 0 0 1 0 0 0 0 2312 0 1 2312 0 1 0 2312 0 0 1 0 1 0 0 2312 0 1 2312 0 0 0 0 0 3 0 0 10 1 0 -0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 10 -1 8 0 0 0 0 0 0 0 0 0 8 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 8 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 10 -2 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 89 178 267 356 445 534 623 712 801 890 979 1068 1157 1246 1335 1424 1513 1602 1691 1780 1869 1958 2047 2136 2225 2314 2403 2492 2581 2670 2759 2848 2937 3026 3115 3204 3293 3382 3471 3560 3649 3738 3827 3916 4005 4094 4183 4272 4361 4450 4539 4628 4717 4806 4895 4984 5073 5162 5251 5340 5429 5518 5607 5696 0 1217 903 1574 88 86 347 1134 424 1990 526 1666 994 7 1743 2280 1543 1668 791 2132 1491 339 2205 291 721 191 968 119 815 101 1766 1256 329 919 1942 1808 1400 1988 271 2107 1941 2034 1285 1383 607 2063 1863 356 22 1089 640 2017 225 529 637 1068 1305 817 846 848 879 18 2266 2093 1291 1719 1199 1039 988 371 996 1919 1384 1966 537 1545 803 1409 310 518 1487 341 1591 447 1120 1418 1510 1363 1290 2127 86 347 1134 424 2120 751 715 2066 7 1743 2280 1543 1511 2213 724 1567 339 2205 291 721 165 1178 2255 285 101 1766 1256 329 122 1842 860 1249 1400 1988 271 1878 2154 500 976 1035 1343 641 856 1037 22 1089 640 1406 1200 1593 2110 497 1997 1140 1904 1266 879 18 2266 1525 2279 284 1199 1039 988 1965 713 797 1384 1966 537 1680 849 1416 1642 2124 1368 1940 1748 441 1787 1497 2103 1595 1647 1694 1439 240 187 1990 526 1666 994 7 1743 2280 1543 1059 340 156 298 570 1630 1675 1774 191 968 119 815 101 1766 1256 329 634 536 548 776 1297 1741 1187 1083 1321 219 1577 56 1667 2216 1285 1383 607 387 1112 252 1212 1761 532 382 1679 1607 637 1068 1305 945 2175 1167 2093 1291 1719 1199 1039 988 109 2097 590 190 1828 1895 740 1770 1910 1753 1347 247 310 518 1487 1466 584 167 668 916 1477 1908 476 1028 1579 1592 990 7 1743 2280 1543 1511 2213 724 1567 570 1630 1675 1774 1598 896 1924 462 101 1766 1256 329 122 1842 860 1249 1297 1741 1187 1083 869 24 1603 552 56 1667 2216 161 2076 1928 641 856 1037 140 1737 702 382 1679 1607 402 1714 763 1140 1904 1266 2245 2253 1864 1199 1039 988 1965 713 797 190 1828 1895 1198 1739 2129 1753 1347 247 1354 499 973 1940 1748 441 2275 1861 1169 243 375 1759 223 1350 2200 281 2241 818 1668 791 2132 1491 339 2205 291 721 191 968 119 815 101 1766 1256 329 479 2046 43 1303 300 795 1414 1763 673 1663 941 369 1451 1441 1100 162 2063 1863 356 22 1089 640 2017 225 529 637 1068 1305 401 651 1896 1944 1456 932 1093 1007 1299 1279 886 1004 2128 947 655 1654 2195 1339 1331 914 743 1231 1821 599 565 1484 1292 2015 143 2309 589 1090 757 2121 1911 1825 1120 1418 1510 390 1210 2274 1797 597 25 339 2205 291 721 165 1178 2255 285 101 1766 1256 329 122 1842 860 1249 300 795 1414 1763 131 1308 1806 2088 1451 1441 1100 162 154 889 2218 528 22 1089 640 1406 1200 1593 2110 497 1997 1140 1904 1266 1944 1456 932 2308 194 1901 1000 239 1479 2293 802 929 1654 2195 1339 1949 1705 974 1231 1821 599 1009 636 1882 2015 143 2309 174 397 418 450 203 1783 214 1670 1899 1595 1647 1694 730 579 304 825 793 1236 191 968 119 815 101 1766 1256 329 634 536 548 776 1297 1741 1187 1083 673 1663 941 369 1451 1441 1100 162 1651 660 1646 1616 1096 653 396 1767 1212 1761 532 382 1679 1607 637 1068 1305 945 2175 1167 2 899 513 1937 1228 576 1279 886 1004 1638 573 543 1331 914 743 1231 1821 599 94 843 1604 2033 1485 756 1026 2176 1776 251 736 400 2121 1911 1825 1216 1309 2049 1908 476 1028 486 2021 64 1554 1179 1081 101 1766 1256 329 122 1842 860 1249 1297 1741 1187 1083 869 24 1603 552 1451 1441 1100 162 154 889 2218 528 1096 653 396 1767 1056 1785 1657 807 382 1679 1607 402 1714 763 1140 1904 1266 2245 2253 1864 1937 1228 576 1690 1045 302 2293 802 929 426 1773 842 1231 1821 599 1009 636 1882 2033 1485 756 2125 700 1202 251 736 400 798 1066 857 214 1670 1899 549 169 2233 223 1350 2200 1671 200 1594 1996 892 1893 2120 751 715 2066 336 311 628 2263 1511 2213 724 1567 910 1420 2243 443 165 1178 2255 285 1389 1472 991 854 122 1842 860 1249 872 694 1540 362 1878 2154 500 1387 909 527 1041 1073 228 595 906 826 1406 1200 1593 185 35 1868 992 1052 917 427 2249 1103 1525 2279 284 1570 412 925 1965 713 797 432 259 1392 1680 849 1416 1475 2074 753 1775 861 68 1509 1963 2007 1877 1539 188 1707 2250 2041 170 435 642 336 311 628 2263 11 1499 2123 1391 910 1420 2243 443 1684 1805 139 2062 1389 1472 991 854 1717 789 705 130 872 694 1540 362 765 1115 2272 2087 1387 909 527 2267 2193 1318 1462 525 93 2146 1123 1095 185 35 1868 59 1458 727 1017 1405 1682 1685 171 703 1570 412 925 312 2162 149 432 259 1392 457 2221 1220 1475 2074 753 1507 1936 2196 615 1959 1658 1270 934 249 238 44 334 421 839 1548 569 1174 388 1511 2213 724 1567 910 1420 2243 443 1598 896 1924 462 2083 1537 788 1476 122 1842 860 1249 872 694 1540 362 869 24 1603 552 955 1126 1534 2153 161 2076 1928 183 2231 1326 595 906 826 606 1613 496 402 1714 763 752 1834 367 427 2249 1103 1338 218 1432 1965 713 797 432 259 1392 1198 1739 2129 1360 823 2037 1354 499 973 1865 2058 1224 1509 1963 2007 748 155 1731 289 1482 57 1379 423 1845 210 2008 1122 910 1420 2243 443 1684 1805 139 2062 2083 1537 788 1476 1696 1337 1108 2108 872 694 1540 362 765 1115 2272 2087 955 1126 1534 2153 1771 1932 1795 809 183 2231 1326 557 773 1067 2146 1123 1095 542 2032 608 752 1834 367 970 1448 2081 1685 171 703 250 602 444 432 259 1392 457 2221 1220 1360 823 2037 386 231 1428 1865 2058 1224 2310 217 1286 1270 934 249 126 1001 1488 1836 377 1319 1227 871 1191 902 1195 2052 165 1178 2255 285 1389 1472 991 854 122 1842 860 1249 872 694 1540 362 131 1308 1806 2088 152 654 829 1161 154 889 2218 528 2223 682 1850 319 1406 1200 1593 185 35 1868 992 1052 917 427 2249 1103 2308 194 1901 178 893 1643 808 320 1440 508 625 1588 1949 1705 974 351 794 999 1009 636 1882 2150 1366 566 174 397 418 1275 1843 1246 1565 100 1576 2236 1568 1900 1707 2250 2041 1892 610 1929 1981 1460 1181 1389 1472 991 854 1717 789 705 130 872 694 1540 362 765 1115 2272 2087 152 654 829 1161 972 1293 1934 99 2223 682 1850 319 1085 2155 264 898 185 35 1868 59 1458 727 1017 1405 1682 1685 171 703 178 893 1643 1372 2050 1831 321 372 330 1664 1760 2026 351 794 999 1323 1746 1393 2150 1366 566 1019 1162 2140 1275 1843 1246 1015 1315 667 1672 1049 120 598 1023 1544 421 839 1548 782 1851 1644 1084 1980 2054 122 1842 860 1249 872 694 1540 362 869 24 1603 552 955 1126 1534 2153 154 889 2218 528 2223 682 1850 319 1056 1785 1657 807 370 2160 61 930 402 1714 763 752 1834 367 427 2249 1103 1338 218 1432 1690 1045 302 1203 45 624 508 625 1588 467 2197 1715 1009 636 1882 2150 1366 566 2125 700 1202 1677 442 578 798 1066 857 1459 1970 2036 2236 1568 1900 40 317 1626 1379 423 1845 1964 299 935 1930 198 366 872 694 1540 362 765 1115 2272 2087 955 1126 1534 2153 1771 1932 1795 809 2223 682 1850 319 1085 2155 264 898 370 2160 61 930 1823 891 16 315 752 1834 367 970 1448 2081 1685 171 703 250 602 444 1203 45 624 986 408 510 1664 1760 2026 911 1424 1516 2150 1366 566 1019 1162 2140 1677 442 578 2261 1375 1116 1459 1970 2036 1281 1894 676 598 1023 1544 2003 327 483 1227 871 1191 2055 696 305 1807 915 168 1059 340 156 298 570 1630 1675 1774 1086 1608 1075 2149 180 1018 184 308 634 536 548 776 1297 1741 1187 1083 1243 1813 53 1817 1130 111 1697 1267 211 670 1745 1061 1723 1027 387 1112 252 920 314 208 582 1274 1168 1221 887 2025 945 2175 1167 6 966 1333 109 2097 590 190 1828 1895 1010 1447 749 2185 771 985 422 600 353 2043 611 37 1466 584 167 1522 1517 2265 394 1147 1933 1977 2181 1564 148 1353 1992 570 1630 1675 1774 1598 896 1924 462 180 1018 184 308 464 2013 1280 1849 1297 1741 1187 1083 869 24 1603 552 1130 111 1697 1267 562 1401 338 202 1061 1723 1027 806 1922 1857 140 1737 702 436 2059 2305 1221 887 2025 1586 132 2073 2245 2253 1864 738 1082 374 190 1828 1895 1198 1739 2129 2185 771 985 1859 2152 1047 2043 611 37 1054 103 1935 2275 1861 1169 1194 1661 648 1189 1283 15 54 2126 1051 585 405 863 1086 1608 1075 2149 180 1018 184 308 1551 1531 98 448 824 618 813 485 1243 1813 53 1817 1130 111 1697 1267 1091 1469 901 1768 1975 995 1860 1247 632 759 1711 574 1847 484 920 314 208 2215 1520 3 2012 2090 75 230 270 2056 6 966 1333 73 1736 2142 1010 1447 749 2185 771 985 2019 236 1474 235 355 1335 669 1650 1875 389 70 1957 1522 1517 2265 939 2144 12 5 84 248 1960 1581 1563 844 1184 48 180 1018 184 308 464 2013 1280 1849 824 618 813 485 1042 1005 1891 2204 1130 111 1697 1267 562 1401 338 202 1975 995 1860 1247 1173 764 1473 952 574 1847 484 256 361 1124 436 2059 2305 437 1995 2094 230 270 2056 1673 2161 2277 738 1082 374 1508 520 1890 2185 771 985 1859 2152 1047 235 355 1335 1304 2295 1348 389 70 1957 116 60 1706 1194 1661 648 545 547 1141 245 1395 204 2191 47 278 1758 723 888 634 536 548 776 1297 1741 1187 1083 1243 1813 53 1817 1130 111 1697 1267 1651 660 1646 1616 1096 653 396 1767 960 1655 967 254 1255 1241 52 201 582 1274 1168 1221 887 2025 945 2175 1167 6 966 1333 276 1778 850 104 13 1182 1638 573 543 453 1702 498 94 843 1604 2033 1485 756 399 1751 2102 2164 2192 1730 2130 781 1854 956 592 612 1216 1309 2049 1558 2085 735 1977 2181 1564 1619 206 836 567 273 2016 1297 1741 1187 1083 869 24 1603 552 1130 111 1697 1267 562 1401 338 202 1096 653 396 1767 1056 1785 1657 807 1255 1241 52 201 1916 1880 1013 417 1221 887 2025 1586 132 2073 2245 2253 1864 738 1082 374 104 13 1182 659 1496 1573 426 1773 842 1222 1300 1322 2033 1485 756 2125 700 1202 2164 2192 1730 1521 604 571 956 592 612 1582 1660 279 549 169 2233 1512 197 605 54 2126 1051 1802 1261 783 716 679 747 1243 1813 53 1817 1130 111 1697 1267 1091 1469 901 1768 1975 995 1860 1247 960 1655 967 254 1255 1241 52 201 1837 316 313 1314 373 1639 1016 635 2012 2090 75 230 270 2056 6 966 1333 73 1736 2142 1053 1457 1907 2283 2208 1211 453 1702 498 841 1781 1542 399 1751 2102 2164 2192 1730 105 862 294 2189 1128 1884 1157 1125 1793 473 2060 1020 1558 2085 735 1376 438 1989 1960 1581 1563 775 1886 335 940 391 1927 1130 111 1697 1267 562 1401 338 202 1975 995 1860 1247 1173 764 1473 952 1255 1241 52 201 1916 1880 1013 417 373 1639 1016 635 1156 28 1538 1552 230 270 2056 1673 2161 2277 738 1082 374 1508 520 1890 2283 2208 1211 164 2294 984 1222 1300 1322 1536 227 1201 2164 2192 1730 1521 604 571 2189 1128 1884 1132 883 1031 473 2060 1020 1822 1055 890 1512 197 605 1163 1374 295 2191 47 278 1738 1547 358 2184 1915 261 1598 896 1924 462 2083 1537 788 1476 464 2013 1280 1849 85 1700 987 1060 869 24 1603 552 955 1126 1534 2153 562 1401 338 202 265 325 1106 96 806 1922 1857 323 242 1686 606 1613 496 750 814 884 1586 132 2073 878 2288 137 1338 218 1432 1931 1764 1938 1198 1739 2129 1360 823 2037 1859 2152 1047 1858 1494 112 1054 103 1935 461 962 2227 748 155 1731 272 1659 796 1820 1872 416 638 822 419 2044 687 943 2083 1537 788 1476 1696 1337 1108 2108 85 1700 987 1060 1798 616 209 1373 955 1126 1534 2153 1771 1932 1795 809 265 325 1106 96 1467 1561 1610 921 323 242 1686 280 1506 1143 542 2032 608 352 1526 874 878 2288 137 1284 108 1465 250 602 444 144 744 1601 1360 823 2037 386 231 1428 1858 1494 112 1606 1435 41 461 962 2227 1632 2247 1550 126 1001 1488 2079 77 1962 1826 1150 691 1025 2138 1968 274 2289 1235 464 2013 1280 1849 85 1700 987 1060 1042 1005 1891 2204 1699 2080 1870 14 562 1401 338 202 265 325 1106 96 1173 764 1473 952 926 1014 1799 1205 256 361 1124 2095 501 76 750 814 884 1412 343 1390 1673 2161 2277 534 2113 19 1931 1764 1938 1328 414 2078 1859 2152 1047 1858 1494 112 1304 2295 1348 895 1030 647 116 60 1706 232 923 904 272 1659 796 2159 2220 83 2281 622 1747 707 621 1159 629 1622 900 85 1700 987 1060 1798 616 209 1373 1699 2080 1870 14 1728 0 931 2022 265 325 1106 96 1467 1561 1610 921 926 1014 1799 1205 50 1519 2269 1721 2095 501 76 2031 368 237 352 1526 874 876 384 1602 534 2113 19 742 1589 1575 144 744 1601 26 558 1230 1858 1494 112 1606 1435 41 895 1030 647 69 17 1050 232 923 904 1365 1693 1950 2079 77 1962 1371 1399 1840 1848 72 581 2148 712 847 1527 938 693 869 24 1603 552 955 1126 1534 2153 562 1401 338 202 265 325 1106 96 1056 1785 1657 807 370 2160 61 930 1916 1880 1013 417 1029 74 951 1033 1586 132 2073 878 2288 137 1338 218 1432 1931 1764 1938 659 1496 1573 350 2077 701 467 2197 1715 2169 1186 1403 2125 700 1202 1677 442 578 1521 604 571 1621 277 1215 1582 1660 279 173 787 1069 40 317 1626 192 2296 1092 638 822 419 1735 159 1223 1617 1154 459 955 1126 1534 2153 1771 1932 1795 809 265 325 1106 96 1467 1561 1610 921 370 2160 61 930 1823 891 16 315 1029 74 951 1033 734 1113 2011 614 878 2288 137 1284 108 1465 250 602 444 144 744 1601 350 2077 701 1562 1580 666 911 1424 1516 1869 257 1569 1677 442 578 2261 1375 1116 1621 277 1215 23 1111 875 173 787 1069 588 398 425 2003 327 483 465 1196 1394 1025 2138 1968 1584 58 733 1259 509 1811 562 1401 338 202 265 325 1106 96 1173 764 1473 952 926 1014 1799 1205 1916 1880 1013 417 1029 74 951 1033 1156 28 1538 1552 1074 1546 1002 546 1673 2161 2277 534 2113 19 1931 1764 1938 1328 414 2078 164 2294 984 1974 376 1454 2169 1186 1403 867 80 469 1521 604 571 1621 277 1215 1132 883 1031 1237 1779 357 1822 1055 890 1442 2172 1998 192 2296 1092 1902 1833 2257 707 621 1159 309 504 1175 1332 2001 1357 265 325 1106 96 1467 1561 1610 921 926 1014 1799 1205 50 1519 2269 1721 1029 74 951 1033 734 1113 2011 614 1074 1546 1002 546 2167 1991 2171 1903 534 2113 19 742 1589 1575 144 744 1601 26 558 1230 1974 376 1454 1226 118 472 1869 257 1569 1945 1649 1914 1621 277 1215 23 1111 875 1237 1779 357 1597 1640 107 1442 2172 1998 1367 684 1107 465 1196 1394 2252 671 942 2148 712 847 307 1695 593 561 1889 1888 479 2046 43 1303 300 795 1414 1763 673 1663 941 369 1451 1441 1100 162 512 1426 2098 2061 1724 1238 1641 2010 1104 820 2292 2298 1665 1917 2163 471 401 651 1896 1944 1456 932 1093 1007 1299 1279 886 1004 90 1726 1117 1678 2047 2009 838 586 2131 695 1982 1713 741 89 1683 1590 1969 1502 141 1816 2119 662 1325 491 568 123 697 1461 2186 1012 1818 539 572 1733 1493 2158 390 1210 2274 1909 559 157 1832 2096 761 300 795 1414 1763 131 1308 1806 2088 1451 1441 1100 162 154 889 2218 528 1724 1238 1641 2010 1369 2086 664 1490 1665 1917 2163 471 1734 160 1614 293 1944 1456 932 2308 194 1901 1000 239 1479 2293 802 929 1678 2047 2009 1271 553 1984 2057 1190 1208 897 2018 1709 1590 1969 1502 1265 524 1344 662 1325 491 55 1306 1133 1461 2186 1012 433 2302 1750 92 1317 1361 46 1855 480 730 579 304 420 689 630 1530 1529 1898 673 1663 941 369 1451 1441 1100 162 1651 660 1646 1616 1096 653 396 1767 1104 820 2292 2298 1665 1917 2163 471 1566 905 1500 2178 2229 2082 1127 983 2 899 513 1937 1228 576 1279 886 1004 1638 573 543 1298 1883 1312 601 263 1145 695 1982 1713 1676 1251 1885 141 1816 2119 662 1325 491 1662 858 1421 688 213 790 845 1971 121 1585 1629 1528 1733 1493 2158 1334 674 596 486 2021 64 779 38 957 110 492 1620 1451 1441 1100 162 154 889 2218 528 1096 653 396 1767 1056 1785 1657 807 1665 1917 2163 471 1734 160 1614 293 2229 2082 1127 983 2303 2151 125 1718 1937 1228 576 1690 1045 302 2293 802 929 426 1773 842 601 263 1145 446 1881 2273 897 2018 1709 1556 645 1874 662 1325 491 55 1306 1133 688 213 790 544 494 1879 1585 1629 1528 1268 1204 1518 46 1855 480 2258 784 2109 1671 200 1594 1071 331 1386 1948 1105 1396 512 1426 2098 2061 1724 1238 1641 2010 1104 820 2292 2298 1665 1917 2163 471 324 2143 997 95 1 306 1311 1144 1032 1449 226 580 39 2254 1846 129 90 1726 1117 1678 2047 2009 838 586 2131 695 1982 1713 2232 1612 2157 2023 882 1397 835 1429 470 2300 1961 1410 1024 1415 333 2170 33 1302 1183 345 2053 587 63 2246 1800 2029 521 714 864 2112 913 2286 729 2225 1505 710 1909 559 157 241 681 1463 1206 253 1114 1724 1238 1641 2010 1369 2086 664 1490 1665 1917 2163 471 1734 160 1614 293 1 306 1311 1144 1158 1599 922 1967 39 2254 1846 129 1402 859 855 1131 1678 2047 2009 1271 553 1984 2057 1190 1208 897 2018 1709 2023 882 1397 1355 639 8 380 34 1351 1656 1972 360 2170 33 1302 1057 1812 207 587 63 2246 29 1295 2203 714 864 2112 392 2240 1164 1419 1436 49 365 1443 1378 420 689 630 1618 359 1480 176 2069 1080 1104 820 2292 2298 1665 1917 2163 471 1566 905 1500 2178 2229 2082 1127 983 1032 1449 226 580 39 2254 1846 129 458 1792 216 1336 135 760 1810 1953 1298 1883 1312 601 263 1145 695 1982 1713 1676 1251 1885 554 478 1921 977 1434 378 2300 1961 1410 2048 774 2190 1183 345 2053 587 63 2246 2217 1897 2306 463 1600 2177 303 381 2166 449 1146 474 2225 1505 710 2256 51 505 779 38 957 1624 609 969 1627 1129 1340 1665 1917 2163 471 1734 160 1614 293 2229 2082 1127 983 2303 2151 125 1718 39 2254 1846 129 1402 859 855 1131 135 760 1810 1953 1423 975 220 1148 601 263 1145 446 1881 2273 897 2018 1709 1556 645 1874 977 1434 378 2282 877 650 1656 1972 360 332 1703 1524 587 63 2246 29 1295 2203 463 1600 2177 1234 1829 927 449 1146 474 296 2199 1438 365 1443 1378 1102 1076 718 1071 331 1386 1170 1232 1008 1327 800 2242 131 1308 1806 2088 152 654 829 1161 154 889 2218 528 2223 682 1850 319 1369 2086 664 1490 36 342 880 269 1734 160 1614 293 1155 1571 1330 1979 2308 194 1901 178 893 1643 808 320 1440 508 625 1588 1271 553 1984 1983 1652 222 2219 413 2070 1541 1572 1278 1265 524 1344 2165 699 762 55 1306 1133 1346 1689 1503 433 2302 1750 583 1273 1560 452 1789 885 1342 81 440 1892 610 1929 393 475 2301 1635 1433 801 152 654 829 1161 972 1293 1934 99 2223 682 1850 319 1085 2155 264 898 36 342 880 269 20 2147 1804 177 1155 1571 1330 1979 1796 1645 708 785 178 893 1643 1372 2050 1831 321 372 330 1664 1760 2026 1983 1652 222 633 2111 1151 153 244 2004 246 831 726 2165 699 762 873 1225 1192 1346 1689 1503 665 1533 1486 583 1273 1560 328 672 698 1489 1064 516 1356 1470 563 782 1851 1644 67 2290 2100 2089 1109 1740 154 889 2218 528 2223 682 1850 319 1056 1785 1657 807 370 2160 61 930 1734 160 1614 293 1155 1571 1330 1979 2303 2151 125 1718 2099 1669 1824 1422 1690 1045 302 1203 45 624 508 625 1588 467 2197 1715 446 1881 2273 2248 2311 1623 1541 1572 1278 196 1450 2114 55 1306 1133 1346 1689 1503 544 494 1879 1987 481 1021 1268 1204 1518 1263 1786 166 1342 81 440 1720 62 348 1964 299 935 1445 1905 2211 2027 777 2002 2223 682 1850 319 1085 2155 264 898 370 2160 61 930 1823 891 16 315 1155 1571 1330 1979 1796 1645 708 785 2099 1669 1824 1422 792 403 1856 816 1203 45 624 986 408 510 1664 1760 2026 911 1424 1516 2248 2311 1623 1455 1119 71 246 831 726 2237 1478 1427 1346 1689 1503 665 1533 1486 1987 481 1021 434 840 78 1263 1786 166 755 2201 804 1356 1470 563 2106 1320 953 2055 696 305 27 255 1906 1160 1296 1999 1369 2086 664 1490 36 342 880 269 1734 160 1614 293 1155 1571 1330 1979 1158 1599 922 1967 928 79 812 407 1402 859 855 1131 1611 1193 515 1634 1271 553 1984 1983 1652 222 2219 413 2070 1541 1572 1278 1355 639 8 1523 758 2174 2259 686 853 1742 1732 1277 1057 1812 207 1498 993 2244 29 1295 2203 322 1790 2156 392 2240 1164 1048 680 66 117 1166 1358 1411 1976 383 393 475 2301 1504 1958 2304 1079 1681 1065 36 342 880 269 20 2147 1804 177 1155 1571 1330 1979 1796 1645 708 785 928 79 812 407 828 907 514 1316 1611 1193 515 1634 535 1535 1121 555 1983 1652 222 633 2111 1151 153 244 2004 246 831 726 1523 758 2174 1801 1359 1452 1674 1815 134 2262 1954 719 1498 993 2244 456 1324 1871 322 1790 2156 1712 2224 1492 1048 680 66 1943 1862 1951 950 1257 490 488 1852 1245 67 2290 2100 1631 577 2038 1844 1078 675 1734 160 1614 293 1155 1571 1330 1979 2303 2151 125 1718 2099 1669 1824 1422 1402 859 855 1131 1611 1193 515 1634 1423 975 220 1148 657 4 1788 1244 446 1881 2273 2248 2311 1623 1541 1572 1278 196 1450 2114 2282 877 650 506 768 1947 1742 1732 1277 1691 810 42 29 1295 2203 322 1790 2156 1234 1829 927 1213 1398 870 296 2199 1438 772 1913 1495 1411 1976 383 1097 517 1381 1445 1905 2211 2260 1553 1653 745 428 720 1155 1571 1330 1979 1796 1645 708 785 2099 1669 1824 1422 792 403 1856 816 1611 1193 515 1634 535 1535 1121 555 657 4 1788 1244 1362 1388 1532 1866 2248 2311 1623 1455 1119 71 246 831 726 2237 1478 1427 506 768 1947 2230 326 1555 2262 1954 719 1729 959 717 322 1790 2156 1712 2224 1492 1213 1398 870 2238 1710 1752 772 1913 1495 495 260 1772 488 1852 1245 318 477 2006 27 255 1906 1413 2235 2287 2028 404 692 1651 660 1646 1616 1096 653 396 1767 960 1655 967 254 1255 1241 52 201 1566 905 1500 2178 2229 2082 1127 983 1952 2207 1135 722 1349 2134 1219 1704 276 1778 850 104 13 1182 1638 573 543 453 1702 498 1137 2168 2226 646 550 2284 1676 1251 1885 1138 406 1754 1662 858 1421 688 213 790 1513 364 982 87 2065 623 1072 179 10 2039 1118 32 1334 674 596 834 1036 301 1619 206 836 1180 556 575 2136 1993 766 1096 653 396 1767 1056 1785 1657 807 1255 1241 52 201 1916 1880 1013 417 2229 2082 1127 983 2303 2151 125 1718 1349 2134 1219 1704 1827 1258 1288 1188 104 13 1182 659 1496 1573 426 1773 842 1222 1300 1322 646 550 2284 379 1587 2117 1556 645 1874 1431 1240 1229 688 213 790 544 494 1879 87 2065 623 1887 21 1609 2039 1118 32 267 1172 1239 2258 784 2109 1417 221 1404 1802 1261 783 1139 1153 1515 656 1688 2092 960 1655 967 254 1255 1241 52 201 1837 316 313 1314 373 1639 1016 635 1952 2207 1135 722 1349 2134 1219 1704 2064 1762 1252 268 2222 142 1407 147 1053 1457 1907 2283 2208 1211 453 1702 498 841 1781 1542 1838 1769 181 769 1596 1352 1138 406 1754 82 1716 2187 1513 364 982 87 2065 623 65 649 1176 948 819 1341 1248 1254 138 2035 643 1382 834 1036 301 1307 175 678 775 1886 335 1819 711 617 1040 1149 2122 1255 1241 52 201 1916 1880 1013 417 373 1639 1016 635 1156 28 1538 1552 1349 2134 1219 1704 1827 1258 1288 1188 2222 142 1407 147 451 965 1559 971 2283 2208 1211 164 2294 984 1222 1300 1322 1536 227 1201 769 1596 1352 2188 102 2198 1431 1240 1229 385 136 1501 87 2065 623 1887 21 1609 948 819 1341 2212 1784 91 2035 643 1382 531 1253 1615 1417 221 1404 1446 2105 258 1738 1547 358 106 868 746 998 2276 2182 1566 905 1500 2178 2229 2082 1127 983 1952 2207 1135 722 1349 2134 1219 1704 458 1792 216 1336 135 760 1810 1953 1034 799 685 958 964 1791 1022 1152 1137 2168 2226 646 550 2284 1676 1251 1885 1138 406 1754 2030 912 172 658 2014 2005 2048 774 2190 1058 564 1708 2217 1897 2306 463 1600 2177 1250 652 2133 1088 981 262 778 275 1557 1207 1725 1370 2256 51 505 663 31 2251 1180 556 575 1628 2234 2068 466 661 1185 2229 2082 1127 983 2303 2151 125 1718 1349 2134 1219 1704 1827 1258 1288 1188 135 760 1810 1953 1423 975 220 1148 964 1791 1022 1152 1918 2278 199 1062 646 550 2284 379 1587 2117 1556 645 1874 1431 1240 1229 658 2014 2005 1136 519 1994 332 1703 1524 1605 811 1329 463 1600 2177 1234 1829 927 1088 981 262 1218 1578 1165 1207 1725 1370 1835 2209 2020 1102 1076 718 937 894 151 1139 1153 1515 2228 415 933 1377 2116 1514 1952 2207 1135 722 1349 2134 1219 1704 2064 1762 1252 268 2222 142 1407 147 1034 799 685 958 964 1791 1022 1152 1464 2291 619 1867 163 9 292 541 1838 1769 181 769 1596 1352 1138 406 1754 82 1716 2187 830 1003 2271 439 739 2091 1058 564 1708 146 1444 603 1250 652 2133 1088 981 262 2051 1313 1425 349 737 1408 533 1986 833 936 182 1625 663 31 2251 1830 2101 1038 1819 711 617 97 523 2214 158 1926 881 1349 2134 1219 1704 1827 1258 1288 1188 2222 142 1407 147 451 965 1559 971 964 1791 1022 1152 1918 2278 199 1062 163 9 292 541 282 502 1214 411 769 1596 1352 2188 102 2198 1431 1240 1229 385 136 1501 439 739 2091 1289 2202 2239 1605 811 1329 2024 1637 949 1088 981 262 1218 1578 1165 349 737 1408 133 1087 2071 936 182 1625 1094 354 2118 937 894 151 1648 1794 511 106 868 746 2139 1364 193 445 2299 2067 1056 1785 1657 807 370 2160 61 930 1916 1880 1013 417 1029 74 951 1033 2303 2151 125 1718 2099 1669 1824 1422 1827 1258 1288 1188 287 1955 1437 1301 659 1496 1573 350 2077 701 467 2197 1715 2169 1186 1403 379 1587 2117 538 978 409 196 1450 2114 1481 2145 2183 544 494 1879 1987 481 1021 1887 21 1609 683 522 1809 267 1172 1239 115 1101 1698 1720 62 348 1471 2040 1549 1735 159 1223 2297 344 832 286 1262 1701 370 2160 61 930 1823 891 16 315 1029 74 951 1033 734 1113 2011 614 2099 1669 1824 1422 792 403 1856 816 287 1955 1437 1301 530 1755 431 963 350 2077 701 1562 1580 666 911 1424 1516 1869 257 1569 538 978 409 1912 1780 805 2237 1478 1427 1006 626 1692 1987 481 1021 434 840 78 683 522 1809 1345 954 410 115 1101 1698 1233 189 1077 2106 1320 953 297 1483 2042 1584 58 733 709 631 455 1011 2307 195 1916 1880 1013 417 1029 74 951 1033 1156 28 1538 1552 1074 1546 1002 546 1827 1258 1288 1188 287 1955 1437 1301 451 965 1559 971 2268 1310 229 215 164 2294 984 1974 376 1454 2169 1186 1403 867 80 469 2188 102 2198 821 1749 627 1481 2145 2183 283 1070 2179 1887 21 1609 683 522 1809 2212 1784 91 1142 1722 460 531 1253 1615 2045 429 1985 1471 2040 1549 770 1973 1939 309 504 1175 1876 1430 780 1853 2135 1043 1029 74 951 1033 734 1113 2011 614 1074 1546 1002 546 2167 1991 2171 1903 287 1955 1437 1301 530 1755 431 963 2268 1310 229 215 1756 1046 1242 924 1974 376 1454 1226 118 472 1869 257 1569 1945 1649 1914 821 1749 627 1380 2072 395 1006 626 1692 363 503 613 683 522 1809 1345 954 410 1142 1722 460 827 704 128 2045 429 1985 851 1110 224 297 1483 2042 1282 2137 1269 307 1695 593 1744 866 290 1453 489 1978 2303 2151 125 1718 2099 1669 1824 1422 1827 1258 1288 1188 287 1955 1437 1301 1423 975 220 1148 657 4 1788 1244 1918 2278 199 1062 706 30 468 946 379 1587 2117 538 978 409 196 1450 2114 1481 2145 2183 1136 519 1994 2084 234 1803 1691 810 42 487 1636 551 1234 1829 927 1213 1398 870 1218 1578 1165 288 1633 145 1835 2209 2020 1177 430 591 1097 517 1381 212 979 2000 2297 344 832 1276 731 1099 266 989 961 2099 1669 1824 1422 792 403 1856 816 287 1955 1437 1301 530 1755 431 963 657 4 1788 1244 1362 1388 1532 1866 706 30 468 946 767 865 1782 1839 538 978 409 1912 1780 805 2237 1478 1427 1006 626 1692 2084 234 1803 493 754 114 1729 959 717 1873 1757 337 1213 1398 870 2238 1710 1752 288 1633 145 1841 786 205 1177 430 591 2210 1272 2075 318 477 2006 852 482 1063 709 631 455 908 677 1923 1946 644 1209 1827 1258 1288 1188 287 1955 1437 1301 451 965 1559 971 2268 1310 229 215 1918 2278 199 1062 706 30 468 946 282 502 1214 411 837 1920 1468 1583 2188 102 2198 821 1749 627 1481 2145 2183 283 1070 2179 1289 2202 2239 2206 1171 2180 487 1636 551 2194 454 732 1218 1578 1165 288 1633 145 133 1087 2071 1956 1814 1765 1094 354 2118 1925 113 150 212 979 2000 2141 540 2285 1876 1430 780 124 1777 1260 2115 944 980 287 1955 1437 1301 530 1755 431 963 2268 1310 229 215 1756 1046 1242 924 706 30 468 946 767 865 1782 1839 837 1920 1468 1583 1294 1727 2173 1197 821 1749 627 1380 2072 395 1006 626 1692 363 503 613 2206 1171 2180 346 1098 233 1873 1757 337 1687 728 127 288 1633 145 1841 786 205 1956 1814 1765 620 1385 507 1925 113 150 2104 2264 725 852 482 1063 1264 594 1287 1744 866 290 186 690 2270 560 1044 918 192 0 1363 1290 2127 1439 240 187 1579 1592 990 281 2241 818 1797 597 25 825 793 1236 1554 1179 1081 1996 892 1893 170 435 642 569 1174 388 210 2008 1122 902 1195 2052 1981 1460 1181 1084 1980 2054 1930 198 366 1807 915 168 148 1353 1992 585 405 863 844 1184 48 1758 723 888 567 273 2016 716 679 747 940 391 1927 2184 1915 261 2044 687 943 274 2289 1235 629 1622 900 1527 938 693 1617 1154 459 1259 509 1811 1332 2001 1357 561 1889 1888 1832 2096 761 1530 1529 1898 110 492 1620 1948 1105 1396 1206 253 1114 176 2069 1080 1627 1129 1340 1327 800 2242 1635 1433 801 2089 1109 1740 2027 777 2002 1160 1296 1999 1079 1681 1065 1844 1078 675 745 428 720 2028 404 692 2136 1993 766 656 1688 2092 1040 1149 2122 998 2276 2182 466 661 1185 1377 2116 1514 158 1926 881 445 2299 2067 286 1262 1701 1011 2307 195 1853 2135 1043 1453 489 1978 266 989 961 1946 644 1209 2115 944 980 560 1044 918 64 0 0 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120 123 126 129 132 135 138 141 144 147 150 153 156 159 162 165 168 171 174 177 180 183 186 189 0 0 0 13 1 0 -3 0 0 1500 0 0 2107 1941 2034 18446744073709551615 0 976 1035 1343 18446744073709551615 0 1041 1073 228 18446744073709551615 0 1462 525 93 18446744073709551615 0 919 1942 1808 18446744073709551615 0 1321 219 1577 18446744073709551615 0 211 670 1745 18446744073709551615 0 632 759 1711 18446744073709551615 0 817 846 848 18446744073709551615 0 2128 947 655 18446744073709551615 0 741 89 1683 18446744073709551615 0 1024 1415 333 18446744073709551615 0 2267 2193 1318 18446744073709551615 0 557 773 1067 18446744073709551615 0 280 1506 1143 18446744073709551615 0 2031 368 237 18446744073709551615 0 312 2162 149 18446744073709551615 0 1323 1746 1393 18446744073709551615 0 873 1225 1192 18446744073709551615 0 456 1324 1871 18446744073709551615 0 2215 1520 3 18446744073709551615 0 437 1995 2094 18446744073709551615 0 1412 343 1390 18446744073709551615 0 876 384 1602 18446744073709551615 0 2019 236 1474 18446744073709551615 0 105 862 294 18446744073709551615 0 65 649 1176 18446744073709551615 0 2051 1313 1425 18446744073709551615 0 69 17 1050 18446744073709551615 0 1597 1640 107 18446744073709551615 0 827 704 128 18446744073709551615 0 620 1385 507 18446744073709551615 0 835 1429 470 18446744073709551615 0 380 34 1351 18446744073709551615 0 2259 686 853 18446744073709551615 0 1674 1815 134 18446744073709551615 0 2232 1612 2157 18446744073709551615 0 554 478 1921 18446744073709551615 0 2030 912 172 18446744073709551615 0 830 1003 2271 18446744073709551615 0 1801 1359 1452 18446744073709551615 0 2230 326 1555 18446744073709551615 0 493 754 114 18446744073709551615 0 346 1098 233 18446744073709551615 0 146 1444 603 18446744073709551615 0 2024 1637 949 18446744073709551615 0 2194 454 732 18446744073709551615 0 1687 728 127 18446744073709551615 0 1093 1007 1299 18446744073709551615 0 1000 239 1479 18446744073709551615 0 808 320 1440 18446744073709551615 0 321 372 330 18446744073709551615 0 1525 2279 284 18446744073709551615 0 1949 1705 974 18446744073709551615 0 1265 524 1344 18446744073709551615 0 1057 1812 207 18446744073709551615 0 1878 2154 500 18446744073709551615 0 161 2076 1928 18446744073709551615 0 806 1922 1857 18446744073709551615 0 256 361 1124 18446744073709551615 0 387 1112 252 18446744073709551615 0 140 1737 702 18446744073709551615 0 606 1613 496 18446744073709551615 0 542 2032 608 18446744073709551615 0 109 2097 590 18446744073709551615 0 94 843 1604 18446744073709551615 0 1662 858 1421 18446744073709551615 0 2217 1897 2306 18446744073709551615 0 401 651 1896 18446744073709551615 0 2 899 513 18446744073709551615 0 276 1778 850 18446744073709551615 0 1053 1457 1907 18446744073709551615 0 386 231 1428 18446744073709551615 0 2261 1375 1116 18446744073709551615 0 434 840 78 18446744073709551615 0 2238 1710 1752 18446744073709551615 0 1372 2050 1831 18446744073709551615 0 986 408 510 18446744073709551615 0 1562 1580 666 18446744073709551615 0 1226 118 472 18446744073709551615 0 841 1781 1542 18446744073709551615 0 1536 227 1201 18446744073709551615 0 867 80 469 18446744073709551615 0 1945 1649 1914 18446744073709551615 0 1304 2295 1348 18446744073709551615 0 1132 883 1031 18446744073709551615 0 2212 1784 91 18446744073709551615 0 133 1087 2071 18446744073709551615 0 1355 639 8 18446744073709551615 0 2282 877 650 18446744073709551615 0 1136 519 1994 18446744073709551615 0 1289 2202 2239 18446744073709551615 0 2048 774 2190 18446744073709551615 0 332 1703 1524 18446744073709551615 0 1691 810 42 18446744073709551615 0 1729 959 717 18446744073709551615 0 544 494 1879 18446744073709551615 0 1234 1829 927 18446744073709551615 0 1198 1739 2129 18446744073709551615 0 2125 700 1202 18446744073709551615 0 467 2197 1715 18446744073709551615 0 911 1424 1516 18446744073709551615 0 1638 573 543 18446744073709551615 0 426 1773 842 18446744073709551615 0 659 1496 1573 18446744073709551615 0 164 2294 984 18446744073709551615 0 2308 194 1901 18446744073709551615 0 1690 1045 302 18446744073709551615 0 2017 225 529 18446744073709551615 0 2110 497 1997 18446744073709551615 0 879 18 2266 18446744073709551615 0 1654 2195 1339 18446744073709551615 0 838 586 2131 18446744073709551615 0 2057 1190 1208 18446744073709551615 0 1590 1969 1502 18446744073709551615 0 2170 33 1302 18446744073709551615 0 992 1052 917 18446744073709551615 0 1017 1405 1682 18446744073709551615 0 1570 412 925 18446744073709551615 0 351 794 999 18446744073709551615 0 2219 413 2070 18446744073709551615 0 153 244 2004 18446744073709551615 0 2165 699 762 18446744073709551615 0 1498 993 2244 18446744073709551615 0 1400 1988 271 18446744073709551615 0 56 1667 2216 18446744073709551615 0 1285 1383 607 18446744073709551615 0 641 856 1037 18446744073709551615 0 1387 909 527 18446744073709551615 0 183 2231 1326 18446744073709551615 0 595 906 826 18446744073709551615 0 2146 1123 1095 18446744073709551615 0 1061 1723 1027 18446744073709551615 0 574 1847 484 18446744073709551615 0 920 314 208 18446744073709551615 0 436 2059 2305 18446744073709551615 0 323 242 1686 18446744073709551615 0 2095 501 76 18446744073709551615 0 750 814 884 18446744073709551615 0 352 1526 874 18446744073709551615 0 2093 1291 1719 18446744073709551615 0 1331 914 743 18446744073709551615 0 2063 1863 356 18446744073709551615 0 1212 1761 532 18446744073709551615 0 1010 1447 749 18446744073709551615 0 399 1751 2102 18446744073709551615 0 582 1274 1168 18446744073709551615 0 2012 2090 75 18446744073709551615 0 141 1816 2119 18446744073709551615 0 1183 345 2053 18446744073709551615 0 90 1726 1117 18446744073709551615 0 1298 1883 1312 18446744073709551615 0 1513 364 982 18446744073709551615 0 1250 652 2133 18446744073709551615 0 1137 2168 2226 18446744073709551615 0 1838 1769 181 18446744073709551615 0 457 2221 1220 18446744073709551615 0 1019 1162 2140 18446744073709551615 0 59 1458 727 18446744073709551615 0 970 1448 2081 18446744073709551615 0 1606 1435 41 18446744073709551615 0 23 1111 875 18446744073709551615 0 1284 108 1465 18446744073709551615 0 742 1589 1575 18446744073709551615 0 665 1533 1486 18446744073709551615 0 1712 2224 1492 18446744073709551615 0 633 2111 1151 18446744073709551615 0 1455 1119 71 18446744073709551615 0 1345 954 410 18446744073709551615 0 1841 786 205 18446744073709551615 0 1912 1780 805 18446744073709551615 0 1380 2072 395 18446744073709551615 0 73 1736 2142 18446744073709551615 0 1508 520 1890 18446744073709551615 0 235 355 1335 18446744073709551615 0 2189 1128 1884 18446744073709551615 0 82 1716 2187 18446744073709551615 0 385 136 1501 18446744073709551615 0 948 819 1341 18446744073709551615 0 349 737 1408 18446744073709551615 0 1328 414 2078 18446744073709551615 0 26 558 1230 18446744073709551615 0 895 1030 647 18446744073709551615 0 1237 1779 357 18446744073709551615 0 283 1070 2179 18446744073709551615 0 363 503 613 18446744073709551615 0 1142 1722 460 18446744073709551615 0 1956 1814 1765 18446744073709551615 0 2023 882 1397 18446744073709551615 0 977 1434 378 18446744073709551615 0 2300 1961 1410 18446744073709551615 0 1656 1972 360 18446744073709551615 0 1523 758 2174 18446744073709551615 0 506 768 1947 18446744073709551615 0 1742 1732 1277 18446744073709551615 0 2262 1954 719 18446744073709551615 0 658 2014 2005 18446744073709551615 0 439 739 2091 18446744073709551615 0 1058 564 1708 18446744073709551615 0 1605 811 1329 18446744073709551615 0 2084 234 1803 18446744073709551615 0 2206 1171 2180 18446744073709551615 0 487 1636 551 18446744073709551615 0 1873 1757 337 18446744073709551615 0 350 2077 701 18446744073709551615 0 1974 376 1454 18446744073709551615 0 2169 1186 1403 18446744073709551615 0 1869 257 1569 18446744073709551615 0 104 13 1182 18446744073709551615 0 2283 2208 1211 18446744073709551615 0 453 1702 498 18446744073709551615 0 1222 1300 1322 18446744073709551615 0 178 893 1643 18446744073709551615 0 1203 45 624 18446744073709551615 0 508 625 1588 18446744073709551615 0 1664 1760 2026 18446744073709551615 0 1944 1456 932 18446744073709551615 0 1937 1228 576 18446744073709551615 0 1279 886 1004 18446744073709551615 0 2293 802 929 18446744073709551615 0 196 1450 2114 18446744073709551615 0 2237 1478 1427 18446744073709551615 0 1987 481 1021 18446744073709551615 0 1213 1398 870 18446744073709551615 0 1338 218 1432 18446744073709551615 0 250 602 444 18446744073709551615 0 1360 823 2037 18446744073709551615 0 1677 442 578 18446744073709551615 0 1676 1251 1885 18446744073709551615 0 1556 645 1874 18446744073709551615 0 688 213 790 18446744073709551615 0 463 1600 2177 18446744073709551615 0 945 2175 1167 18446744073709551615 0 2245 2253 1864 18446744073709551615 0 190 1828 1895 18446744073709551615 0 2033 1485 756 18446744073709551615 0 1887 21 1609 18446744073709551615 0 1218 1578 1165 18446744073709551615 0 379 1587 2117 18446744073709551615 0 2188 102 2198 18446744073709551615 0 55 1306 1133 18446744073709551615 0 29 1295 2203 18446744073709551615 0 1271 553 1984 18446744073709551615 0 446 1881 2273 18446744073709551615 0 1859 2152 1047 18446744073709551615 0 1521 604 571 18446744073709551615 0 1586 132 2073 18446744073709551615 0 1673 2161 2277 18446744073709551615 0 1965 713 797 18446744073709551615 0 1009 636 1882 18446744073709551615 0 1406 1200 1593 18446744073709551615 0 402 1714 763 18446744073709551615 0 288 1633 145 18446744073709551615 0 683 522 1809 18446744073709551615 0 1006 626 1692 18446744073709551615 0 1481 2145 2183 18446744073709551615 0 821 1749 627 18446744073709551615 0 538 978 409 18446744073709551615 0 1088 981 262 18446744073709551615 0 87 2065 623 18446744073709551615 0 1431 1240 1229 18446744073709551615 0 1138 406 1754 18446744073709551615 0 769 1596 1352 18446744073709551615 0 646 550 2284 18446744073709551615 0 322 1790 2156 18446744073709551615 0 1346 1689 1503 18446744073709551615 0 246 831 726 18446744073709551615 0 1541 1572 1278 18446744073709551615 0 2248 2311 1623 18446744073709551615 0 1983 1652 222 18446744073709551615 0 587 63 2246 18446744073709551615 0 662 1325 491 18446744073709551615 0 897 2018 1709 18446744073709551615 0 695 1982 1713 18446744073709551615 0 601 263 1145 18446744073709551615 0 1678 2047 2009 18446744073709551615 0 1621 277 1215 18446744073709551615 0 1858 1494 112 18446744073709551615 0 144 744 1601 18446744073709551615 0 1931 1764 1938 18446744073709551615 0 534 2113 19 18446744073709551615 0 878 2288 137 18446744073709551615 0 2164 2192 1730 18446744073709551615 0 2185 771 985 18446744073709551615 0 738 1082 374 18446744073709551615 0 6 966 1333 18446744073709551615 0 230 270 2056 18446744073709551615 0 1221 887 2025 18446744073709551615 0 2150 1366 566 18446744073709551615 0 432 259 1392 18446744073709551615 0 1685 171 703 18446744073709551615 0 427 2249 1103 18446744073709551615 0 752 1834 367 18446744073709551615 0 185 35 1868 18446744073709551615 0 1231 1821 599 18446744073709551615 0 1199 1039 988 18446744073709551615 0 1140 1904 1266 18446744073709551615 0 637 1068 1305 18446744073709551615 0 382 1679 1607 18446744073709551615 0 22 1089 640 18446744073709551615 366 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160 165 170 175 180 185 190 195 200 205 210 215 220 225 230 235 240 245 250 255 260 265 270 275 280 285 290 295 300 305 310 315 320 325 330 335 340 345 350 355 360 365 370 375 380 385 390 395 400 405 410 415 420 425 430 435 440 445 450 455 460 465 470 475 480 485 490 495 500 505 510 515 520 525 530 535 540 545 550 555 560 565 570 575 580 585 590 595 600 605 610 615 620 625 630 635 640 645 650 655 660 665 670 675 680 685 690 695 700 705 710 715 720 725 730 735 740 745 750 755 760 765 770 775 780 785 790 795 800 805 810 815 820 825 830 835 840 845 850 855 860 865 870 875 880 885 890 895 900 905 910 915 920 925 930 935 940 945 950 955 960 965 970 975 980 985 990 995 1000 1005 1010 1015 1020 1025 1030 1035 1040 1045 1050 1055 1060 1065 1070 1075 1080 1085 1090 1095 1100 1105 1110 1115 1120 1125 1130 1135 1140 1145 1150 1155 1160 1165 1170 1175 1180 1185 1190 1195 1200 1205 1210 1215 1220 1225 1230 1235 1240 1245 1250 1255 1260 1265 1270 1275 1280 1285 1290 1295 1300 1305 1310 1315 1320 1325 1330 1335 1340 1345 1350 1355 1360 1365 1370 1375 1380 1385 1390 1395 1400 1405 1410 1415 1420 1425 1430 1435 1440 1445 1450 1455 1460 1465 1470 1475 1480 1485 1490 1495 0 0 1200 0 0 371 996 1919 18446744073709551615 0 1384 1966 537 18446744073709551615 0 1545 803 1409 18446744073709551615 0 310 518 1487 18446744073709551615 0 341 1591 447 18446744073709551615 0 1120 1418 1510 18446744073709551615 0 1680 849 1416 18446744073709551615 0 1642 2124 1368 18446744073709551615 0 1940 1748 441 18446744073709551615 0 1787 1497 2103 18446744073709551615 0 1595 1647 1694 18446744073709551615 0 740 1770 1910 18446744073709551615 0 1753 1347 247 18446744073709551615 0 1466 584 167 18446744073709551615 0 668 916 1477 18446744073709551615 0 1908 476 1028 18446744073709551615 0 1354 499 973 18446744073709551615 0 2275 1861 1169 18446744073709551615 0 243 375 1759 18446744073709551615 0 223 1350 2200 18446744073709551615 0 565 1484 1292 18446744073709551615 0 2015 143 2309 18446744073709551615 0 589 1090 757 18446744073709551615 0 2121 1911 1825 18446744073709551615 0 390 1210 2274 18446744073709551615 0 174 397 418 18446744073709551615 0 450 203 1783 18446744073709551615 0 214 1670 1899 18446744073709551615 0 730 579 304 18446744073709551615 0 1026 2176 1776 18446744073709551615 0 251 736 400 18446744073709551615 0 1216 1309 2049 18446744073709551615 0 486 2021 64 18446744073709551615 0 798 1066 857 18446744073709551615 0 549 169 2233 18446744073709551615 0 1671 200 1594 18446744073709551615 0 1475 2074 753 18446744073709551615 0 1775 861 68 18446744073709551615 0 1509 1963 2007 18446744073709551615 0 1877 1539 188 18446744073709551615 0 1707 2250 2041 18446744073709551615 0 1507 1936 2196 18446744073709551615 0 615 1959 1658 18446744073709551615 0 1270 934 249 18446744073709551615 0 238 44 334 18446744073709551615 0 421 839 1548 18446744073709551615 0 1865 2058 1224 18446744073709551615 0 748 155 1731 18446744073709551615 0 289 1482 57 18446744073709551615 0 1379 423 1845 18446744073709551615 0 2310 217 1286 18446744073709551615 0 126 1001 1488 18446744073709551615 0 1836 377 1319 18446744073709551615 0 1227 871 1191 18446744073709551615 0 1275 1843 1246 18446744073709551615 0 1565 100 1576 18446744073709551615 0 2236 1568 1900 18446744073709551615 0 1892 610 1929 18446744073709551615 0 1015 1315 667 18446744073709551615 0 1672 1049 120 18446744073709551615 0 598 1023 1544 18446744073709551615 0 782 1851 1644 18446744073709551615 0 1459 1970 2036 18446744073709551615 0 40 317 1626 18446744073709551615 0 1964 299 935 18446744073709551615 0 1281 1894 676 18446744073709551615 0 2003 327 483 18446744073709551615 0 2055 696 305 18446744073709551615 0 422 600 353 18446744073709551615 0 2043 611 37 18446744073709551615 0 1522 1517 2265 18446744073709551615 0 394 1147 1933 18446744073709551615 0 1977 2181 1564 18446744073709551615 0 1054 103 1935 18446744073709551615 0 1194 1661 648 18446744073709551615 0 1189 1283 15 18446744073709551615 0 54 2126 1051 18446744073709551615 0 669 1650 1875 18446744073709551615 0 389 70 1957 18446744073709551615 0 939 2144 12 18446744073709551615 0 5 84 248 18446744073709551615 0 1960 1581 1563 18446744073709551615 0 116 60 1706 18446744073709551615 0 545 547 1141 18446744073709551615 0 245 1395 204 18446744073709551615 0 2191 47 278 18446744073709551615 0 2130 781 1854 18446744073709551615 0 956 592 612 18446744073709551615 0 1558 2085 735 18446744073709551615 0 1619 206 836 18446744073709551615 0 1582 1660 279 18446744073709551615 0 1512 197 605 18446744073709551615 0 1802 1261 783 18446744073709551615 0 1157 1125 1793 18446744073709551615 0 473 2060 1020 18446744073709551615 0 1376 438 1989 18446744073709551615 0 775 1886 335 18446744073709551615 0 1822 1055 890 18446744073709551615 0 1163 1374 295 18446744073709551615 0 1738 1547 358 18446744073709551615 0 461 962 2227 18446744073709551615 0 272 1659 796 18446744073709551615 0 1820 1872 416 18446744073709551615 0 638 822 419 18446744073709551615 0 1632 2247 1550 18446744073709551615 0 2079 77 1962 18446744073709551615 0 1826 1150 691 18446744073709551615 0 1025 2138 1968 18446744073709551615 0 232 923 904 18446744073709551615 0 2159 2220 83 18446744073709551615 0 2281 622 1747 18446744073709551615 0 707 621 1159 18446744073709551615 0 1365 1693 1950 18446744073709551615 0 1371 1399 1840 18446744073709551615 0 1848 72 581 18446744073709551615 0 2148 712 847 18446744073709551615 0 173 787 1069 18446744073709551615 0 192 2296 1092 18446744073709551615 0 1735 159 1223 18446744073709551615 0 588 398 425 18446744073709551615 0 465 1196 1394 18446744073709551615 0 1584 58 733 18446744073709551615 0 1442 2172 1998 18446744073709551615 0 1902 1833 2257 18446744073709551615 0 309 504 1175 18446744073709551615 0 1367 684 1107 18446744073709551615 0 2252 671 942 18446744073709551615 0 307 1695 593 18446744073709551615 0 568 123 697 18446744073709551615 0 1461 2186 1012 18446744073709551615 0 1818 539 572 18446744073709551615 0 1733 1493 2158 18446744073709551615 0 1909 559 157 18446744073709551615 0 433 2302 1750 18446744073709551615 0 92 1317 1361 18446744073709551615 0 46 1855 480 18446744073709551615 0 420 689 630 18446744073709551615 0 845 1971 121 18446744073709551615 0 1585 1629 1528 18446744073709551615 0 1334 674 596 18446744073709551615 0 779 38 957 18446744073709551615 0 1268 1204 1518 18446744073709551615 0 2258 784 2109 18446744073709551615 0 1071 331 1386 18446744073709551615 0 1800 2029 521 18446744073709551615 0 714 864 2112 18446744073709551615 0 913 2286 729 18446744073709551615 0 2225 1505 710 18446744073709551615 0 241 681 1463 18446744073709551615 0 392 2240 1164 18446744073709551615 0 1419 1436 49 18446744073709551615 0 365 1443 1378 18446744073709551615 0 1618 359 1480 18446744073709551615 0 303 381 2166 18446744073709551615 0 449 1146 474 18446744073709551615 0 2256 51 505 18446744073709551615 0 1624 609 969 18446744073709551615 0 296 2199 1438 18446744073709551615 0 1102 1076 718 18446744073709551615 0 1170 1232 1008 18446744073709551615 0 583 1273 1560 18446744073709551615 0 452 1789 885 18446744073709551615 0 1342 81 440 18446744073709551615 0 393 475 2301 18446744073709551615 0 328 672 698 18446744073709551615 0 1489 1064 516 18446744073709551615 0 1356 1470 563 18446744073709551615 0 67 2290 2100 18446744073709551615 0 1263 1786 166 18446744073709551615 0 1720 62 348 18446744073709551615 0 1445 1905 2211 18446744073709551615 0 755 2201 804 18446744073709551615 0 2106 1320 953 18446744073709551615 0 27 255 1906 18446744073709551615 0 1048 680 66 18446744073709551615 0 117 1166 1358 18446744073709551615 0 1411 1976 383 18446744073709551615 0 1504 1958 2304 18446744073709551615 0 1943 1862 1951 18446744073709551615 0 950 1257 490 18446744073709551615 0 488 1852 1245 18446744073709551615 0 1631 577 2038 18446744073709551615 0 772 1913 1495 18446744073709551615 0 1097 517 1381 18446744073709551615 0 2260 1553 1653 18446744073709551615 0 495 260 1772 18446744073709551615 0 318 477 2006 18446744073709551615 0 1413 2235 2287 18446744073709551615 0 1072 179 10 18446744073709551615 0 2039 1118 32 18446744073709551615 0 834 1036 301 18446744073709551615 0 1180 556 575 18446744073709551615 0 267 1172 1239 18446744073709551615 0 1417 221 1404 18446744073709551615 0 1139 1153 1515 18446744073709551615 0 1248 1254 138 18446744073709551615 0 2035 643 1382 18446744073709551615 0 1307 175 678 18446744073709551615 0 1819 711 617 18446744073709551615 0 531 1253 1615 18446744073709551615 0 1446 2105 258 18446744073709551615 0 106 868 746 18446744073709551615 0 778 275 1557 18446744073709551615 0 1207 1725 1370 18446744073709551615 0 663 31 2251 18446744073709551615 0 1628 2234 2068 18446744073709551615 0 1835 2209 2020 18446744073709551615 0 937 894 151 18446744073709551615 0 2228 415 933 18446744073709551615 0 533 1986 833 18446744073709551615 0 936 182 1625 18446744073709551615 0 1830 2101 1038 18446744073709551615 0 97 523 2214 18446744073709551615 0 1094 354 2118 18446744073709551615 0 1648 1794 511 18446744073709551615 0 2139 1364 193 18446744073709551615 0 115 1101 1698 18446744073709551615 0 1471 2040 1549 18446744073709551615 0 2297 344 832 18446744073709551615 0 1233 189 1077 18446744073709551615 0 297 1483 2042 18446744073709551615 0 709 631 455 18446744073709551615 0 2045 429 1985 18446744073709551615 0 770 1973 1939 18446744073709551615 0 1876 1430 780 18446744073709551615 0 851 1110 224 18446744073709551615 0 1282 2137 1269 18446744073709551615 0 1744 866 290 18446744073709551615 0 1177 430 591 18446744073709551615 0 212 979 2000 18446744073709551615 0 1276 731 1099 18446744073709551615 0 2210 1272 2075 18446744073709551615 0 852 482 1063 18446744073709551615 0 908 677 1923 18446744073709551615 0 1925 113 150 18446744073709551615 0 2141 540 2285 18446744073709551615 0 124 1777 1260 18446744073709551615 0 2104 2264 725 18446744073709551615 0 1264 594 1287 18446744073709551615 0 186 690 2270 18446744073709551615 282 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 10 110 35 130 650 730 670 750 185 275 210 295 805 875 825 895 20 45 70 90 195 220 240 260 355 375 400 420 510 530 550 570 0 55 100 145 340 385 430 465 640 685 720 765 940 975 1010 1045 205 250 290 325 520 560 595 625 820 855 890 925 1095 1125 1155 1185 395 475 415 490 985 1055 1000 1070 545 615 565 630 1115 1175 1130 1190 740 760 780 795 885 905 920 935 1025 1040 1060 1075 1150 1165 1180 1195 590 605 620 635 445 460 480 495 285 305 320 335 120 140 160 175 845 915 860 930 235 315 255 330 695 775 710 790 65 155 85 170 960 995 1030 1065 665 705 745 785 365 410 450 485 30 80 125 165 1135 1120 1105 1090 1160 1100 1145 1085 1170 1140 1110 1080 1005 990 970 955 1035 965 1020 950 1050 1015 980 945 865 850 835 815 900 830 880 810 910 870 840 800 715 700 680 660 755 675 735 655 770 725 690 645 575 555 535 515 600 525 585 505 610 580 540 500 425 405 380 360 455 370 440 350 470 435 390 345 265 245 225 200 300 215 280 190 310 270 230 180 95 75 50 25 135 40 115 15 150 105 60 5 73 23 Policy::Sequential<3,3> +DEAL::0 0 785 0 1 1217 903 1574 88 18446744073709551615 0 1892 610 1929 1981 18446744073709551615 0 635 2463 1457 2441 18446744073709551615 0 741 89 1683 1590 18446744073709551615 0 1979 1983 1652 222 18446744073709551615 0 1716 2321 65 649 18446744073709551615 0 946 2084 234 1803 18446744073709551615 0 355 1538 2443 1283 18446744073709551615 0 167 668 916 1477 18446744073709551615 0 1484 1292 2015 143 18446744073709551615 0 892 1893 336 311 18446744073709551615 0 1075 2149 180 1018 18446744073709551615 0 1859 2320 1047 1054 18446744073709551615 0 987 1060 265 325 18446744073709551615 0 2220 83 2281 622 18446744073709551615 0 1556 645 1874 544 18446744073709551615 0 1064 516 2422 1470 18446744073709551615 0 1856 816 1455 1119 18446744073709551615 0 2391 1708 1250 652 18446744073709551615 0 852 482 1063 908 18446744073709551615 0 2062 1717 789 705 18446744073709551615 0 1604 2033 1485 756 18446744073709551615 0 1658 1270 2428 249 18446744073709551615 0 1957 939 2144 12 18446744073709551615 0 1399 1840 1848 72 18446744073709551615 0 2446 1277 1498 2392 18446744073709551615 0 1224 2363 155 1731 18446744073709551615 0 1347 247 1466 584 1 1347 247 1466 584 18446744073709551615 0 2032 608 970 1448 18446744073709551615 0 1231 1821 599 565 1 1231 1821 599 565 18446744073709551615 0 1995 2094 1673 2161 18446744073709551615 0 1671 200 1594 1996 1 1671 200 1594 1996 18446744073709551615 0 1144 1032 1449 226 18446744073709551615 0 1460 2447 972 1293 18446744073709551615 0 1002 546 1974 376 18446744073709551615 0 1934 2330 1085 2155 18446744073709551615 0 1788 1244 506 768 18446744073709551615 0 2283 2208 1211 841 18446744073709551615 0 1107 2252 671 942 18446744073709551615 0 1781 1542 105 862 18446744073709551615 0 1214 411 1289 2202 18446744073709551615 0 1969 1502 141 2466 18446744073709551615 0 2384 1164 803 575 18446744073709551615 0 2219 413 2070 1541 18446744073709551615 0 1288 1188 379 1587 18446744073709551615 0 1572 1278 2165 2334 18446744073709551615 0 1077 297 1483 2042 18446744073709551615 0 1176 948 819 1341 18446744073709551615 0 1693 32 2299 707 18446744073709551615 0 487 1636 551 288 18446744073709551615 0 934 2212 1087 356 18446744073709551615 0 628 2263 2352 1420 18446744073709551615 0 422 600 353 2043 18446744073709551615 0 1603 552 161 2076 18446744073709551615 0 1131 1355 639 8 18446744073709551615 0 1592 2433 1598 896 18446744073709551615 0 1619 206 836 567 18446744073709551615 0 2309 589 1090 757 18446744073709551615 0 1970 2036 2322 317 18446744073709551615 0 1210 2274 2455 597 18446744073709551615 0 1953 554 478 1921 18446744073709551615 0 2243 443 1389 1472 18446744073709551615 0 209 1373 1467 1561 18446744073709551615 0 184 308 1243 1813 18446744073709551615 0 406 1754 1513 364 18446744073709551615 0 103 1935 1194 1661 18446744073709551615 0 689 630 1530 1529 18446744073709551615 0 1747 2402 621 1159 18446744073709551615 0 688 213 790 2395 18446744073709551615 0 2390 96 323 242 18446744073709551615 0 1698 1471 2040 1549 18446744073709551615 0 563 67 2290 2100 18446744073709551615 0 924 1380 2072 395 18446744073709551615 0 71 2237 1478 1427 18446744073709551615 0 1615 1446 2105 258 18446744073709551615 0 332 1703 1524 1234 18446744073709551615 0 1026 2176 1776 251 18446744073709551615 0 1847 484 2215 1520 18446744073709551615 0 238 44 334 421 18446744073709551615 0 1870 14 926 1014 18446744073709551615 0 130 765 1115 2272 18446744073709551615 0 1924 2360 869 24 1 1924 2360 869 24 18446744073709551615 0 580 39 2254 1846 18446744073709551615 0 386 231 1428 2310 18446744073709551615 0 514 1316 535 1535 18446744073709551615 0 1908 476 1028 1579 1 1908 476 1028 1579 18446744073709551615 0 2081 2379 602 444 18446744073709551615 0 2277 1508 520 1890 18446744073709551615 0 787 1069 192 2296 18446744073709551615 0 2121 1911 1825 390 1 2121 1911 1825 390 18446744073709551615 0 1304 2295 1348 116 18446744073709551615 0 129 2418 1612 2157 18446744073709551615 0 199 1062 1136 519 18446744073709551615 0 264 898 1372 2050 18446744073709551615 0 1454 867 80 469 18446744073709551615 0 1947 2469 810 42 18446744073709551615 0 1264 594 1287 186 18446744073709551615 0 294 2189 1128 1884 18446744073709551615 0 2239 2024 1637 949 18446744073709551615 0 2325 1695 593 561 18446744073709551615 0 1818 684 99 1147 18446744073709551615 0 762 2343 1689 1503 18446744073709551615 0 2117 1431 1240 1229 18446744073709551615 0 709 631 455 1011 18446744073709551615 0 2052 250 60 1445 18446744073709551615 0 1271 553 1984 2057 18446744073709551615 0 1610 2409 280 1506 18446744073709551615 0 2440 37 2312 2372 18446744073709551615 0 991 854 872 694 18446744073709551615 0 1772 318 477 2006 18446744073709551615 0 1626 1964 2344 935 18446744073709551615 0 977 1434 378 2048 18446744073709551615 0 25 131 1308 1806 18446744073709551615 0 1444 603 2051 1313 18446744073709551615 0 380 34 1351 1656 18446744073709551615 0 273 2016 1916 1880 18446744073709551615 0 402 1714 763 2245 18446744073709551615 0 1928 140 1737 702 1 1928 140 1737 702 18446744073709551615 0 217 1286 126 1001 18446744073709551615 0 2380 1706 545 547 18446744073709551615 0 1092 1735 2401 1223 18446744073709551615 0 2023 882 1397 835 18446744073709551615 0 1121 555 1801 2468 18446744073709551615 0 1994 1605 811 1329 18446744073709551615 0 2141 2327 2285 124 18446744073709551615 125 0 0 6 12 18 24 30 36 42 48 54 60 66 72 78 84 90 96 102 108 114 120 126 132 138 144 150 156 162 173 179 190 196 207 213 219 225 231 237 243 249 255 261 267 273 279 285 291 297 303 309 315 321 327 333 339 345 351 357 363 369 375 381 387 393 399 405 411 417 423 429 435 441 447 453 459 465 471 477 483 489 495 501 512 518 524 530 541 547 553 559 570 576 582 588 594 600 606 612 618 624 630 636 642 648 654 660 666 672 678 684 690 696 702 708 714 720 726 732 743 749 755 761 767 773 779 0 0 2478 2478 0 0 0 0 1 0 0 0 0 2478 0 1 2478 0 1 0 2478 0 0 1 0 1 0 0 2478 0 1 2478 0 0 0 0 0 3 0 0 10 1 0 +0 1 0 0 1 0 4294967295 0 0 0 0 1 0 4294967295 1 0 1 0 10 +1 8 0 0 0 0 0 0 0 0 0 8 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 0 0 0 8 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 8 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 10 +2 64 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 219 308 397 486 575 664 753 842 931 1020 1109 1198 1287 1376 1465 1554 1643 1732 1821 1910 1999 2088 2177 2266 2355 2444 2533 2622 2711 2800 2889 2978 3067 3156 3245 3334 3423 3512 3601 3690 3779 3868 3957 4046 4135 4224 4313 4402 4491 4580 4669 4758 4847 4936 5025 5114 5203 5292 5381 5470 5559 5648 5737 5826 0 1217 903 1574 88 1347 247 1466 584 1231 1821 599 565 1908 476 1028 1579 1671 200 1594 1996 1924 2360 869 24 2121 1911 1825 390 1928 140 1737 702 86 347 1134 424 1990 2346 1666 994 7 1743 2280 1543 1668 791 2132 1491 339 2205 291 721 191 968 119 815 101 1766 1256 329 919 1942 1808 1400 1988 271 2107 1941 2034 1285 1383 607 2063 1863 2431 22 1089 2436 2017 225 529 637 1068 1305 817 846 848 879 18 2266 2093 1291 1719 2410 1039 988 371 996 1919 1384 1966 537 1545 2355 1409 310 518 1487 341 1591 447 1120 1418 1510 1363 1290 2127 2120 751 715 2066 1511 2213 724 1567 165 1178 2255 285 122 2413 860 1249 1878 2154 500 976 1035 1343 641 2373 2416 1406 1200 2465 2110 497 1997 1140 1904 1266 1525 2279 284 1965 713 797 1680 849 1416 1642 2124 1368 1940 1748 441 1787 1497 2103 1595 1647 1694 1439 240 187 1059 340 156 298 570 1630 1675 1774 634 536 548 776 1297 1741 1187 1083 1321 219 1577 56 1667 2216 387 1112 252 1212 1761 532 382 1679 1607 945 2175 1167 109 2097 590 190 1828 1895 740 1770 1910 1753 1347 247 1466 584 167 668 916 1477 1908 476 1028 1579 1592 2433 1598 896 1924 2360 869 24 1603 552 161 2076 1928 140 1737 702 402 1714 763 2245 2253 1864 1198 1739 2129 1354 499 973 2459 1861 1169 243 375 1759 223 1350 2200 281 2241 818 2382 2046 43 1303 300 795 2340 1763 673 2476 941 369 1451 1441 1100 162 401 651 1896 1944 1456 932 1093 1007 1299 1279 886 1004 2128 947 655 1654 2195 1339 1331 914 743 1231 1821 599 565 1908 476 1028 1579 1484 1292 2015 143 2309 589 1090 757 2121 1911 1825 390 1928 140 1737 702 1210 2274 2455 597 25 131 1308 1806 2400 154 889 2218 2448 2308 194 1901 1000 239 1479 2293 802 929 1949 1705 974 1009 636 1882 2348 2338 418 450 203 2389 214 941 369 1451 2393 1899 730 579 304 825 793 1236 1651 660 1646 1616 1096 653 396 1767 2 899 513 1937 1228 576 1638 573 543 94 843 1908 476 1028 1579 1592 2433 1598 896 2309 589 1090 757 1604 2033 1485 756 1928 140 1737 702 402 1714 763 2245 25 131 1308 1806 1026 2176 1776 251 2218 2448 2308 736 400 1216 1861 1169 243 1309 2332 486 1705 974 1009 2021 2451 1554 2046 43 1303 1179 1081 1056 941 369 1451 1441 1100 162 579 304 825 1785 1657 807 660 1646 1616 1690 1045 302 1279 886 1004 426 1773 842 2125 700 1202 798 1066 857 549 169 2233 1671 200 1594 1996 1924 2360 869 24 2121 1911 1825 390 1928 140 1737 702 892 1893 336 311 628 2263 2352 1420 2243 443 1389 1472 991 854 872 694 1540 362 1387 375 1759 223 909 527 1041 636 1882 2348 1073 228 2314 906 826 185 35 1868 2374 1052 917 427 2249 1103 1570 412 925 432 259 1392 1475 2074 753 1775 861 68 1509 1963 2007 1877 2336 188 1707 2250 2041 2417 435 642 11 1499 2123 1391 1684 1805 139 1924 2360 869 24 1603 552 161 2076 1928 140 1737 702 402 1714 763 2245 628 2263 2352 1420 2062 1717 789 705 991 854 872 694 130 765 1115 2272 375 1759 223 1350 2200 281 2241 818 2382 2046 43 1303 906 826 185 2087 2267 2193 1318 1462 525 93 2146 1123 412 925 432 1095 59 1458 2074 753 1775 2426 1017 1405 1963 2007 1877 1682 1685 171 703 312 2162 149 457 2221 1654 2195 1339 1220 1507 1936 2196 615 1959 2121 1911 1825 390 1928 140 1737 702 1210 2274 2455 597 25 131 1308 1806 2243 443 1389 1472 991 854 872 694 1658 1270 2428 249 238 44 334 421 802 929 1949 1705 974 1009 636 1882 2348 2338 418 450 839 1548 569 1174 388 2083 1052 917 427 1537 788 1476 259 1392 1475 2074 753 1775 955 1126 1534 2153 183 2231 1326 606 1613 496 752 1834 2250 2041 2417 367 1338 218 576 1638 573 1432 1360 823 2037 1865 2058 1928 140 1737 702 402 1714 763 2245 25 131 1308 1806 1026 2176 1776 251 991 854 872 694 130 765 1115 2272 238 44 334 421 1224 2363 155 1731 1705 974 1009 2021 2451 1554 2046 43 1303 1179 1081 1056 1174 388 2083 289 1482 57 93 2146 1123 1379 423 1845 2074 753 1775 2426 1017 1405 2153 183 2231 210 2008 1122 496 752 1834 1696 1337 1108 149 457 2221 2108 1771 1932 798 1066 857 1795 809 2439 773 1067 542 167 668 916 1477 2032 608 970 1448 1592 2433 1598 896 2081 2379 602 444 1603 552 161 2076 386 231 1428 2310 402 1714 763 2245 217 1286 126 1001 1739 2129 1354 1488 1836 377 1319 1227 871 1191 902 1195 1350 2200 281 2378 152 654 829 1161 2223 682 1850 319 1763 673 2476 178 893 2386 1441 1100 162 808 320 1440 1944 1456 932 508 625 1588 351 794 999 2150 1366 566 1275 1843 1246 1565 100 1576 2236 1568 1900 2032 608 970 1448 1892 610 1929 1981 2081 2379 602 444 1460 2447 972 1293 386 231 1428 2310 1934 2330 1085 2155 217 1286 126 1001 264 898 1372 2050 1488 1836 377 1831 321 372 330 1664 1760 2026 1323 1746 2378 152 654 1393 1019 1162 2140 1015 2445 667 1672 1049 178 893 2386 120 598 1023 808 320 1440 1544 2361 1851 508 625 1588 1644 1084 1980 2054 370 2385 61 930 1203 45 624 467 2197 1715 1677 442 578 1459 1592 2433 1598 896 2081 2379 602 444 1604 2033 1485 756 1970 2036 2322 317 402 1714 763 2245 217 1286 126 1001 1026 2176 1776 251 1626 1964 2344 935 736 400 1216 1930 198 366 1191 902 1195 1823 891 16 2021 2451 1554 315 986 408 682 1850 319 510 911 1424 1441 1100 162 808 320 1440 1785 1657 807 1516 2261 1375 1690 1045 302 2396 2342 1894 2150 1366 566 676 2003 327 483 2055 696 305 1807 915 168 1086 1608 2081 2379 602 444 1460 2447 972 1293 1970 2036 2322 317 1075 2149 180 1018 217 1286 126 1001 264 898 1372 2050 1626 1964 2344 935 184 308 1243 1813 1930 198 366 53 1817 1130 2026 1323 1746 111 1697 1267 315 986 408 211 670 1745 667 1672 1049 1061 1723 1027 808 320 1440 1544 2361 1851 1516 2261 1375 920 314 208 2396 2342 1894 582 1274 1168 61 930 1203 1221 2323 2025 6 966 1333 1010 1447 749 2185 771 985 1603 552 161 2076 386 231 1428 2310 402 1714 763 2245 217 1286 126 1001 2062 1717 789 705 422 600 353 2043 130 765 1115 2272 2440 37 2312 2372 1350 2200 281 2378 152 654 829 1161 2223 682 1850 319 2087 2267 2193 2265 2347 2331 1933 2460 2181 1564 148 1353 1095 59 1458 1992 464 2013 2426 1017 1405 1280 1849 562 1682 1685 171 1401 338 202 806 1922 1857 436 2059 2305 1565 100 1576 1586 132 2073 738 1082 374 386 231 1428 2310 1934 2330 1085 2155 217 1286 126 1001 264 898 1372 2050 422 600 353 2043 1859 2320 1047 1054 2440 37 2312 2372 103 1935 1194 1661 2378 152 654 1393 1019 1162 2140 1015 2445 667 1672 1049 2265 2347 2331 648 1189 2456 15 2414 2452 2449 585 405 1992 464 2013 863 1551 1531 1280 1849 562 98 448 824 1401 338 202 618 813 485 1091 1469 901 1768 2375 995 2197 1715 1677 1860 1247 632 759 1711 574 402 1714 763 2245 217 1286 126 1001 1026 2176 1776 251 1626 1964 2344 935 130 765 1115 2272 2440 37 2312 2372 1224 2363 155 1731 1847 484 2215 1520 2021 2451 1554 315 986 408 682 1850 319 510 911 1424 289 1482 57 3 2357 2335 1564 148 1353 75 2467 270 2426 1017 1405 1280 1849 562 210 2008 1122 2056 73 1736 1696 1337 1108 2142 2407 236 436 2059 2305 1474 235 2453 305 1807 915 1335 669 1650 1875 389 70 217 1286 126 1001 264 898 1372 2050 1626 1964 2344 935 184 308 1243 1813 2440 37 2312 2372 103 1935 1194 1661 1847 484 2215 1520 1957 939 2144 12 315 986 408 211 670 1745 667 1672 1049 1061 1723 1027 3 2357 2335 5 84 248 2449 585 405 1960 1581 1563 1280 1849 562 98 448 824 2056 73 1736 844 1184 48 2142 2407 236 1042 2425 1891 1768 2375 995 2204 2397 764 1010 1447 749 1473 952 256 361 1124 437 1484 1292 2015 143 2309 589 1090 757 1995 2094 1673 2161 2277 1508 520 1890 1210 2274 2455 597 25 131 1308 1806 1304 2295 1348 116 2380 1706 545 547 1141 245 1395 204 2191 47 239 1479 2293 278 1758 723 888 960 2438 967 254 1255 2338 418 450 1241 52 2394 2393 1899 730 579 304 825 276 1778 850 2317 13 1182 453 1702 498 399 1751 2102 1767 2 899 2164 2192 1730 2130 781 1854 956 592 612 1558 2085 735 2309 589 1090 757 1604 2033 1485 756 2277 1508 520 1890 1619 206 836 567 25 131 1308 1806 1026 2176 1776 251 2380 1706 545 547 273 2016 1916 1880 204 2191 47 1013 417 659 1309 2332 486 1496 1573 1222 967 254 1255 1300 1322 1521 1179 1081 1056 604 571 1582 579 304 825 1785 1657 807 2317 13 1182 1660 279 1512 399 1751 2102 197 2339 1802 426 1773 842 1261 783 716 679 747 1837 316 313 1314 373 1639 1016 1995 2094 1673 2161 2277 1508 520 1890 635 2463 1457 2441 2283 2208 1211 841 1304 2295 1348 116 2380 1706 545 547 1781 1542 105 862 294 2189 1128 1884 2388 1125 1793 473 2060 1020 278 1758 723 1376 438 1989 775 1886 335 940 391 1927 1241 52 2394 1156 28 2454 276 1778 850 2317 13 1182 1552 164 2294 984 1536 227 1201 1132 883 1031 1822 1055 2164 2192 1730 890 1163 1374 295 1738 1547 358 2184 1915 261 85 1700 2277 1508 520 1890 1619 206 836 567 2283 2208 1211 841 987 1060 265 325 2380 1706 545 547 273 2016 1916 1880 294 2189 1128 1884 2390 96 323 242 473 2060 1020 1686 750 814 1496 1573 1222 884 878 2288 940 391 1927 137 1931 1764 604 571 1582 1938 1858 1494 2317 13 1182 1660 279 1512 984 1536 227 112 461 962 1031 1822 1055 2227 272 1659 1261 783 716 796 1820 1872 416 638 822 419 2377 687 943 1798 2366 1210 2274 2455 597 25 131 1308 1806 1304 2295 1348 116 2380 1706 545 547 1658 1270 2428 249 238 44 334 421 209 1373 1467 1561 1610 2409 280 1506 888 960 2438 967 254 1255 2338 418 450 1241 52 2394 1143 352 1526 874 1284 108 1537 788 1476 1465 144 744 955 1126 1534 2153 183 2231 1601 1606 1435 41 1632 2247 1550 2079 77 1962 1826 1150 367 1338 218 691 2326 2138 956 592 612 1968 274 2289 1235 1699 2080 25 131 1308 1806 1026 2176 1776 251 2380 1706 545 547 273 2016 1916 1880 238 44 334 421 1224 2363 155 1731 1610 2409 280 1506 1870 14 926 1014 967 254 1255 1300 1322 1521 1179 1081 1056 604 571 1582 874 1284 108 1799 1205 2095 1379 423 1845 501 76 1412 2153 183 2231 210 2008 1122 41 1632 2247 343 1390 534 1962 1826 1150 2113 19 1328 2108 1771 1932 414 2078 895 316 313 1314 1030 647 232 923 904 2159 1304 2295 1348 116 2380 1706 545 547 1781 1542 105 862 294 2189 1128 1884 209 1373 1467 1561 1610 2409 280 1506 2220 83 2281 622 1747 2402 621 1159 775 1886 335 940 391 1927 1241 52 2394 1156 28 2454 629 1622 900 1728 2341 931 1465 144 744 2022 50 1519 1601 1606 1435 41 1632 2247 2269 1721 2031 368 237 876 384 1602 742 1589 1575 26 691 2326 2138 558 1230 69 358 2184 1915 17 1050 1365 2403 1950 1371 2380 1706 545 547 273 2016 1916 1880 294 2189 1128 1884 2390 96 323 242 1610 2409 280 1506 1870 14 926 1014 1747 2402 621 1159 1399 1840 1848 72 940 391 1927 137 1931 1764 604 571 1582 1938 1858 1494 1728 2341 931 581 2148 712 501 76 1412 847 1527 938 41 1632 2247 343 1390 534 368 237 876 693 1029 74 1589 1575 26 951 1033 350 414 2078 895 2077 701 2169 419 2377 687 1186 1403 1621 277 1215 173 1604 2033 1485 756 1970 2036 2322 317 1619 206 836 567 787 1069 192 2296 1026 2176 1776 251 1626 1964 2344 935 273 2016 1916 1880 1092 1735 2401 1223 1013 417 659 1617 1154 459 1823 891 16 734 1113 2442 1300 1322 1521 614 1562 1580 510 911 1424 666 1869 257 1785 1657 807 1516 2261 1375 1660 279 1512 2358 23 1111 197 2339 1802 875 588 398 676 2003 327 425 465 1196 1394 1584 58 733 1259 509 1811 1074 1546 1970 2036 2322 317 1075 2149 180 1018 787 1069 192 2296 1002 546 1974 376 1626 1964 2344 935 184 308 1243 1813 1092 1735 2401 1223 1454 867 80 469 1617 1154 459 1237 1779 357 111 1697 1267 1442 2172 1998 614 1562 1580 1902 1833 2257 1061 1723 1027 309 504 2370 1516 2261 1375 920 314 208 2358 23 1111 1332 2001 1357 875 588 398 2167 1991 2171 1221 2323 2025 1903 1226 118 472 1945 1649 1914 1597 1640 107 1367 2329 1619 206 836 567 787 1069 192 2296 987 1060 265 325 1107 2252 671 942 273 2016 1916 1880 1092 1735 2401 1223 2390 96 323 242 2325 1695 593 561 1686 750 814 1889 1888 512 734 1113 2442 1426 2098 2061 137 1931 1764 1724 1238 1641 666 1869 257 2010 1104 820 1660 279 1512 2358 23 1111 112 461 962 2292 2298 1665 2227 272 1659 1917 2163 471 425 465 1196 90 1726 1117 1678 2047 2009 838 586 2131 695 1982 1713 787 1069 192 2296 1002 546 1974 376 1107 2252 671 942 741 89 1683 1590 1092 1735 2401 1223 1454 867 80 469 2325 1695 593 561 1969 1502 141 2466 1889 1888 512 2119 662 1325 1442 2172 1998 2376 568 123 1724 1238 1641 697 1461 2186 309 504 2370 1012 2328 539 2358 23 1111 1332 2001 1357 2292 2298 1665 572 1733 1493 1917 2163 471 2158 1909 559 1903 1226 118 157 1832 2096 761 2473 2086 664 1490 1734 160 1614 293 1026 2176 1776 251 1626 1964 2344 935 273 2016 1916 1880 1092 1735 2401 1223 1224 2363 155 1731 1847 484 2215 1520 1870 14 926 1014 1271 553 1984 2057 1300 1322 1521 614 1562 1580 510 911 1424 666 1869 257 1799 1205 2095 1190 1208 897 75 2467 270 2018 1709 1265 210 2008 1122 2056 73 1736 343 1390 534 524 1344 55 2113 19 1328 1306 1133 433 1474 235 2453 2302 1750 92 733 1259 509 1317 1361 46 1855 2316 420 1626 1964 2344 935 184 308 1243 1813 1092 1735 2401 1223 1454 867 80 469 1847 484 2215 1520 1957 939 2144 12 1271 553 1984 2057 689 630 1530 1529 614 1562 1580 1902 1833 2257 1061 1723 1027 309 504 2370 1190 1208 897 1898 1566 905 1960 1581 1563 1500 2178 2229 2056 73 1736 844 1184 48 524 1344 55 2082 1127 983 1306 1133 433 1298 1883 1312 2204 2397 764 601 263 2369 1914 1597 1640 1676 1251 1885 1662 858 1421 273 2016 1916 1880 1092 1735 2401 1223 2390 96 323 242 2325 1695 593 561 1870 14 926 1014 1271 553 1984 2057 1399 1840 1848 72 688 213 790 2395 137 1931 1764 1724 1238 1641 666 1869 257 2010 1104 820 581 2148 712 1971 121 1585 2018 1709 1265 1629 1528 1334 343 1390 534 524 1344 55 693 1029 74 674 596 779 951 1033 350 38 2421 110 2302 1750 92 492 1620 2303 838 586 2131 2151 125 1718 446 1881 2273 1092 1735 2401 1223 1454 867 80 469 2325 1695 593 561 1969 1502 141 2466 1271 553 1984 2057 689 630 1530 1529 688 213 790 2395 1556 645 1874 544 1724 1238 1641 697 1461 2186 309 504 2370 1012 2328 539 1971 121 1585 494 1879 1268 1500 2178 2229 1204 1518 2258 524 1344 55 2082 1127 983 674 596 779 784 2109 1071 38 2421 110 331 2333 1948 601 263 2369 1105 1396 324 664 1490 1734 2143 997 95 1 306 1311 892 1893 336 311 628 2263 2352 1420 2243 443 1389 1472 991 854 872 694 1144 1032 1449 226 580 39 2254 1846 129 2418 1612 2157 2023 882 1397 835 1073 228 2314 906 826 185 35 1868 2374 1052 917 427 1429 470 2300 1961 1410 1024 2367 333 2170 33 1302 1183 345 2053 587 63 2246 1800 2029 521 714 864 2112 2313 2286 729 2225 1505 710 241 681 1463 1206 253 2427 1158 1499 2123 1391 1599 922 1967 1402 859 2458 628 2263 2352 1420 2062 1717 789 705 991 854 872 694 130 765 1115 2272 580 39 2254 1846 1131 1355 639 8 2023 882 1397 835 380 34 1351 1656 906 826 185 2087 2267 2193 1318 1462 525 93 2146 1123 1961 1410 1024 1972 360 1057 1812 207 29 1295 2203 392 63 2246 1800 2240 2354 1419 864 2112 2313 1436 49 365 1505 710 241 1443 1378 1618 359 1480 176 2069 1080 458 1220 1507 1936 1792 216 1336 135 760 1810 2243 443 1389 1472 991 854 872 694 1658 1270 2428 249 238 44 334 421 129 2418 1612 2157 2023 882 1397 835 1953 554 478 1921 977 1434 378 2048 839 1548 569 1174 388 2083 1052 917 427 1537 788 1476 774 2190 2217 2359 2306 463 33 1302 1183 2371 2177 303 2029 521 714 864 2112 2313 381 2166 449 1146 474 2474 51 505 1624 609 969 1627 253 2427 1158 2472 1340 1423 1432 1360 823 975 220 1148 2437 877 650 991 854 872 694 130 765 1115 2272 238 44 334 421 1224 2363 155 1731 2023 882 1397 835 380 34 1351 1656 977 1434 378 2048 332 1703 1524 1234 1174 388 2083 289 1482 57 93 2146 1123 1379 423 1845 2359 2306 463 1829 927 296 1295 2203 392 2199 1438 1102 864 2112 2313 1436 49 365 1146 474 2474 1076 718 1170 609 969 1627 1232 1008 1327 2069 1080 458 800 2242 36 1795 809 2439 342 880 269 1155 1571 2419 1144 1032 1449 226 580 39 2254 1846 129 2418 1612 2157 2023 882 1397 835 1979 1983 1652 222 2219 413 2070 1541 1572 1278 2165 2334 762 2343 1689 1503 1429 470 2300 1961 1410 1024 2367 333 2170 33 1302 1183 583 1273 1560 452 2424 2423 1342 81 440 393 475 2301 1635 1433 801 20 2362 1804 177 1796 1645 2464 785 633 2111 1151 153 244 2004 246 831 726 873 1225 1192 665 1599 922 1967 1533 1486 328 672 698 1489 580 39 2254 1846 1131 1355 639 8 2023 882 1397 835 380 34 1351 1656 2219 413 2070 1541 1064 516 2422 1470 762 2343 1689 1503 563 67 2290 2100 1961 1410 1024 1972 360 1057 1812 207 29 1295 2203 392 452 2424 2423 2089 2365 1740 2099 1669 1824 1422 2248 2311 20 2362 1804 1623 196 1450 2464 785 633 2114 1987 481 244 2004 246 1021 1263 1786 2475 1720 62 348 2381 1905 1792 216 1336 2211 2027 777 2002 792 403 129 2418 1612 2157 2023 882 1397 835 1953 554 478 1921 977 1434 378 2048 1572 1278 2165 2334 762 2343 1689 1503 1856 816 1455 1119 71 2237 1478 1427 774 2190 2217 2359 2306 463 33 1302 1183 2371 2177 303 434 840 78 755 2201 804 393 475 2301 2106 1320 953 177 1796 1645 2464 785 633 27 255 1906 1160 1296 1999 928 79 812 407 2351 2319 1225 1192 665 515 1634 1523 975 220 1148 758 2174 2387 686 853 1742 2023 882 1397 835 380 34 1351 1656 977 1434 378 2048 332 1703 1524 1234 762 2343 1689 1503 563 67 2290 2100 71 2237 1478 1427 2446 1277 1498 2392 2359 2306 463 1829 927 296 1295 2203 392 2199 1438 1102 755 2201 804 2244 322 2434 1422 2248 2311 2156 1048 680 2464 785 633 2114 1987 481 1160 1296 1999 66 117 1166 407 2351 2319 1358 1411 1976 348 2381 1905 383 1504 1958 342 880 269 2337 1079 1681 1065 828 907 2062 1717 789 705 422 600 353 2043 130 765 1115 2272 2440 37 2312 2372 1131 1355 639 8 514 1316 535 1535 380 34 1351 1656 1121 555 1801 2468 2087 2267 2193 2265 2347 2331 1933 2460 2181 1564 148 1353 1972 360 1057 2444 1674 1815 134 2262 1954 719 456 1324 2240 2354 1419 1871 1712 2224 1436 49 365 1492 2318 1862 1443 1378 1618 1951 950 1257 490 488 1852 2470 1631 577 1586 132 2073 2038 1844 1078 675 657 4 422 600 353 2043 1859 2320 1047 1054 2440 37 2312 2372 103 1935 1194 1661 514 1316 535 1535 1788 1244 506 768 1121 555 1801 2468 1947 2469 810 42 2265 2347 2331 648 1189 2456 15 2414 2452 2449 585 405 2444 1674 1815 1213 1398 870 772 1913 1495 1097 517 1381 1871 1712 2224 2260 1553 1653 1492 2318 1862 745 428 720 1951 950 1257 1362 1388 1532 1866 2230 326 1555 1729 959 1860 1247 632 717 2238 1710 1752 495 260 130 765 1115 2272 2440 37 2312 2372 1224 2363 155 1731 1847 484 2215 1520 380 34 1351 1656 1121 555 1801 2468 332 1703 1524 1234 1772 318 477 2006 289 1482 57 3 2357 2335 1564 148 1353 75 2467 270 1829 927 296 1413 2235 2287 719 456 1324 2028 404 692 1436 49 365 1492 2318 1862 1076 718 1170 1952 2207 1135 1232 1008 1327 722 1349 2134 2470 1631 577 1219 1704 1137 1335 669 1650 2168 2226 646 550 2284 1138 2440 37 2312 2372 103 1935 1194 1661 1847 484 2215 1520 1957 939 2144 12 1121 555 1801 2468 1947 2469 810 42 1772 318 477 2006 406 1754 1513 364 3 2357 2335 5 84 248 2449 585 405 1960 1581 1563 1413 2235 2287 982 87 2065 1097 517 1381 623 1072 179 1492 2318 1862 745 428 720 1952 2207 1135 10 2039 1118 722 1349 2134 2404 834 1036 1555 1729 959 301 1180 556 1473 952 256 2356 2136 1993 766 1827 1258 1131 1355 639 8 514 1316 535 1535 380 34 1351 1656 1121 555 1801 2468 1064 516 2422 1470 1288 1188 379 1587 563 67 2290 2100 2117 1431 1240 1229 1972 360 1057 2444 1674 1815 134 2262 1954 719 456 1324 2089 2365 1740 1887 21 1609 267 1172 2408 1417 221 1404 1623 196 1450 1139 1153 1515 2114 1987 481 656 1688 2092 1021 1263 1786 2064 1762 1252 268 2222 142 2315 2462 1838 2038 1844 1078 1769 181 769 1596 2399 82 514 1316 535 1535 1788 1244 506 768 1121 555 1801 2468 1947 2469 810 42 1288 1188 379 1587 1716 2321 65 649 2117 1431 1240 1229 1176 948 819 1341 2444 1674 1815 1213 1398 870 772 1913 1495 1097 517 1381 1887 21 1609 1248 1254 138 2035 643 1382 1307 175 678 1139 1153 1515 1819 711 617 656 1688 2092 1040 1149 2122 2064 1762 1252 451 2450 1559 2471 2188 102 2198 2349 136 717 2238 1710 1501 2429 1784 91 531 1253 380 34 1351 1656 1121 555 1801 2468 332 1703 1524 1234 1772 318 477 2006 563 67 2290 2100 2117 1431 1240 1229 2446 1277 1498 2392 1615 1446 2105 258 1829 927 296 1413 2235 2287 719 456 1324 2028 404 692 2244 322 2434 106 868 746 1417 221 1404 998 2276 2182 2114 1987 481 656 1688 2092 66 117 1166 1034 799 685 1358 1411 1976 958 964 1791 2315 2462 1838 1022 1152 2030 2168 2226 646 912 172 658 2014 2005 1058 1121 555 1801 2468 1947 2469 810 42 1772 318 477 2006 406 1754 1513 364 2117 1431 1240 1229 1176 948 819 1341 1615 1446 2105 258 2391 1708 1250 652 1413 2235 2287 982 87 2065 1097 517 1381 623 1072 179 106 868 746 2133 1088 981 1307 175 678 262 778 275 656 1688 2092 1040 1149 2122 1034 799 685 1557 1207 1725 958 964 1791 1370 663 31 2198 2349 136 2251 1628 2234 2356 2136 1993 2068 466 661 1185 1918 2278 1658 1270 2428 249 238 44 334 421 209 1373 1467 1561 1610 2409 280 1506 1953 554 478 1921 977 1434 378 2048 199 1062 1136 519 1994 1605 811 1329 1143 352 1526 874 1284 108 1537 788 1476 1465 144 744 1218 1578 2398 1835 2209 2020 2371 2177 303 937 2383 151 381 2166 449 1146 474 2474 2228 415 2364 1377 2116 1514 1464 2291 619 1867 163 9 2472 1340 1423 292 541 830 1968 274 2289 1003 2271 439 739 2091 146 238 44 334 421 1224 2363 155 1731 1610 2409 280 1506 1870 14 926 1014 977 1434 378 2048 332 1703 1524 1234 1994 1605 811 1329 1444 603 2051 1313 874 1284 108 1799 1205 2095 1379 423 1845 501 76 1412 1835 2209 2020 1425 349 737 2199 1438 1102 1408 533 1986 1146 474 2474 1076 718 1170 1377 2116 1514 833 936 182 1867 163 9 1625 1830 2101 800 2242 36 1038 97 523 1030 647 232 2214 158 1926 881 282 502 209 1373 1467 1561 1610 2409 280 1506 2220 83 2281 622 1747 2402 621 1159 199 1062 1136 519 1994 1605 811 1329 1214 411 1289 2202 2239 2024 1637 949 629 1622 900 1728 2341 931 1465 144 744 2022 50 1519 133 2430 2071 1094 2324 2118 937 2383 151 1648 1794 2432 2228 415 2364 1377 2116 1514 2368 1364 193 445 2405 2067 287 1955 1437 1301 538 978 292 541 830 409 1481 2145 17 1050 1365 2183 683 522 1809 115 1101 1610 2409 280 1506 1870 14 926 1014 1747 2402 621 1159 1399 1840 1848 72 1994 1605 811 1329 1444 603 2051 1313 2239 2024 1637 949 1698 1471 2040 1549 1728 2341 931 581 2148 712 501 76 1412 847 1527 938 1094 2324 2118 2297 344 832 1408 533 1986 286 1262 1701 1377 2116 1514 833 936 182 445 2405 2067 530 1755 431 1301 538 978 963 1912 1780 1038 97 523 805 1006 626 1186 1403 1621 1692 1345 954 410 1233 189 1953 554 478 1921 977 1434 378 2048 199 1062 1136 519 1994 1605 811 1329 1856 816 1455 1119 71 2237 1478 1427 1077 297 1483 2042 709 631 455 1011 1218 1578 2398 1835 2209 2020 2371 2177 303 937 2383 151 2307 195 2268 1310 229 215 2106 1320 953 821 1749 627 27 255 1906 1160 1296 1999 283 1070 2179 1142 2457 460 2045 429 1985 770 1973 1939 515 1634 1523 1876 1430 780 1003 2271 439 1853 2135 1043 1756 1046 1242 977 1434 378 2048 332 1703 1524 1234 1994 1605 811 1329 1444 603 2051 1313 71 2237 1478 1427 2446 1277 1498 2392 709 631 455 1011 924 1380 2072 395 1835 2209 2020 1425 349 737 2199 1438 1102 1408 533 1986 1310 229 215 363 503 613 2156 1048 680 827 704 128 1160 1296 1999 66 117 1166 1142 2457 460 851 1110 224 770 1973 1939 1282 2137 1269 383 1504 1958 1744 866 290 2214 158 1926 1453 489 1978 706 30 2477 199 1062 1136 519 1994 1605 811 1329 1214 411 1289 2202 2239 2024 1637 949 1077 297 1483 2042 709 631 455 1011 946 2084 234 1803 487 1636 551 288 133 2430 2071 1094 2324 2118 937 2383 151 1648 1794 2432 1633 145 1177 430 591 212 821 1749 627 979 2000 1276 283 1070 2179 1142 2457 460 731 1099 266 989 961 767 865 1782 1839 493 754 114 1876 1430 780 1873 1757 2353 2183 683 522 1841 786 205 2210 1272 2075 1994 1605 811 1329 1444 603 2051 1313 2239 2024 1637 949 1698 1471 2040 1549 709 631 455 1011 924 1380 2072 395 487 1636 551 288 852 482 1063 908 1094 2324 2118 2297 344 832 1408 533 1986 286 1262 1701 430 591 212 677 1923 1946 827 704 128 644 1209 837 1142 2457 460 851 1110 224 989 961 767 1920 1468 1583 493 754 114 2206 1171 2180 1744 866 290 2194 454 732 1692 1345 954 1956 1814 1765 1925 113 150 1224 2363 155 1731 1847 484 2215 1520 1870 14 926 1014 1271 553 1984 2057 332 1703 1524 1234 1772 318 477 2006 1444 603 2051 1313 2141 2327 2285 124 1799 1205 2095 1190 1208 897 75 2467 270 2018 1709 1265 1425 349 737 2345 1260 2115 2028 404 692 944 980 1294 1076 718 1170 1952 2207 1135 833 936 182 1727 2461 1197 1625 1830 2101 346 1098 233 1219 1704 1137 1687 728 127 1317 1361 46 620 1385 507 2104 2264 725 1847 484 2215 1520 1957 939 2144 12 1271 553 1984 2057 689 630 1530 1529 1772 318 477 2006 406 1754 1513 364 2141 2327 2285 124 1264 594 1287 186 1190 1208 897 1898 1566 905 1960 1581 1563 1500 2178 2229 2345 1260 2115 690 2270 560 623 1072 179 1044 918 1522 1952 2207 1135 10 2039 1118 1727 2461 1197 913 2412 1407 346 1098 233 480 104 1943 301 1180 556 1193 2152 2187 1676 1251 1885 40 887 2411 307 1025 540 1870 14 926 1014 1271 553 1984 2057 1399 1840 1848 72 688 213 790 2395 1444 603 2051 1313 2141 2327 2285 124 1698 1471 2040 1549 1818 684 99 1147 581 2148 712 1971 121 1585 2018 1709 1265 1629 1528 1334 2297 344 832 2049 1386 699 944 980 1294 2090 1539 2304 833 936 182 1727 2461 1197 530 1755 431 397 605 1414 963 1912 1780 0 1281 1346 1687 728 127 299 1777 526 2151 125 1718 394 174 385 2415 1611 910 1271 553 1984 2057 689 630 1530 1529 688 213 790 2395 1556 645 1874 544 2141 2327 2285 124 1264 594 1287 186 1818 684 99 1147 2384 1164 803 575 1971 121 1585 494 1879 1268 1500 2178 2229 1204 1518 2258 2049 1386 699 2012 2420 1897 1044 918 1522 462 782 2147 1727 2461 1197 913 2412 1407 397 605 1414 748 933 1109 0 1281 1346 616 1415 2139 1193 2152 2187 1145 1175 1600 2143 997 95 1517 856 2435 1975 491 2044 332 1703 1524 1234 1772 318 477 2006 1444 603 2051 1313 2141 2327 2285 124 2446 1277 1498 2392 1615 1446 2105 258 924 1380 2072 395 2052 250 60 1445 1425 349 737 2345 1260 2115 2028 404 692 944 980 1294 363 503 613 479 894 337 998 2276 2182 2160 1643 2259 66 117 1166 1034 799 685 851 1110 224 1157 1783 1106 1282 2137 1269 564 993 1670 1022 1152 2030 201 845 1116 620 1385 507 1173 1165 1352 2088 159 2406 1772 318 477 2006 406 1754 1513 364 2141 2327 2285 124 1264 594 1287 186 1615 1446 2105 258 2391 1708 1250 652 2052 250 60 1445 1693 32 2299 707 2345 1260 2115 690 2270 560 623 1072 179 1044 918 1522 479 894 337 2019 1239 921 262 778 275 1199 354 595 1034 799 685 1557 1207 1725 1157 1783 1106 1842 54 1732 564 993 1670 1037 170 2232 2251 1628 2234 1330 1569 957 40 887 2411 1356 885 1789 1005 727 1114 1444 603 2051 1313 2141 2327 2285 124 1698 1471 2040 1549 1818 684 99 1147 924 1380 2072 395 2052 250 60 1445 852 482 1063 908 934 2212 1087 356 2297 344 832 2049 1386 699 944 980 1294 2090 1539 2304 677 1923 1946 511 990 1790 2160 1643 2259 992 640 2282 851 1110 224 1157 1783 1106 1920 1468 1583 1655 557 611 2206 1171 2180 1907 2011 1797 201 845 1116 1452 1315 2350 394 174 385 1181 528 1051 965 64 2126 2141 2327 2285 124 1264 594 1287 186 1818 684 99 1147 2384 1164 803 575 2052 250 60 1445 1693 32 2299 707 934 2212 1087 356 355 1538 2443 1283 2049 1386 699 2012 2420 1897 1044 918 1522 462 782 2147 511 990 1790 1722 855 2275 1199 354 595 1977 2173 147 1157 1783 1106 1842 54 1732 1655 557 611 1053 708 1593 1907 2011 1797 1816 230 1359 1330 1569 957 1691 1245 971 1517 856 2435 1129 1369 2256 166 1663 468 214 0 56 1667 2216 387 1112 252 1212 1761 532 382 1679 1607 945 2175 1167 109 2097 590 190 1828 1895 740 1770 1910 1753 1331 914 743 543 94 843 549 169 2233 1684 1805 139 2196 615 1959 2037 1865 2058 773 1067 542 2236 1568 1900 442 578 1459 168 1086 1608 2185 771 985 738 1082 374 759 1711 574 1875 389 70 361 1124 437 1558 2085 735 373 1639 1016 261 85 1700 943 1798 2366 1235 1699 2080 923 904 2159 2403 1950 1371 277 1215 173 1811 1074 1546 107 1367 2329 695 1982 1713 160 1614 293 1855 2316 420 1662 858 1421 446 1881 2273 1 306 1311 1402 859 2458 135 760 1810 2437 877 650 1155 1571 2419 672 698 1489 2002 792 403 686 853 1742 1065 828 907 675 657 4 1752 495 260 550 2284 1138 766 1827 1258 1596 2399 82 91 531 1253 2014 2005 1058 1185 1918 2278 739 2091 146 881 282 502 1809 115 1101 410 1233 189 1756 1046 1242 706 30 2477 2210 1272 2075 1925 113 150 2104 2264 725 307 1025 540 2415 1611 910 1975 491 2044 2088 159 2406 1005 727 1114 965 64 2126 166 1663 468 64 0 0 25 28 31 34 37 40 43 46 49 52 55 58 61 64 67 70 73 76 79 82 85 88 91 94 97 100 103 106 109 112 115 118 121 124 127 130 133 136 139 142 145 148 151 154 157 160 163 166 169 172 175 178 181 184 187 190 193 196 199 202 205 208 211 64 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 1 0 +3 0 0 1584 0 1 2132 1491 339 2205 291 721 191 18446744073709551615 0 499 973 2459 18446744073709551615 0 1319 1227 871 18446744073709551615 0 330 1664 1760 18446744073709551615 1 86 347 1134 424 1990 2346 1666 18446744073709551615 0 2400 154 889 18446744073709551615 0 1141 245 1395 18446744073709551615 0 2388 1125 1793 18446744073709551615 1 18 2266 2093 1291 1719 2410 1039 18446744073709551615 0 2249 1103 1570 18446744073709551615 0 345 2053 587 18446744073709551615 0 1635 1433 801 18446744073709551615 0 1831 321 372 18446744073709551615 0 53 1817 1130 18446744073709551615 0 1237 1779 357 18446744073709551615 0 2119 662 1325 18446744073709551615 0 120 598 1023 18446744073709551615 0 863 1551 1531 18446744073709551615 0 2260 1553 1653 18446744073709551615 0 1819 711 617 18446744073709551615 0 1376 438 1989 18446744073709551615 0 884 878 2288 18446744073709551615 0 1426 2098 2061 18446744073709551615 0 2376 568 123 18446744073709551615 0 1552 164 2294 18446744073709551615 0 2269 1721 2031 18446744073709551615 0 2368 1364 193 18446744073709551615 0 731 1099 266 18446744073709551615 0 572 1733 1493 18446744073709551615 0 784 2109 1071 18446744073709551615 0 748 933 1109 18446744073709551615 0 1053 708 1593 18446744073709551615 0 1342 81 440 18446744073709551615 0 2099 1669 1824 18446744073709551615 0 267 1172 2408 18446744073709551615 0 2035 643 1382 18446744073709551615 0 583 1273 1560 18446744073709551615 0 434 840 78 18446744073709551615 0 2307 195 2268 18446744073709551615 0 1633 145 1177 18446744073709551615 0 1248 1254 138 18446744073709551615 0 2133 1088 981 18446744073709551615 0 2019 1239 921 18446744073709551615 0 1722 855 2275 18446744073709551615 0 979 2000 1276 18446744073709551615 0 644 1209 837 18446744073709551615 0 992 640 2282 18446744073709551615 0 1977 2173 147 18446744073709551615 0 35 1868 2374 18446744073709551615 0 1318 1462 525 18446744073709551615 0 1933 2460 2181 18446744073709551615 0 15 2414 2452 18446744073709551615 0 1763 673 2476 18446744073709551615 0 1095 59 1458 18446744073709551615 0 2240 2354 1419 18446744073709551615 0 1623 196 1450 18446744073709551615 0 1739 2129 1354 18446744073709551615 0 736 400 1216 18446744073709551615 0 1013 417 659 18446744073709551615 0 1686 750 814 18446744073709551615 0 239 1479 2293 18446744073709551615 0 1309 2332 486 18446744073709551615 0 1823 891 16 18446744073709551615 0 111 1697 1267 18446744073709551615 0 2393 1899 730 18446744073709551615 0 955 1126 1534 18446744073709551615 0 381 2166 449 18446744073709551615 0 27 255 1906 18446744073709551615 0 1073 228 2314 18446744073709551615 0 839 1548 569 18446744073709551615 0 1143 352 1526 18446744073709551615 0 629 1622 900 18446744073709551615 0 920 314 208 18446744073709551615 0 844 1184 48 18446744073709551615 0 10 2039 1118 18446744073709551615 0 1557 1207 1725 18446744073709551615 0 648 1189 2456 18446744073709551615 0 5 84 248 18446744073709551615 0 1898 1566 905 18446744073709551615 0 494 1879 1268 18446744073709551615 0 2022 50 1519 18446744073709551615 0 847 1527 938 18446744073709551615 0 1629 1528 1334 18446744073709551615 0 1204 1518 2258 18446744073709551615 0 112 461 962 18446744073709551615 0 693 1029 74 18446744073709551615 0 530 1755 431 18446744073709551615 0 1920 1468 1583 18446744073709551615 0 2089 2365 1740 18446744073709551615 0 2244 322 2434 18446744073709551615 0 363 503 613 18446744073709551615 0 677 1923 1946 18446744073709551615 0 2106 1320 953 18446744073709551615 0 2156 1048 680 18446744073709551615 0 998 2276 2182 18446744073709551615 0 262 778 275 18446744073709551615 0 1076 718 1170 18446744073709551615 0 66 117 1166 18446744073709551615 0 1785 1657 807 18446744073709551615 0 210 2008 1122 18446744073709551615 0 75 2467 270 18446744073709551615 0 1960 1581 1563 18446744073709551615 0 1537 788 1476 18446744073709551615 0 1379 423 1845 18446744073709551615 0 1799 1205 2095 18446744073709551615 0 581 2148 712 18446744073709551615 0 2087 2267 2193 18446744073709551615 0 289 1482 57 18446744073709551615 0 909 527 1041 1 2431 22 1089 2436 2017 225 529 18446744073709551615 0 2241 818 2382 18446744073709551615 0 300 795 2340 1 988 371 996 1919 1384 1966 537 18446744073709551615 0 412 925 432 18446744073709551615 0 2367 333 2170 18446744073709551615 0 1812 207 29 18446744073709551615 0 63 2246 1800 18446744073709551615 0 20 2362 1804 18446744073709551615 0 829 1161 2223 18446744073709551615 0 2140 1015 2445 18446744073709551615 0 178 893 2386 18446744073709551615 0 1992 464 2013 18446744073709551615 0 134 2262 1954 18446744073709551615 0 772 1913 1495 18446744073709551615 0 1871 1712 2224 18446744073709551615 0 1139 1153 1515 18446744073709551615 0 2253 1864 1198 1 994 7 1743 2280 1543 1668 791 18446744073709551615 0 2218 2448 2308 18446744073709551615 0 194 1901 1000 1 968 119 815 101 1766 1256 329 18446744073709551615 0 1861 1169 243 18446744073709551615 0 1488 1836 377 18446744073709551615 0 1930 198 366 18446744073709551615 0 1191 902 1195 18446744073709551615 0 2026 1323 1746 18446744073709551615 0 204 2191 47 18446744073709551615 0 473 2060 1020 18446744073709551615 0 278 1758 723 18446744073709551615 0 1496 1573 1222 18446744073709551615 0 1617 1154 459 18446744073709551615 0 1889 1888 512 18446744073709551615 0 734 1113 2442 18446744073709551615 0 1442 2172 1998 18446744073709551615 0 203 2389 214 1 1545 2355 1409 310 518 1487 341 18446744073709551615 0 259 1392 1475 18446744073709551615 0 1540 362 1387 1 919 1942 1808 1400 1988 271 2107 18446744073709551615 0 802 929 1949 18446744073709551615 0 276 1778 850 18446744073709551615 0 1601 1606 1435 18446744073709551615 0 888 960 2438 18446744073709551615 0 775 1886 335 18446744073709551615 0 2029 521 714 18446744073709551615 0 177 1796 1645 18446744073709551615 0 1429 470 2300 18446744073709551615 0 774 2190 2217 18446744073709551615 0 2228 415 2364 18446744073709551615 0 283 1070 2179 18446744073709551615 0 1218 1578 2398 18446744073709551615 0 133 2430 2071 18446744073709551615 0 1544 2361 1851 18446744073709551615 0 98 448 824 18446744073709551615 0 1393 1019 1162 18446744073709551615 0 211 670 1745 18446744073709551615 0 1332 2001 1357 18446744073709551615 0 2082 1127 983 18446744073709551615 0 1902 1833 2257 18446744073709551615 0 697 1461 2186 18446744073709551615 0 745 428 720 18446744073709551615 0 1040 1149 2122 18446744073709551615 0 1213 1398 870 18446744073709551615 0 982 87 2065 18446744073709551615 0 913 2412 1407 18446744073709551615 0 1842 54 1732 18446744073709551615 0 690 2270 560 18446744073709551615 0 2012 2420 1897 18446744073709551615 0 1156 28 2454 18446744073709551615 0 1938 1858 1494 18446744073709551615 0 984 1536 227 18446744073709551615 0 368 237 876 18446744073709551615 0 1648 1794 2432 18446744073709551615 0 286 1262 1701 18446744073709551615 0 445 2405 2067 18446744073709551615 0 989 961 767 18446744073709551615 0 2010 1104 820 18446744073709551615 0 1012 2328 539 18446744073709551615 0 2292 2298 1665 18446744073709551615 0 674 596 779 18446744073709551615 0 2090 1539 2304 18446744073709551615 0 462 782 2147 18446744073709551615 0 397 605 1414 18446744073709551615 0 1655 557 611 18446744073709551615 0 452 2424 2423 18446744073709551615 0 755 2201 804 18446744073709551615 0 393 475 2301 18446744073709551615 0 1422 2248 2311 18446744073709551615 0 1887 21 1609 18446744073709551615 0 106 868 746 18446744073709551615 0 1417 221 1404 18446744073709551615 0 1307 175 678 18446744073709551615 0 1310 229 215 18446744073709551615 0 430 591 212 18446744073709551615 0 821 1749 627 18446744073709551615 0 827 704 128 18446744073709551615 0 479 894 337 18446744073709551615 0 511 990 1790 18446744073709551615 0 2160 1643 2259 18446744073709551615 0 1199 354 595 18446744073709551615 0 1190 1208 897 18446744073709551615 0 1971 121 1585 18446744073709551615 0 2018 1709 1265 18446744073709551615 0 1500 2178 2229 18446744073709551615 0 874 1284 108 18446744073709551615 0 1728 2341 931 18446744073709551615 0 1465 144 744 18446744073709551615 0 501 76 1412 18446744073709551615 0 2265 2347 2331 18446744073709551615 0 3 2357 2335 18446744073709551615 0 1564 148 1353 18446744073709551615 0 2449 585 405 18446744073709551615 0 906 826 185 18446744073709551615 0 1174 388 2083 18446744073709551615 0 1052 917 427 18446744073709551615 0 93 2146 1123 18446744073709551615 0 2028 404 692 18446744073709551615 0 623 1072 179 18446744073709551615 0 1952 2207 1135 18446744073709551615 0 1034 799 685 18446744073709551615 0 510 911 1424 18446744073709551615 0 1061 1723 1027 18446744073709551615 0 1516 2261 1375 18446744073709551615 0 2056 73 1736 18446744073709551615 0 2371 2177 303 18446744073709551615 0 2199 1438 1102 18446744073709551615 0 1146 474 2474 18446744073709551615 0 1160 1296 1999 18446744073709551615 0 2338 418 450 18446744073709551615 0 1179 1081 1056 18446744073709551615 0 579 304 825 18446744073709551615 0 2153 183 2231 18446744073709551615 0 833 936 182 18446744073709551615 0 851 1110 224 18446744073709551615 0 1425 349 737 18446744073709551615 0 2297 344 832 18446744073709551615 0 1436 49 365 18446744073709551615 0 2114 1987 481 18446744073709551615 0 1972 360 1057 18446744073709551615 0 1829 927 296 18446744073709551615 0 1660 279 1512 18446744073709551615 0 343 1390 534 18446744073709551615 0 1300 1322 1521 18446744073709551615 0 137 1931 1764 18446744073709551615 0 1441 1100 162 18446744073709551615 0 2426 1017 1405 18446744073709551615 0 1350 2200 281 18446744073709551615 0 2021 2451 1554 18446744073709551615 0 1157 1783 1106 18446744073709551615 0 1727 2461 1197 18446744073709551615 0 1044 918 1522 18446744073709551615 0 944 980 1294 18446744073709551615 0 2049 1386 699 18446744073709551615 0 2345 1260 2115 18446744073709551615 0 1142 2457 460 18446744073709551615 0 1377 2116 1514 18446744073709551615 0 1408 533 1986 18446744073709551615 0 937 2383 151 18446744073709551615 0 1094 2324 2118 18446744073709551615 0 1835 2209 2020 18446744073709551615 0 656 1688 2092 18446744073709551615 0 1492 2318 1862 18446744073709551615 0 1097 517 1381 18446744073709551615 0 719 456 1324 18446744073709551615 0 1413 2235 2287 18446744073709551615 0 2444 1674 1815 18446744073709551615 0 2464 785 633 18446744073709551615 0 864 2112 2313 18446744073709551615 0 1295 2203 392 18446744073709551615 0 33 1302 1183 18446744073709551615 0 2359 2306 463 18446744073709551615 0 1961 1410 1024 18446744073709551615 0 524 1344 55 18446744073709551615 0 2358 23 1111 18446744073709551615 0 309 504 2370 18446744073709551615 0 666 1869 257 18446744073709551615 0 1724 1238 1641 18446744073709551615 0 614 1562 1580 18446744073709551615 0 41 1632 2247 18446744073709551615 0 2317 13 1182 18446744073709551615 0 604 571 1582 18446744073709551615 0 1241 52 2394 18446744073709551615 0 940 391 1927 18446744073709551615 0 967 254 1255 18446744073709551615 0 1280 1849 562 18446744073709551615 0 808 320 1440 18446744073709551615 0 667 1672 1049 18446744073709551615 0 682 1850 319 18446744073709551615 0 315 986 408 18446744073709551615 0 2378 152 654 18446744073709551615 0 2074 753 1775 18446744073709551615 0 941 369 1451 1 1591 447 1120 1418 1510 1363 1290 18446744073709551615 0 2046 43 1303 18446744073709551615 0 636 1882 2348 1 637 1068 1305 817 846 848 879 18446744073709551615 0 1705 974 1009 18446744073709551615 0 375 1759 223 1 1941 2034 1285 1383 607 2063 1863 18446744073709551615 366 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 0 9 14 19 24 33 38 43 48 57 62 67 72 77 82 87 92 97 102 107 112 117 122 127 132 137 142 147 152 157 162 167 172 177 182 187 192 197 202 207 212 217 222 227 232 237 242 247 252 257 262 267 272 277 282 287 292 297 302 307 312 317 322 327 332 337 342 347 352 357 362 367 372 377 382 387 392 397 402 407 412 417 422 427 432 437 442 447 452 457 462 467 472 477 482 487 492 497 502 507 512 517 522 527 532 537 542 547 552 565 570 583 588 593 598 603 608 613 618 623 628 633 638 643 648 661 666 679 684 689 694 699 704 709 714 719 724 729 734 739 744 757 762 775 780 785 790 795 800 805 810 815 820 825 830 835 840 845 850 855 860 865 870 875 880 885 890 895 900 905 910 915 920 925 930 935 940 945 950 955 960 965 970 975 980 985 990 995 1000 1005 1010 1015 1020 1025 1030 1035 1040 1045 1050 1055 1060 1065 1070 1075 1080 1085 1090 1095 1100 1105 1110 1115 1120 1125 1130 1135 1140 1145 1150 1155 1160 1165 1170 1175 1180 1185 1190 1195 1200 1205 1210 1215 1220 1225 1230 1235 1240 1245 1250 1255 1260 1265 1270 1275 1280 1285 1290 1295 1300 1305 1310 1315 1320 1325 1330 1335 1340 1345 1350 1355 1360 1365 1370 1375 1380 1385 1390 1395 1400 1405 1410 1415 1420 1425 1430 1435 1440 1445 1450 1455 1460 1465 1470 1475 1480 1485 1490 1495 1500 1505 1510 1515 1520 1525 1530 1535 1548 1553 1566 1571 0 0 1272 0 1 2127 2120 751 715 2066 1511 2213 724 1567 165 1178 2255 285 18446744073709551615 0 401 651 1896 1 122 2413 860 1249 1878 2154 500 976 1035 1343 641 2373 2416 18446744073709551615 1 1406 1200 2465 2110 497 1997 1140 1904 1266 1525 2279 284 1965 18446744073709551615 0 1096 653 396 1 713 797 1680 849 1416 1642 2124 1368 1940 1748 441 1787 1497 18446744073709551615 1 2103 1595 1647 1694 1439 240 187 1059 340 156 298 570 1630 18446744073709551615 0 435 642 11 1 1675 1774 634 536 548 776 1297 1741 1187 1083 1321 219 1577 18446744073709551615 0 1944 1456 932 18446744073709551615 0 1093 1007 1299 18446744073709551615 0 1279 886 1004 18446744073709551615 0 2128 947 655 18446744073709551615 0 1654 2195 1339 18446744073709551615 0 793 1236 1651 18446744073709551615 0 660 1646 1616 18446744073709551615 0 1767 2 899 18446744073709551615 0 513 1937 1228 18446744073709551615 0 576 1638 573 18446744073709551615 0 1690 1045 302 18446744073709551615 0 426 1773 842 18446744073709551615 0 2125 700 1202 18446744073709551615 0 798 1066 857 18446744073709551615 0 861 68 1509 18446744073709551615 0 1963 2007 1877 18446744073709551615 0 2336 188 1707 18446744073709551615 0 2250 2041 2417 18446744073709551615 0 1499 2123 1391 18446744073709551615 0 1682 1685 171 18446744073709551615 0 703 312 2162 18446744073709551615 0 149 457 2221 18446744073709551615 0 1220 1507 1936 18446744073709551615 0 1326 606 1613 18446744073709551615 0 496 752 1834 18446744073709551615 0 367 1338 218 18446744073709551615 0 1432 1360 823 18446744073709551615 0 1696 1337 1108 18446744073709551615 0 2108 1771 1932 18446744073709551615 0 1795 809 2439 18446744073709551615 0 508 625 1588 18446744073709551615 0 351 794 999 18446744073709551615 0 2150 1366 566 18446744073709551615 0 1275 1843 1246 18446744073709551615 0 1565 100 1576 18446744073709551615 0 1644 1084 1980 18446744073709551615 0 2054 370 2385 18446744073709551615 0 61 930 1203 18446744073709551615 0 45 624 467 18446744073709551615 0 2197 1715 1677 18446744073709551615 0 2396 2342 1894 18446744073709551615 0 676 2003 327 18446744073709551615 0 483 2055 696 18446744073709551615 0 305 1807 915 18446744073709551615 0 582 1274 1168 18446744073709551615 0 1221 2323 2025 18446744073709551615 0 6 966 1333 18446744073709551615 0 1010 1447 749 18446744073709551615 0 1401 338 202 18446744073709551615 0 806 1922 1857 18446744073709551615 0 436 2059 2305 18446744073709551615 0 1586 132 2073 18446744073709551615 0 618 813 485 18446744073709551615 0 1091 1469 901 18446744073709551615 0 1768 2375 995 18446744073709551615 0 1860 1247 632 18446744073709551615 0 2142 2407 236 18446744073709551615 0 1474 235 2453 18446744073709551615 0 1335 669 1650 18446744073709551615 0 1042 2425 1891 18446744073709551615 0 2204 2397 764 18446744073709551615 0 1473 952 256 18446744073709551615 0 453 1702 498 18446744073709551615 0 399 1751 2102 18446744073709551615 0 2164 2192 1730 18446744073709551615 0 2130 781 1854 18446744073709551615 0 956 592 612 18446744073709551615 0 197 2339 1802 18446744073709551615 0 1261 783 716 18446744073709551615 0 679 747 1837 18446744073709551615 0 316 313 1314 18446744073709551615 0 1201 1132 883 18446744073709551615 0 1031 1822 1055 18446744073709551615 0 890 1163 1374 18446744073709551615 0 295 1738 1547 18446744073709551615 0 358 2184 1915 18446744073709551615 0 2227 272 1659 18446744073709551615 0 796 1820 1872 18446744073709551615 0 416 638 822 18446744073709551615 0 419 2377 687 18446744073709551615 0 1550 2079 77 18446744073709551615 0 1962 1826 1150 18446744073709551615 0 691 2326 2138 18446744073709551615 0 1968 274 2289 18446744073709551615 0 2113 19 1328 18446744073709551615 0 414 2078 895 18446744073709551615 0 1030 647 232 18446744073709551615 0 384 1602 742 18446744073709551615 0 1589 1575 26 18446744073709551615 0 558 1230 69 18446744073709551615 0 17 1050 1365 18446744073709551615 0 951 1033 350 18446744073709551615 0 2077 701 2169 18446744073709551615 0 1186 1403 1621 18446744073709551615 0 875 588 398 18446744073709551615 0 425 465 1196 18446744073709551615 0 1394 1584 58 18446744073709551615 0 733 1259 509 18446744073709551615 0 2167 1991 2171 18446744073709551615 0 1903 1226 118 18446744073709551615 0 472 1945 1649 18446744073709551615 0 1914 1597 1640 18446744073709551615 0 1917 2163 471 18446744073709551615 0 90 1726 1117 18446744073709551615 0 1678 2047 2009 18446744073709551615 0 838 586 2131 18446744073709551615 0 2158 1909 559 18446744073709551615 0 157 1832 2096 18446744073709551615 0 761 2473 2086 18446744073709551615 0 664 1490 1734 18446744073709551615 0 1306 1133 433 18446744073709551615 0 2302 1750 92 18446744073709551615 0 1317 1361 46 18446744073709551615 0 1298 1883 1312 18446744073709551615 0 601 263 2369 18446744073709551615 0 1676 1251 1885 18446744073709551615 0 38 2421 110 18446744073709551615 0 492 1620 2303 18446744073709551615 0 2151 125 1718 18446744073709551615 0 331 2333 1948 18446744073709551615 0 1105 1396 324 18446744073709551615 0 2143 997 95 18446744073709551615 0 2286 729 2225 18446744073709551615 0 1505 710 241 18446744073709551615 0 681 1463 1206 18446744073709551615 0 253 2427 1158 18446744073709551615 0 1599 922 1967 18446744073709551615 0 1443 1378 1618 18446744073709551615 0 359 1480 176 18446744073709551615 0 2069 1080 458 18446744073709551615 0 1792 216 1336 18446744073709551615 0 51 505 1624 18446744073709551615 0 609 969 1627 18446744073709551615 0 2472 1340 1423 18446744073709551615 0 975 220 1148 18446744073709551615 0 1232 1008 1327 18446744073709551615 0 800 2242 36 18446744073709551615 0 342 880 269 18446744073709551615 0 2111 1151 153 18446744073709551615 0 244 2004 246 18446744073709551615 0 831 726 873 18446744073709551615 0 1225 1192 665 18446744073709551615 0 1533 1486 328 18446744073709551615 0 1021 1263 1786 18446744073709551615 0 2475 1720 62 18446744073709551615 0 348 2381 1905 18446744073709551615 0 2211 2027 777 18446744073709551615 0 928 79 812 18446744073709551615 0 407 2351 2319 18446744073709551615 0 515 1634 1523 18446744073709551615 0 758 2174 2387 18446744073709551615 0 1358 1411 1976 18446744073709551615 0 383 1504 1958 18446744073709551615 0 2337 1079 1681 18446744073709551615 0 1951 950 1257 18446744073709551615 0 490 488 1852 18446744073709551615 0 2470 1631 577 18446744073709551615 0 2038 1844 1078 18446744073709551615 0 1362 1388 1532 18446744073709551615 0 1866 2230 326 18446744073709551615 0 1555 1729 959 18446744073709551615 0 717 2238 1710 18446744073709551615 0 722 1349 2134 18446744073709551615 0 1219 1704 1137 18446744073709551615 0 2168 2226 646 18446744073709551615 0 2404 834 1036 18446744073709551615 0 301 1180 556 18446744073709551615 0 2356 2136 1993 18446744073709551615 0 2064 1762 1252 18446744073709551615 0 268 2222 142 18446744073709551615 0 2315 2462 1838 18446744073709551615 0 1769 181 769 18446744073709551615 0 451 2450 1559 18446744073709551615 0 2471 2188 102 18446744073709551615 0 2198 2349 136 18446744073709551615 0 1501 2429 1784 18446744073709551615 0 958 964 1791 18446744073709551615 0 1022 1152 2030 18446744073709551615 0 912 172 658 18446744073709551615 0 1370 663 31 18446744073709551615 0 2251 1628 2234 18446744073709551615 0 2068 466 661 18446744073709551615 0 1464 2291 619 18446744073709551615 0 1867 163 9 18446744073709551615 0 292 541 830 18446744073709551615 0 1003 2271 439 18446744073709551615 0 1625 1830 2101 18446744073709551615 0 1038 97 523 18446744073709551615 0 2214 158 1926 18446744073709551615 0 287 1955 1437 18446744073709551615 0 1301 538 978 18446744073709551615 0 409 1481 2145 18446744073709551615 0 2183 683 522 18446744073709551615 0 963 1912 1780 18446744073709551615 0 805 1006 626 18446744073709551615 0 1692 1345 954 18446744073709551615 0 2045 429 1985 18446744073709551615 0 770 1973 1939 18446744073709551615 0 1876 1430 780 18446744073709551615 0 1853 2135 1043 18446744073709551615 0 1282 2137 1269 18446744073709551615 0 1744 866 290 18446744073709551615 0 1453 489 1978 18446744073709551615 0 865 1782 1839 18446744073709551615 0 493 754 114 18446744073709551615 0 1873 1757 2353 18446744073709551615 0 1841 786 205 18446744073709551615 0 2206 1171 2180 18446744073709551615 0 2194 454 732 18446744073709551615 0 1956 1814 1765 18446744073709551615 0 346 1098 233 18446744073709551615 0 1687 728 127 18446744073709551615 0 620 1385 507 18446744073709551615 0 480 104 1943 18446744073709551615 0 1193 2152 2187 18446744073709551615 0 40 887 2411 18446744073709551615 0 0 1281 1346 18446744073709551615 0 299 1777 526 18446744073709551615 0 394 174 385 18446744073709551615 0 616 1415 2139 18446744073709551615 0 1145 1175 1600 18446744073709551615 0 1517 856 2435 18446744073709551615 0 564 993 1670 18446744073709551615 0 201 845 1116 18446744073709551615 0 1173 1165 1352 18446744073709551615 0 1037 170 2232 18446744073709551615 0 1330 1569 957 18446744073709551615 0 1356 885 1789 18446744073709551615 0 1907 2011 1797 18446744073709551615 0 1452 1315 2350 18446744073709551615 0 1181 528 1051 18446744073709551615 0 1816 230 1359 18446744073709551615 0 1691 1245 971 18446744073709551615 0 1129 1369 2256 18446744073709551615 282 0 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 4294967295 34 182 107 202 722 802 742 822 257 347 282 367 877 947 897 967 68 117 142 162 267 292 312 332 427 447 472 492 582 602 622 642 0 127 172 217 412 457 502 537 712 757 792 837 1012 1047 1082 1117 277 322 362 397 592 632 667 697 892 927 962 997 1167 1197 1227 1257 467 547 487 562 1057 1127 1072 1142 617 687 637 702 1187 1247 1202 1262 812 832 852 867 957 977 992 1007 1097 1112 1132 1147 1222 1237 1252 1267 662 677 692 707 517 532 552 567 357 377 392 407 192 212 232 247 917 987 932 1002 307 387 327 402 767 847 782 862 137 227 157 242 1032 1067 1102 1137 737 777 817 857 437 482 522 557 102 152 197 237 1207 1192 1177 1162 1232 1172 1217 1157 1242 1212 1182 1152 1077 1062 1042 1027 1107 1037 1092 1022 1122 1087 1052 1017 937 922 907 887 972 902 952 882 982 942 912 872 787 772 752 732 827 747 807 727 842 797 762 717 647 627 607 587 672 597 657 577 682 652 612 572 497 477 452 432 527 442 512 422 542 507 462 417 337 317 297 272 372 287 352 262 382 342 302 252 167 147 122 83 207 112 187 49 222 177 132 15 73 23 Policy::Sequential<3,3> DEAL::OK From 950cfca3abb5ba36505ed286f4ab2424bb2cb8f9 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Mon, 11 Mar 2019 09:48:48 -0400 Subject: [PATCH 245/507] enable lld linker if available --- cmake/checks/check_02_compiler_features.cmake | 28 +++++++++++++++---- doc/news/changes/minor/20190411TimoHeister | 3 ++ 2 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 doc/news/changes/minor/20190411TimoHeister diff --git a/cmake/checks/check_02_compiler_features.cmake b/cmake/checks/check_02_compiler_features.cmake index 7ac38fe19f3c..d108cc47672f 100644 --- a/cmake/checks/check_02_compiler_features.cmake +++ b/cmake/checks/check_02_compiler_features.cmake @@ -420,19 +420,33 @@ 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=lld") +CHECK_CXX_SOURCE_COMPILES( + " + int main() { return 0; } + " + DEAL_II_COMPILER_HAS_FUSE_LD_LLD) +RESET_CMAKE_REQUIRED() + IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Wno-unused-command-line-argument") ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Intel") @@ -446,7 +460,9 @@ CHECK_CXX_SOURCE_COMPILES( DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) RESET_CMAKE_REQUIRED() -IF(DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) +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() diff --git a/doc/news/changes/minor/20190411TimoHeister b/doc/news/changes/minor/20190411TimoHeister new file mode 100644 index 000000000000..db6c9bdafb94 --- /dev/null +++ b/doc/news/changes/minor/20190411TimoHeister @@ -0,0 +1,3 @@ +New: If present, we will detect the LLD linker ld.lld at configuration time. +
    +(Timo Heister, 2019/03/11) From ee9245435d37cdc5887f33c8656abe9ea24e33ef Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 11 Mar 2019 18:56:31 +0100 Subject: [PATCH 246/507] Fix warnings in Convert::to_pattern() --- include/deal.II/base/patterns.h | 46 ++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/include/deal.II/base/patterns.h b/include/deal.II/base/patterns.h index 3a8617fc91e0..bbb5b50adf6c 100644 --- a/include/deal.II/base/patterns.h +++ b/include/deal.II/base/patterns.h @@ -1493,22 +1493,38 @@ namespace Patterns struct Convert::value>::type> { - static std::unique_ptr - to_pattern() + template + static + typename std::enable_if::value && + std::is_same::value, + std::unique_ptr>::type + to_pattern() { - if (std::is_same::value) - return std_cxx14::make_unique(); - else if (std::is_integral::value) - return std_cxx14::make_unique( - static_cast(std::numeric_limits::lowest()), - static_cast(std::numeric_limits::max())); - else if (std::is_floating_point::value) - return std_cxx14::make_unique( - std::numeric_limits::lowest(), std::numeric_limits::max()); - - Assert(false, ExcNotImplemented()); - // the following line should never be invoked - return nullptr; + return std_cxx14::make_unique(); + } + + template + static + typename std::enable_if::value && + !std::is_same::value && + std::is_integral::value, + std::unique_ptr>::type + to_pattern() + { + return std_cxx14::make_unique( + std::numeric_limits::lowest(), std::numeric_limits::max()); + } + + template + static + typename std::enable_if::value && + !std::is_same::value && + std::is_floating_point::value, + std::unique_ptr>::type + to_pattern() + { + return std_cxx14::make_unique( + std::numeric_limits::lowest(), std::numeric_limits::max()); } static std::string From d21b2a9064356332ad81f905ae54d42f84b51ce6 Mon Sep 17 00:00:00 2001 From: David Wells Date: Mon, 11 Mar 2019 15:32:21 -0400 Subject: [PATCH 247/507] Excise remaining calls to VectorSlice. --- .../meshworker/vector_selector.templates.h | 49 +++++++++---------- source/lac/chunk_sparsity_pattern.cc | 2 +- source/lac/sparsity_pattern.cc | 2 +- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/include/deal.II/meshworker/vector_selector.templates.h b/include/deal.II/meshworker/vector_selector.templates.h index 1efeaa4852ea..acf92bac61b4 100644 --- a/include/deal.II/meshworker/vector_selector.templates.h +++ b/include/deal.II/meshworker/vector_selector.templates.h @@ -132,21 +132,21 @@ namespace MeshWorker for (unsigned int i = 0; i < this->n_values(); ++i) { const VectorType *src = data.read_ptr(this->value_index(i)); - VectorSlice>> - dst(values[i], component, n_comp); - fe.get_function_values(*src, make_slice(index, start, size), dst, true); + fe.get_function_values(*src, + make_array_view(index, start, size), + make_array_view(values[i], component, n_comp), + true); } for (unsigned int i = 0; i < this->n_gradients(); ++i) { const VectorType *src = data.read_ptr(this->gradient_index(i)); - VectorSlice>>> - dst(gradients[i], component, n_comp); fe.get_function_gradients(*src, - make_slice(index, start, size), - dst, + make_array_view(index, start, size), + make_array_view(gradients[i], + component, + n_comp), true); } @@ -154,12 +154,11 @@ namespace MeshWorker { const VectorType *src = data.read_ptr(this->hessian_index(i)); - VectorSlice>>> - dst(hessians[i], component, n_comp); fe.get_function_hessians(*src, - make_slice(index, start, size), - dst, + make_array_view(index, start, size), + make_array_view(hessians[i], + component, + n_comp), true); } } @@ -233,11 +232,9 @@ namespace MeshWorker { const MGLevelObject *src = data.read_ptr>(this->value_index(i)); - VectorSlice>> - dst(values[i], component, n_comp); fe.get_function_values((*src)[level], - make_slice(index, start, size), - dst, + make_array_view(index, start, size), + make_array_view(values[i], component, n_comp), true); } @@ -245,12 +242,11 @@ namespace MeshWorker { const MGLevelObject *src = data.read_ptr>(this->value_index(i)); - VectorSlice>>> - dst(gradients[i], component, n_comp); fe.get_function_gradients((*src)[level], - make_slice(index, start, size), - dst, + make_array_view(index, start, size), + make_array_view(gradients[i], + component, + n_comp), true); } @@ -258,12 +254,11 @@ namespace MeshWorker { const MGLevelObject *src = data.read_ptr>(this->value_index(i)); - VectorSlice>>> - dst(hessians[i], component, n_comp); fe.get_function_hessians((*src)[level], - make_slice(index, start, size), - dst, + make_array_view(index, start, size), + make_array_view(hessians[i], + component, + n_comp), true); } } diff --git a/source/lac/chunk_sparsity_pattern.cc b/source/lac/chunk_sparsity_pattern.cc index db9cc4bbe47b..836c5077e393 100644 --- a/source/lac/chunk_sparsity_pattern.cc +++ b/source/lac/chunk_sparsity_pattern.cc @@ -264,7 +264,7 @@ ChunkSparsityPattern::reinit(const size_type m, { Assert(chunk_size > 0, ExcInvalidNumber(chunk_size)); - reinit(m, n, make_slice(row_lengths), chunk_size); + reinit(m, n, make_array_view(row_lengths), chunk_size); } diff --git a/source/lac/sparsity_pattern.cc b/source/lac/sparsity_pattern.cc index 2eb565a4542d..0e747a27c1a0 100644 --- a/source/lac/sparsity_pattern.cc +++ b/source/lac/sparsity_pattern.cc @@ -605,7 +605,7 @@ SparsityPattern::reinit(const size_type m, const size_type n, const std::vector &row_lengths) { - reinit(m, n, make_slice(row_lengths)); + reinit(m, n, make_array_view(row_lengths)); } From 9853a35a8f31afeba27858cde01a20f104bfeafd Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sun, 10 Mar 2019 22:07:44 +0100 Subject: [PATCH 248/507] Rename a test --- .../{precondition_amg_dgp.cc => precondition_amg_dgp_01.cc} | 0 ...tput => precondition_amg_dgp_01.with_64bit_indices=off.output} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/trilinos/{precondition_amg_dgp.cc => precondition_amg_dgp_01.cc} (100%) rename tests/trilinos/{precondition_amg_dgp.with_64bit_indices=off.output => precondition_amg_dgp_01.with_64bit_indices=off.output} (100%) diff --git a/tests/trilinos/precondition_amg_dgp.cc b/tests/trilinos/precondition_amg_dgp_01.cc similarity index 100% rename from tests/trilinos/precondition_amg_dgp.cc rename to tests/trilinos/precondition_amg_dgp_01.cc diff --git a/tests/trilinos/precondition_amg_dgp.with_64bit_indices=off.output b/tests/trilinos/precondition_amg_dgp_01.with_64bit_indices=off.output similarity index 100% rename from tests/trilinos/precondition_amg_dgp.with_64bit_indices=off.output rename to tests/trilinos/precondition_amg_dgp_01.with_64bit_indices=off.output From 0f0f6ee19b351e1a943e52b5020ad6d338a67a2d Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Tue, 12 Mar 2019 09:35:07 +0100 Subject: [PATCH 249/507] Add useful methods to TrilinosWrappers::PreconditionAMG::AdditionalData. These include: - the initialization of a parameter list, which can be later modified by the user, and - the initialisation of the null space settings in an existing parameter list. --- .../changes/minor/20190310Jean-PaulPelteret-1 | 6 + include/deal.II/lac/trilinos_precondition.h | 72 +++++++++ source/lac/trilinos_precondition_ml.cc | 151 ++++++++++++------ 3 files changed, 180 insertions(+), 49 deletions(-) create mode 100644 doc/news/changes/minor/20190310Jean-PaulPelteret-1 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/include/deal.II/lac/trilinos_precondition.h b/include/deal.II/lac/trilinos_precondition.h index cb6d2ee11b62..aba329ce8a6e 100644 --- a/include/deal.II/lac/trilinos_precondition.h +++ b/include/deal.II/lac/trilinos_precondition.h @@ -34,6 +34,7 @@ # include # endif # include +# include # include # include # include @@ -1382,6 +1383,77 @@ namespace TrilinosWrappers const char * smoother_type = "Chebyshev", const char * coarse_type = "Amesos-KLU"); + /** + * Fill in a @p parameter_list that can be used to initialize the + * AMG preconditioner. + * + * The @p matrix is used in conjunction with the @p constant_modes to + * configure the null space settings for the preconditioner. + * The @p distributed_constant_modes are initialized by this function, and + * must remain in scope until PreconditionAMG::initialize() has been + * called. + * + * @note The set parameters reflect the current settings in this + * object, with various options being set both directly though the state + * of the member variables (e.g. the "smoother: type") as well as + * indirectly (e.g. the "aggregation: type"). If you wish to have + * fine-grained control over the configuration of the AMG preconditioner, + * then you can create the parameter list using this function (which + * conveniently sets the null space of the operator), change the relevant + * settings, and use the amended parameters list as an argument to + * PreconditionAMG::initialize(), instead of the AdditionalData object + * itself. + * + * See the documentation for the + * + * Trilinos ML package for details on what options are available for + * modification. + * + * @note Any user-defined parameters that are not in conflict with those + * set by this data structure will be retained. + */ + void + set_parameters( + Teuchos::ParameterList & parameter_list, + std::unique_ptr &distributed_constant_modes, + const Epetra_RowMatrix & matrix) const; + + /** + * Fill in a parameter list that can be used to initialize the + * AMG preconditioner. + * + * @note Any user-defined parameters that are not in conflict with those + * set by this data structure will be retained. + */ + void + set_parameters( + Teuchos::ParameterList & parameter_list, + std::unique_ptr &distributed_constant_modes, + const SparseMatrix & matrix) const; + + /** + * Configure the null space setting in the @p parameter_list for + * the input @p matrix based on the state of the @p constant_modes + * variable. + */ + void + set_operator_null_space( + Teuchos::ParameterList & parameter_list, + std::unique_ptr &distributed_constant_modes, + const Epetra_RowMatrix & matrix) const; + + /** + * Configure the null space setting in the @p parameter_list for + * the input @p matrix based on the state of the @p constant_modes + * variable. + */ + void + set_operator_null_space( + Teuchos::ParameterList & parameter_list, + std::unique_ptr &distributed_constant_modes, + const SparseMatrix & matrix) const; + /** * Determines whether the AMG preconditioner should be optimized for * elliptic problems (ML option smoothed aggregation SA, using a diff --git a/source/lac/trilinos_precondition_ml.cc b/source/lac/trilinos_precondition_ml.cc index 0375697c3920..848315efaa74 100644 --- a/source/lac/trilinos_precondition_ml.cc +++ b/source/lac/trilinos_precondition_ml.cc @@ -63,31 +63,14 @@ namespace TrilinosWrappers {} - PreconditionAMG::~PreconditionAMG() - { - preconditioner.reset(); - trilinos_matrix.reset(); - } - - void - PreconditionAMG::initialize(const SparseMatrix & matrix, - const AdditionalData &additional_data) - { - initialize(matrix.trilinos_matrix(), additional_data); - } - - - - void - PreconditionAMG::initialize(const Epetra_RowMatrix &matrix, - const AdditionalData & additional_data) + PreconditionAMG::AdditionalData::set_parameters( + Teuchos::ParameterList & parameter_list, + std::unique_ptr &distributed_constant_modes, + const Epetra_RowMatrix & matrix) const { - // Build the AMG preconditioner. - Teuchos::ParameterList parameter_list; - - if (additional_data.elliptic == true) + if (elliptic == true) { ML_Epetra::SetDefaults("SA", parameter_list); @@ -99,7 +82,7 @@ namespace TrilinosWrappers // standard choice uncoupled. if higher order, right now we also just // use Uncoupled, but we should be aware that maybe MIS might be // needed - if (additional_data.higher_order_elements) + if (higher_order_elements) parameter_list.set("aggregation: type", "Uncoupled"); } else @@ -109,8 +92,8 @@ namespace TrilinosWrappers parameter_list.set("aggregation: block scaling", true); } - parameter_list.set("smoother: type", additional_data.smoother_type); - parameter_list.set("coarse: type", additional_data.coarse_type); + parameter_list.set("smoother: type", smoother_type); + parameter_list.set("coarse: type", coarse_type); // Force re-initialization of the random seed to make ML deterministic // (only supported in trilinos >12.2): @@ -118,34 +101,43 @@ namespace TrilinosWrappers parameter_list.set("initialize random seed", true); # endif - parameter_list.set("smoother: sweeps", - static_cast(additional_data.smoother_sweeps)); - parameter_list.set("cycle applications", - static_cast(additional_data.n_cycles)); - if (additional_data.w_cycle == true) + parameter_list.set("smoother: sweeps", static_cast(smoother_sweeps)); + parameter_list.set("cycle applications", static_cast(n_cycles)); + if (w_cycle == true) parameter_list.set("prec type", "MGW"); else parameter_list.set("prec type", "MGV"); parameter_list.set("smoother: Chebyshev alpha", 10.); parameter_list.set("smoother: ifpack overlap", - static_cast(additional_data.smoother_overlap)); - parameter_list.set("aggregation: threshold", - additional_data.aggregation_threshold); + static_cast(smoother_overlap)); + parameter_list.set("aggregation: threshold", aggregation_threshold); parameter_list.set("coarse: max size", 2000); - if (additional_data.output_details) + if (output_details) parameter_list.set("ML output", 10); else parameter_list.set("ML output", 0); + set_operator_null_space(parameter_list, distributed_constant_modes, matrix); + } + + + + void + PreconditionAMG::AdditionalData::set_operator_null_space( + Teuchos::ParameterList & parameter_list, + std::unique_ptr &ptr_distributed_constant_modes, + const Epetra_RowMatrix & matrix) const + { const Epetra_Map &domain_map = matrix.OperatorDomainMap(); - const size_type constant_modes_dimension = - additional_data.constant_modes.size(); - Epetra_MultiVector distributed_constant_modes( - domain_map, constant_modes_dimension > 0 ? constant_modes_dimension : 1); - std::vector dummy(constant_modes_dimension); + const size_type constant_modes_dimension = constant_modes.size(); + ptr_distributed_constant_modes.reset(new Epetra_MultiVector( + domain_map, constant_modes_dimension > 0 ? constant_modes_dimension : 1)); + Assert(ptr_distributed_constant_modes, ExcNotInitialized()); + Epetra_MultiVector &distributed_constant_modes = + *ptr_distributed_constant_modes; if (constant_modes_dimension > 0) { @@ -159,7 +151,7 @@ namespace TrilinosWrappers TrilinosWrappers::global_length( distributed_constant_modes))); const bool constant_modes_are_global = - additional_data.constant_modes[0].size() == global_size; + constant_modes[0].size() == global_size; const size_type my_size = domain_map.NumMyElements(); // Reshape null space as a contiguous vector of doubles so that @@ -168,10 +160,9 @@ namespace TrilinosWrappers constant_modes_are_global ? global_size : my_size; for (size_type d = 0; d < constant_modes_dimension; ++d) { - Assert( - additional_data.constant_modes[d].size() == expected_mode_size, - ExcDimensionMismatch(additional_data.constant_modes[d].size(), - expected_mode_size)); + Assert(constant_modes[d].size() == expected_mode_size, + ExcDimensionMismatch(constant_modes[d].size(), + expected_mode_size)); for (size_type row = 0; row < my_size; ++row) { const TrilinosWrappers::types::int_type mode_index = @@ -179,7 +170,7 @@ namespace TrilinosWrappers TrilinosWrappers::global_index(domain_map, row) : row; distributed_constant_modes[d][row] = - additional_data.constant_modes[d][mode_index]; + constant_modes[d][mode_index]; } } (void)expected_mode_size; @@ -190,13 +181,75 @@ namespace TrilinosWrappers if (my_size > 0) parameter_list.set("null space: vectors", distributed_constant_modes.Values()); - // We need to set a valid pointer to data even if there is no data on - // the current processor. Therefore, pass a dummy in that case else - parameter_list.set("null space: vectors", dummy.data()); + { + // We need to set a valid pointer to data even if there is no data + // on the current processor. Therefore, pass a dummy in that case + static std::vector dummy; + if (dummy.size() != constant_modes_dimension) + dummy.resize(constant_modes_dimension); + parameter_list.set("null space: vectors", dummy.data()); + } } + } + + + + void + PreconditionAMG::AdditionalData::set_parameters( + Teuchos::ParameterList & parameter_list, + std::unique_ptr &distributed_constant_modes, + const SparseMatrix & matrix) const + { + return set_parameters(parameter_list, + distributed_constant_modes, + matrix.trilinos_matrix()); + } + + + + void + PreconditionAMG::AdditionalData::set_operator_null_space( + Teuchos::ParameterList & parameter_list, + std::unique_ptr &distributed_constant_modes, + const SparseMatrix & matrix) const + { + return set_operator_null_space(parameter_list, + distributed_constant_modes, + matrix.trilinos_matrix()); + } + + + + PreconditionAMG::~PreconditionAMG() + { + preconditioner.reset(); + trilinos_matrix.reset(); + } + + + + void + PreconditionAMG::initialize(const SparseMatrix & matrix, + const AdditionalData &additional_data) + { + initialize(matrix.trilinos_matrix(), additional_data); + } + + + + void + PreconditionAMG::initialize(const Epetra_RowMatrix &matrix, + const AdditionalData & additional_data) + { + // Build the AMG preconditioner. + Teuchos::ParameterList ml_parameters; + std::unique_ptr distributed_constant_modes; + additional_data.set_parameters(ml_parameters, + distributed_constant_modes, + matrix); - initialize(matrix, parameter_list); + initialize(matrix, ml_parameters); if (additional_data.output_details) { From df6e953a83aae7b3a3d5ba30b6771486312797a9 Mon Sep 17 00:00:00 2001 From: David Wells Date: Mon, 11 Mar 2019 15:35:27 -0400 Subject: [PATCH 250/507] Excise remaining inclusions of vector_slice.h. --- include/deal.II/fe/fe_values.h | 1 - include/deal.II/lac/chunk_sparsity_pattern.h | 1 - include/deal.II/meshworker/vector_selector.templates.h | 2 -- source/lac/block_sparsity_pattern.cc | 1 - source/lac/sparsity_pattern.cc | 1 - tests/integrators/advection_01.cc | 1 + tests/integrators/divergence_01.cc | 1 + tests/integrators/elasticity_01.cc | 1 + tests/integrators/elasticity_02.cc | 1 + tests/integrators/grad_div_01.cc | 1 + tests/integrators/laplacian_01.cc | 1 + 11 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/deal.II/fe/fe_values.h b/include/deal.II/fe/fe_values.h index 3e03139485d1..713f1c64adad 100644 --- a/include/deal.II/fe/fe_values.h +++ b/include/deal.II/fe/fe_values.h @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/include/deal.II/lac/chunk_sparsity_pattern.h b/include/deal.II/lac/chunk_sparsity_pattern.h index e958ecd89a54..a5e14d6de72d 100644 --- a/include/deal.II/lac/chunk_sparsity_pattern.h +++ b/include/deal.II/lac/chunk_sparsity_pattern.h @@ -21,7 +21,6 @@ #include #include -#include #include diff --git a/include/deal.II/meshworker/vector_selector.templates.h b/include/deal.II/meshworker/vector_selector.templates.h index acf92bac61b4..283edd873bc0 100644 --- a/include/deal.II/meshworker/vector_selector.templates.h +++ b/include/deal.II/meshworker/vector_selector.templates.h @@ -17,8 +17,6 @@ #define dealii_vector_selector_templates_h -#include - #include #include diff --git a/source/lac/block_sparsity_pattern.cc b/source/lac/block_sparsity_pattern.cc index de077a77a494..7cec15500db0 100644 --- a/source/lac/block_sparsity_pattern.cc +++ b/source/lac/block_sparsity_pattern.cc @@ -15,7 +15,6 @@ #include -#include #include diff --git a/source/lac/sparsity_pattern.cc b/source/lac/sparsity_pattern.cc index 0e747a27c1a0..6b4bb1a1f476 100644 --- a/source/lac/sparsity_pattern.cc +++ b/source/lac/sparsity_pattern.cc @@ -16,7 +16,6 @@ #include #include -#include #include #include diff --git a/tests/integrators/advection_01.cc b/tests/integrators/advection_01.cc index 44d11ab050ec..06e81f156156 100644 --- a/tests/integrators/advection_01.cc +++ b/tests/integrators/advection_01.cc @@ -16,6 +16,7 @@ // Test the functions in integrators/laplace.h // Output matrices and assert consistency of residuals +#include #include #include diff --git a/tests/integrators/divergence_01.cc b/tests/integrators/divergence_01.cc index 5df9cd73f716..8fec5dbb1442 100644 --- a/tests/integrators/divergence_01.cc +++ b/tests/integrators/divergence_01.cc @@ -16,6 +16,7 @@ // Test the functions in integrators/divergence.h // Output matrices and assert consistency of residuals +#include #include #include diff --git a/tests/integrators/elasticity_01.cc b/tests/integrators/elasticity_01.cc index 20cfaa40bf48..8e548adec15b 100644 --- a/tests/integrators/elasticity_01.cc +++ b/tests/integrators/elasticity_01.cc @@ -16,6 +16,7 @@ // Test the functions in integrators/elasticity.h // Output matrices and assert consistency of residuals +#include #include #include diff --git a/tests/integrators/elasticity_02.cc b/tests/integrators/elasticity_02.cc index 656f336d581d..723e15ecdd25 100644 --- a/tests/integrators/elasticity_02.cc +++ b/tests/integrators/elasticity_02.cc @@ -16,6 +16,7 @@ // Test nitsche_tangential in Elasticity // Output matrices and assert consistency of residuals +#include #include #include diff --git a/tests/integrators/grad_div_01.cc b/tests/integrators/grad_div_01.cc index 645294228716..8953f9ec92f8 100644 --- a/tests/integrators/grad_div_01.cc +++ b/tests/integrators/grad_div_01.cc @@ -16,6 +16,7 @@ // Test the functions in integrators/grad_div.h // Output matrices and assert consistency of residuals +#include #include #include diff --git a/tests/integrators/laplacian_01.cc b/tests/integrators/laplacian_01.cc index 2eb8a8cd534f..2e0dd1550640 100644 --- a/tests/integrators/laplacian_01.cc +++ b/tests/integrators/laplacian_01.cc @@ -16,6 +16,7 @@ // Test the functions in integrators/laplace.h // Output matrices and assert consistency of residuals +#include #include #include From d16e5bcfbd81ac9f1303b3cfda95b67374a1ce71 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Mon, 11 Mar 2019 22:59:07 -0600 Subject: [PATCH 251/507] Update documentation of class Vector. --- include/deal.II/lac/vector.h | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/include/deal.II/lac/vector.h b/include/deal.II/lac/vector.h index b413f686b129..5ba965853180 100644 --- a/include/deal.II/lac/vector.h +++ b/include/deal.II/lac/vector.h @@ -78,15 +78,22 @@ namespace parallel */ /** - * Numerical vector of data. For this class there are different types of - * functions available. The first type of function initializes the vector, - * changes its size, or computes the norm of the vector in order to measure - * its length in a suitable norm. The second type helps us to manipulate the - * components of the vector. The third type defines the algebraic operations - * for vectors, while the last type defines a few input and output functions. - * As opposed to the array of the C++ standard library called @p vector (with - * a lowercase "v"), this class implements an element of a vector space - * suitable for numerical computations. + * A class that represents a vector of numerical elements. As for the + * other classes, in the @ref Vectors group, this class has a substantial + * number of member functions. These include: + * - functions that initialize the vector or change its size; + * - functions that compute properties of the vector, such as a variety of + * norms; + * - functions that allow reading from or writing to individual elements of the + * vector; + * - functions that implement algebraic operations for vectors, such as + * addition of vectors; and + * - functions that allow inputting and outputting the data stored by vectors. + * + * In contrast to the C++ standard library class `std::vector`, this class + * intends to implement not simply an array that allows access to its elements, + * but indeed a vector that is a member of the mathematical concept of a + * "vector space" suitable for numerical computations. * * @note Instantiations for this template are provided for @, * @, @@>, @@>; From cf5d11dcc2e5cfdf6194be9c25e4edf27897224f Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 12 Mar 2019 17:02:16 +0100 Subject: [PATCH 252/507] Update allowed MSVC version in bundled boost --- .../boost-1.62.0/include/boost/config/compiler/visualc.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 2f9053427795e0c23bbc54a1d8fd003a3d251197 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 12 Mar 2019 21:35:11 +0100 Subject: [PATCH 253/507] Allow CXX14/17 autodetection for MSVC --- cmake/checks/check_01_cxx_features.cmake | 32 +++++++++++++++---- cmake/checks/check_02_compiler_features.cmake | 26 ++++++++++++--- cmake/configure/configure_2_boost.cmake | 6 +++- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/cmake/checks/check_01_cxx_features.cmake b/cmake/checks/check_01_cxx_features.cmake index bf1aedec3bee..1f71219af41f 100644 --- a/cmake/checks/check_01_cxx_features.cmake +++ b/cmake/checks/check_01_cxx_features.cmake @@ -99,10 +99,17 @@ 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}") - ENDIF() + 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 +133,12 @@ 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") + IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX /EHsc") + ELSE() + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") + ENDIF() + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_VERSION_FLAG}") UNSET_IF_CHANGED(CHECK_CXX_FEATURES_FLAGS_CXX17_SAVED "${CMAKE_REQUIRED_FLAGS}${DEAL_II_CXX_VERSION_FLAG}" @@ -512,6 +524,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 +542,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 +586,11 @@ 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") +IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX") +ELSE() + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror -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 d108cc47672f..d7d7c8321893 100644 --- a/cmake/checks/check_02_compiler_features.cmake +++ b/cmake/checks/check_02_compiler_features.cmake @@ -298,7 +298,11 @@ 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") +IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX") +ELSE() + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror -Wno-unused-command-line-argument") +ENDIF() # first see if the compiler accepts the attribute CHECK_CXX_SOURCE_COMPILES( @@ -405,7 +409,11 @@ ENDIF() # # - Matthias Maier, 2015 # -ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") +IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX") +ELSE() + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") +ENDIF() CHECK_CXX_SOURCE_COMPILES( " _Pragma(\"GCC diagnostic push\") @@ -439,7 +447,12 @@ IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Intel") ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-diag-error warn") ENDIF() -ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror -fuse-ld=lld") +IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX") +ELSE() + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") +ENDIF() +ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-fuse-ld=lld") CHECK_CXX_SOURCE_COMPILES( " int main() { return 0; } @@ -452,7 +465,12 @@ IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 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") +IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX") +ELSE() + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") +ENDIF() +ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-fuse-ld=gold") CHECK_CXX_SOURCE_COMPILES( " int main() { return 0; } diff --git a/cmake/configure/configure_2_boost.cmake b/cmake/configure/configure_2_boost.cmake index 5c6f9c35a806..1b5988fc8f36 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") + ELSE() + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") + ENDIF() CHECK_CXX_SOURCE_COMPILES( " From 2876a2686c53ae96e215226c7f8104e413e628cb Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 13 Mar 2019 09:56:12 +0100 Subject: [PATCH 254/507] Avoid tabs and don't test for alternative linker with MSVC --- cmake/checks/check_01_cxx_features.cmake | 6 +- cmake/checks/check_02_compiler_features.cmake | 67 +++++++++---------- cmake/configure/configure_2_boost.cmake | 2 +- 3 files changed, 34 insertions(+), 41 deletions(-) diff --git a/cmake/checks/check_01_cxx_features.cmake b/cmake/checks/check_01_cxx_features.cmake index 1f71219af41f..2f5cf61e7efc 100644 --- a/cmake/checks/check_01_cxx_features.cmake +++ b/cmake/checks/check_01_cxx_features.cmake @@ -104,12 +104,12 @@ MACRO(_check_cxx_flag _suffix) IF(DEAL_II_HAVE_FLAG_stdcxx${_suffix}) SET(DEAL_II_CXX_VERSION_FLAG "/std:c++${_suffix}") ENDIF() - ELSE() + 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() ENDIF() ENDMACRO() @@ -542,7 +542,7 @@ CHECK_CXX_SOURCE_COMPILES( } " DEAL_II_COMPILER_DEFAULTS_TO_CXX11_OR_NEWER) - RESET_CMAKE_REQUIRED() +RESET_CMAKE_REQUIRED() IF(_user_provided_cxx_version_flag OR NOT DEAL_II_COMPILER_DEFAULTS_TO_CXX11_OR_NEWER OR diff --git a/cmake/checks/check_02_compiler_features.cmake b/cmake/checks/check_02_compiler_features.cmake index d7d7c8321893..e844e7d904dc 100644 --- a/cmake/checks/check_02_compiler_features.cmake +++ b/cmake/checks/check_02_compiler_features.cmake @@ -442,45 +442,38 @@ RESET_CMAKE_REQUIRED() # # 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() -IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX") -ELSE() +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") -ENDIF() -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() + 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(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() -IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX") -ELSE() + 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") -ENDIF() -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() + 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") + 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/configure/configure_2_boost.cmake b/cmake/configure/configure_2_boost.cmake index 1b5988fc8f36..1637b16695c8 100644 --- a/cmake/configure/configure_2_boost.cmake +++ b/cmake/configure/configure_2_boost.cmake @@ -59,7 +59,7 @@ MACRO(FEATURE_BOOST_CONFIGURE_COMMON) # circumvent the issue. Hence, we just check ourselves. ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_VERSION_FLAG}") IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX") + ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX /EHsc") ELSE() ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") ENDIF() From 632294e2abf0c86b550e8c5f8875edd1aa0c7407 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 13 Mar 2019 10:28:23 +0100 Subject: [PATCH 255/507] Replace '-Werror' by a _werror_flag variable --- cmake/checks/check_01_cxx_features.cmake | 25 +++++++++++-------- cmake/checks/check_02_compiler_features.cmake | 22 +++++++++------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/cmake/checks/check_01_cxx_features.cmake b/cmake/checks/check_01_cxx_features.cmake index 2f5cf61e7efc..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: # @@ -133,12 +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}\"") - IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX /EHsc") - ELSE() - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") - ENDIF() - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_VERSION_FLAG}") + 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}" @@ -586,10 +592,9 @@ UNSET_IF_CHANGED(CHECK_CXX_FEATURES_FLAGS_SAVED # possibilities here. # ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_FLAGS}") -IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX") -ELSE() - 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 e844e7d904dc..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,10 +307,9 @@ ENDIF() # "warning #1292: unknown attribute "deprecated"" (icc) # Hence, we treat warnings as errors: ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_FLAGS}") -IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX") -ELSE() - 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 @@ -409,11 +417,7 @@ ENDIF() # # - Matthias Maier, 2015 # -IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "/WX") -ELSE() - ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror") -ENDIF() +ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${_werror_flag}") CHECK_CXX_SOURCE_COMPILES( " _Pragma(\"GCC diagnostic push\") From 6225139ff3ef6273575d57656bad05827d62df62 Mon Sep 17 00:00:00 2001 From: Martin Kronbichler Date: Wed, 13 Mar 2019 17:16:04 +0100 Subject: [PATCH 256/507] Fix MatrixFree::loop() for the case where VectorType is not a vector --- include/deal.II/matrix_free/matrix_free.h | 23 ++++++++++++++++---- source/matrix_free/task_info.cc | 1 + tests/matrix_free/matrix_free_type_traits.cc | 11 ++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/include/deal.II/matrix_free/matrix_free.h b/include/deal.II/matrix_free/matrix_free.h index 4877be670b78..65a2f533f5f8 100644 --- a/include/deal.II/matrix_free/matrix_free.h +++ b/include/deal.II/matrix_free/matrix_free.h @@ -1436,7 +1436,6 @@ class MatrixFree : public Subscriptor * Queries whether or not the geometry-related information for the cells has * been set. */ - bool mapping_initialized() const; @@ -3321,13 +3320,15 @@ namespace internal /** - * Zero out vector region for vector that do _not_ support - * exchange on a subset of DoFs <==> begin() + ind == local_element(ind) + * Zero out vector region for vector that do _not_ support exchange on a + * subset of DoFs <==> begin() + ind == local_element(ind) but are still a + * vector type */ template < typename VectorType, typename std::enable_if::value, - VectorType>::type * = nullptr> + VectorType>::type * = nullptr, + typename VectorType::value_type * = nullptr> void zero_vector_region(const unsigned int range_index, VectorType &vec) const { @@ -3341,6 +3342,20 @@ namespace internal + /** + * Zero out vector region for non-vector types, i.e., classes that do not + * have VectorType::value_type + */ + void + zero_vector_region(const unsigned int, ...) const + { + Assert(false, + ExcNotImplemented("Zeroing is only implemented for vector types " + "which provide VectorType::value_type")); + } + + + const dealii::MatrixFree &matrix_free; const typename dealii::MatrixFree::DataAccessOnFaces vector_face_access; diff --git a/source/matrix_free/task_info.cc b/source/matrix_free/task_info.cc index d60db786c86b..203fcad6ea72 100644 --- a/source/matrix_free/task_info.cc +++ b/source/matrix_free/task_info.cc @@ -631,6 +631,7 @@ namespace internal n_blocks = 0; scheme = none; partition_row_index.clear(); + partition_row_index.resize(2); cell_partition_data.clear(); face_partition_data.clear(); boundary_partition_data.clear(); diff --git a/tests/matrix_free/matrix_free_type_traits.cc b/tests/matrix_free/matrix_free_type_traits.cc index fb0f597c0c64..4ea0771d0bd2 100644 --- a/tests/matrix_free/matrix_free_type_traits.cc +++ b/tests/matrix_free/matrix_free_type_traits.cc @@ -90,5 +90,16 @@ main() << "unsigned int = " << internal::is_serial_or_dummy::value << std::endl; + // check that MatrixFree::cell_loop can run for non-vector types + MatrixFree<2> matrix_free; + int dummy = 0; + matrix_free.cell_loop( + std::function &, + int &, + const int &, + const std::pair &)>(), + dummy, + dummy); + deallog << "OK" << std::endl; } From 266a351d3a4ce16bfeb2b0ad9f7d302d2877dea9 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Wed, 13 Mar 2019 15:39:56 +0100 Subject: [PATCH 257/507] remove unneeded assert in internal::update_ghost_values_finish() --- include/deal.II/matrix_free/matrix_free.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/deal.II/matrix_free/matrix_free.h b/include/deal.II/matrix_free/matrix_free.h index 4877be670b78..ed477fd6cfa7 100644 --- a/include/deal.II/matrix_free/matrix_free.h +++ b/include/deal.II/matrix_free/matrix_free.h @@ -2897,12 +2897,6 @@ namespace internal const VectorType & vec) { (void)component_in_block_vector; - Assert( - (vector_face_access == - dealii::MatrixFree::DataAccessOnFaces::unspecified || - vec.size() == 0), - ExcNotImplemented()); - vec.update_ghost_values_finish(); } From 6bda43589a278cb5e2a20ce0698744341c9ab394 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Wed, 13 Mar 2019 12:26:27 -0600 Subject: [PATCH 258/507] Improve the error text of an assertion. --- include/deal.II/numerics/vector_tools.templates.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/deal.II/numerics/vector_tools.templates.h b/include/deal.II/numerics/vector_tools.templates.h index aebdafb33768..5e024874eb18 100644 --- a/include/deal.II/numerics/vector_tools.templates.h +++ b/include/deal.II/numerics/vector_tools.templates.h @@ -2947,7 +2947,12 @@ namespace VectorTools ExcMessage( "This function can only deal with requested boundary " "values that correspond to primitive (scalar) base " - "elements")); + "elements. You may want to look up in the deal.II " + "glossary what the term 'primitive' means." + "\n\n" + "There are alternative boundary value interpolation " + "functions in namespace 'VectorTools' that you can " + "use for non-primitive finite elements.")); } const typename DoFHandlerType::face_iterator From 1d929dd41a003e0131d24040d659e30315c5cf88 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 13 Mar 2019 17:25:57 +0100 Subject: [PATCH 259/507] Fix compiling bundled boost with MSVC and C++17 --- .../include/boost/algorithm/cxx14/equal.hpp | 3 +- .../algorithm/string/detail/case_conv.hpp | 8 ++- .../boost/algorithm/string/detail/util.hpp | 5 +- .../boost/config/stdlib/dinkumware.hpp | 2 +- .../boost/function/function_template.hpp | 11 ---- .../boost-1.62.0/include/boost/functional.hpp | 58 ++++++++++++++----- .../boost/functional/hash/extensions.hpp | 9 ++- .../include/boost/functional/hash/hash.hpp | 12 ++-- .../include/boost/graph/astar_search.hpp | 5 +- .../include/boost/graph/detail/geodesic.hpp | 12 ++-- .../crauser_et_al_shortest_paths.hpp | 10 +++- .../boost/graph/parallel/algorithm.hpp | 15 ++++- .../boost/graph/transitive_closure.hpp | 3 +- .../include/boost/iostreams/chain.hpp | 5 +- .../numeric/conversion/detail/converter.hpp | 15 +---- .../boost/signals2/detail/signal_template.hpp | 1 - .../signals2/detail/signals_common_macros.hpp | 6 +- .../boost/signals2/detail/slot_template.hpp | 2 +- .../signals2/detail/variadic_arg_type.hpp | 19 +++--- .../include/boost/smart_ptr/owner_less.hpp | 49 +++++----------- .../include/boost/typeof/std/functional.hpp | 2 + .../boost/utility/compare_pointees.hpp | 13 ++++- 22 files changed, 147 insertions(+), 118 deletions(-) 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/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) ; } } ; From 95f6e6068ff5675aba5f814942550fcaff23fdec Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 14 Mar 2019 09:54:01 +0100 Subject: [PATCH 260/507] Add CMake module and configuration files for SymEngine --- cmake/configure/configure_symengine.cmake | 41 +++++++ cmake/modules/FindSYMENGINE.cmake | 129 ++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 cmake/configure/configure_symengine.cmake create mode 100644 cmake/modules/FindSYMENGINE.cmake diff --git a/cmake/configure/configure_symengine.cmake b/cmake/configure/configure_symengine.cmake new file mode 100644 index 000000000000..4867772178fe --- /dev/null +++ b/cmake/configure/configure_symengine.cmake @@ -0,0 +1,41 @@ +## --------------------------------------------------------------------- +## +## 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: +# + +# +# We require at least version 0.3 of the symengine library: +# +SET(SYMENGINE_MINIMUM_REQUIRED_VERSION "0.3") + + +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_DEBUG) + SET(SYMENGINE_CXX_FLAGS_RELEASE) +ENDMACRO() + + +CONFIGURE_FEATURE(SYMENGINE) diff --git a/cmake/modules/FindSYMENGINE.cmake b/cmake/modules/FindSYMENGINE.cmake new file mode 100644 index 000000000000..4b7468f9eca8 --- /dev/null +++ b/cmake/modules/FindSYMENGINE.cmake @@ -0,0 +1,129 @@ +## --------------------------------------------------------------------- +## +## 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 ${SYMENGINE_MINIMUM_REQUIRED_VERSION} + 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_MAJOR}.${SYMENGINE_VERSION_MINOR}.${SYMENGINE_VERSION_PATCH}" + ) +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) + +SET(_symengine_libraries ${SYMENGINE_LIBRARIES}) + + +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 +) From e3a394d4e47307036dddd0cc3db5bedc8424019c Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 14 Mar 2019 19:06:29 +0100 Subject: [PATCH 261/507] Fix 'test' target for MSVC --- tests/quick_tests/CMakeLists.txt | 6 +++--- tests/quick_tests/run.cmake | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/quick_tests/CMakeLists.txt b/tests/quick_tests/CMakeLists.txt index f76cfc008b7a..8393f3ed1c38 100644 --- a/tests/quick_tests/CMakeLists.txt +++ b/tests/quick_tests/CMakeLists.txt @@ -44,9 +44,9 @@ MACRO(make_quicktest test_basename build_name mpi_run) DEAL_II_INSOURCE_SETUP_TARGET(${_target} ${build_name}) IF("${mpi_run}" STREQUAL "") - SET(_command ./${_target}) + SET(_command ${_target}) ELSE() - SET(_command ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${mpi_run} ${MPIEXEC_PREFLAGS} ./${_target}) + SET(_command ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${mpi_run} ${MPIEXEC_PREFLAGS} ${_target}) ENDIF() ADD_CUSTOM_TARGET(${_target}.run DEPENDS ${_target} @@ -195,7 +195,7 @@ ENDIF() # A custom test target: ADD_CUSTOM_TARGET(test - COMMAND ${CMAKE_COMMAND} -D ALL_TESTS="${ALL_TESTS}" -P ${CMAKE_CURRENT_SOURCE_DIR}/run.cmake + COMMAND ${CMAKE_COMMAND} -D ALL_TESTS="${ALL_TESTS}" -DCMAKE_BUILD_TYPE=${_mybuild} -P ${CMAKE_CURRENT_SOURCE_DIR}/run.cmake WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Running quicktests..." ) diff --git a/tests/quick_tests/run.cmake b/tests/quick_tests/run.cmake index 4e4c21299836..ab6e7fc80626 100644 --- a/tests/quick_tests/run.cmake +++ b/tests/quick_tests/run.cmake @@ -25,6 +25,7 @@ ENDIF() SEPARATE_ARGUMENTS(ALL_TESTS) EXECUTE_PROCESS(COMMAND ${CMAKE_CTEST_COMMAND} -j${_n_processors} + -C ${CMAKE_BUILD_TYPE} --force-new-ctest-process --output-on-failure -O quicktests.log From 9f73b559112557765bb53f9b288158040cae697e Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Tue, 12 Mar 2019 09:32:28 -0400 Subject: [PATCH 262/507] Encapsulate the calls to tbb::parallel_for --- include/deal.II/base/parallel.h | 75 +++++++++++++------ include/deal.II/base/work_stream.h | 9 +-- .../deal.II/lac/vector_operations_internal.h | 12 +-- 3 files changed, 61 insertions(+), 35 deletions(-) diff --git a/include/deal.II/base/parallel.h b/include/deal.II/base/parallel.h index 9f82c1175025..d9db08f5acd5 100644 --- a/include/deal.II/base/parallel.h +++ b/include/deal.II/base/parallel.h @@ -131,6 +131,7 @@ namespace parallel }; + /** * Take a function object and create a Body object from it. We do this in * this helper function since alternatively we would have to specify the @@ -143,6 +144,41 @@ namespace parallel { return Body(f); } + + + + /** + * Encapsulate tbb::parallel_for. + */ + template + void + parallel_for(Iterator x_begin, + Iterator x_end, + const Functor & functor, + const unsigned int grainsize) + { + tbb::parallel_for(tbb::blocked_range(x_begin, x_end, grainsize), + functor, + tbb::auto_partitioner()); + } + + + + /** + * Encapsulate tbb::parallel_for when an affinite_partitioner is provided. + */ + template + void + parallel_for(Iterator x_begin, + Iterator x_end, + const Functor & functor, + const unsigned int grainsize, + const std::shared_ptr &partitioner) + { + tbb::parallel_for(tbb::blocked_range(x_begin, x_end, grainsize), + functor, + *partitioner); + } } // namespace internal /** @@ -188,11 +224,10 @@ namespace parallel using SyncIterators = SynchronousIterators; Iterators x_begin(begin_in, out); Iterators x_end(end_in, OutputIterator()); - tbb::parallel_for(tbb::blocked_range(x_begin, - x_end, - grainsize), - internal::make_body(predicate), - tbb::auto_partitioner()); + internal::parallel_for(SyncIterators(x_begin), + SyncIterators(x_end), + internal::make_body(predicate), + grainsize); #endif } @@ -246,11 +281,10 @@ namespace parallel using SyncIterators = SynchronousIterators; Iterators x_begin(begin_in1, in2, out); Iterators x_end(end_in1, InputIterator2(), OutputIterator()); - tbb::parallel_for(tbb::blocked_range(x_begin, - x_end, - grainsize), - internal::make_body(predicate), - tbb::auto_partitioner()); + internal::parallel_for(SyncIterators(x_begin), + SyncIterators(x_end), + internal::make_body(predicate), + grainsize); #endif } @@ -309,11 +343,10 @@ namespace parallel InputIterator2(), InputIterator3(), OutputIterator()); - tbb::parallel_for(tbb::blocked_range(x_begin, - x_end, - grainsize), - internal::make_body(predicate), - tbb::auto_partitioner()); + internal::parallel_for(SyncIterators(x_begin), + SyncIterators(x_end), + internal::make_body(predicate), + grainsize); #endif } @@ -428,12 +461,13 @@ namespace parallel ff(begin, end); # endif #else - tbb::parallel_for( - tbb::blocked_range(begin, end, grainsize), + internal::parallel_for( + begin, + end, std::bind(&internal::apply_to_subranges, std::placeholders::_1, std::cref(f)), - tbb::auto_partitioner()); + grainsize); #endif } @@ -826,10 +860,7 @@ namespace parallel apply_to_subrange(begin, end); #else internal::ParallelForWrapper worker(*this); - tbb::parallel_for( - tbb::blocked_range(begin, end, minimum_parallel_grain_size), - worker, - tbb::auto_partitioner()); + internal::parallel_for(begin, end, worker, minimum_parallel_grain_size); #endif } diff --git a/include/deal.II/base/work_stream.h b/include/deal.II/base/work_stream.h index b09c2d1fdfb4..555c35c98da7 100644 --- a/include/deal.II/base/work_stream.h +++ b/include/deal.II/base/work_stream.h @@ -1154,14 +1154,13 @@ namespace WorkStream sample_scratch_data, sample_copy_data); - tbb::parallel_for( - tbb::blocked_range(colored_iterators[color].begin(), - colored_iterators[color].end(), - /*grain_size=*/chunk_size), + parallel::internal::parallel_for( + colored_iterators[color].begin(), + colored_iterators[color].end(), std::bind(&WorkerAndCopier::operator(), std::ref(worker_and_copier), std::placeholders::_1), - tbb::auto_partitioner()); + chunk_size); } } # endif diff --git a/include/deal.II/lac/vector_operations_internal.h b/include/deal.II/lac/vector_operations_internal.h index 5d98e3f23a6b..bd13406faac5 100644 --- a/include/deal.II/lac/vector_operations_internal.h +++ b/include/deal.II/lac/vector_operations_internal.h @@ -188,10 +188,8 @@ namespace internal partitioner->acquire_one_partitioner(); TBBForFunctor generic_functor(functor, start, end); - tbb::parallel_for( - tbb::blocked_range(0, generic_functor.n_chunks, 1), - generic_functor, - *tbb_partitioner); + parallel::internal::parallel_for( + 0U, generic_functor.n_chunks, generic_functor, 1, tbb_partitioner); partitioner->release_one_partitioner(tbb_partitioner); } else if (vec_size > 0) @@ -1389,10 +1387,8 @@ namespace internal TBBReduceFunctor generic_functor(op, start, end); - tbb::parallel_for( - tbb::blocked_range(0, generic_functor.n_chunks, 1), - generic_functor, - *tbb_partitioner); + parallel::internal::parallel_for( + 0U, generic_functor.n_chunks, generic_functor, 1, tbb_partitioner); partitioner->release_one_partitioner(tbb_partitioner); result = generic_functor.do_sum(); } From e74a4ba7c6051960e28c278a6cb8ce9d5a95c555 Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Thu, 14 Mar 2019 17:58:31 -0400 Subject: [PATCH 263/507] Make clear that the predicate must be const --- include/deal.II/base/parallel.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/deal.II/base/parallel.h b/include/deal.II/base/parallel.h index d9db08f5acd5..8b9d5cc49159 100644 --- a/include/deal.II/base/parallel.h +++ b/include/deal.II/base/parallel.h @@ -209,7 +209,7 @@ namespace parallel transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, - Predicate & predicate, + const Predicate & predicate, const unsigned int grainsize) { #ifndef DEAL_II_WITH_THREADS @@ -265,7 +265,7 @@ namespace parallel const InputIterator1 &end_in1, InputIterator2 in2, OutputIterator out, - Predicate & predicate, + const Predicate & predicate, const unsigned int grainsize) { #ifndef DEAL_II_WITH_THREADS @@ -324,7 +324,7 @@ namespace parallel InputIterator2 in2, InputIterator3 in3, OutputIterator out, - Predicate & predicate, + const Predicate & predicate, const unsigned int grainsize) { #ifndef DEAL_II_WITH_THREADS From de5ff7d6fe6443960b41cf58a9019062ca2d4178 Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Thu, 14 Mar 2019 18:00:30 -0400 Subject: [PATCH 264/507] Use std::lambda instead of boost::lambda --- tests/base/parallel_transform_01.cc | 4 +--- tests/base/parallel_transform_02.cc | 4 +--- tests/base/parallel_transform_03.cc | 5 +---- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/tests/base/parallel_transform_01.cc b/tests/base/parallel_transform_01.cc index 78939f85eff9..9bf1faf5a966 100644 --- a/tests/base/parallel_transform_01.cc +++ b/tests/base/parallel_transform_01.cc @@ -20,8 +20,6 @@ #include -#include - #include "../tests.h" @@ -39,7 +37,7 @@ main() // set y=2*x parallel::transform( - x.begin(), x.end(), y.begin(), (2 * boost::lambda::_1), 10); + x.begin(), x.end(), y.begin(), [](double i) { return 2. * i; }, 10); // compute y=0 from the previous result y -= x; diff --git a/tests/base/parallel_transform_02.cc b/tests/base/parallel_transform_02.cc index f3cfdd4eca9a..764746bab152 100644 --- a/tests/base/parallel_transform_02.cc +++ b/tests/base/parallel_transform_02.cc @@ -20,8 +20,6 @@ #include -#include - #include "../tests.h" @@ -45,7 +43,7 @@ main() x.end(), y.begin(), z.begin(), - (boost::lambda::_1 + 2 * boost::lambda::_2), + [](double i, double j) { return i + 2 * j; }, 10); Assert(z.l2_norm() == 0, ExcInternalError()); diff --git a/tests/base/parallel_transform_03.cc b/tests/base/parallel_transform_03.cc index 741f3eac8124..2931c4dbe87d 100644 --- a/tests/base/parallel_transform_03.cc +++ b/tests/base/parallel_transform_03.cc @@ -20,8 +20,6 @@ #include -#include - #include "../tests.h" @@ -48,8 +46,7 @@ main() y.begin(), z.begin(), a.begin(), - (boost::lambda::_1 + boost::lambda::_2 - - boost::lambda::_3), + [](double i, double j, double k) { return i + j - k; }, 10); AssertThrow(a.l2_norm() == 0, ExcInternalError()); From 91b02361986948ffd0bc82daebd17ef7fe8576d7 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Fri, 15 Mar 2019 09:40:03 +0100 Subject: [PATCH 265/507] Remove dummy vector when initializing AMG constant modes --- source/lac/trilinos_precondition_ml.cc | 14 +- tests/trilinos/precondition_amg_dgp_03.cc | 273 ++++++++++++++++++ ...n_amg_dgp_03.with_64bit_indices=off.output | 5 + 3 files changed, 280 insertions(+), 12 deletions(-) create mode 100644 tests/trilinos/precondition_amg_dgp_03.cc create mode 100644 tests/trilinos/precondition_amg_dgp_03.with_64bit_indices=off.output diff --git a/source/lac/trilinos_precondition_ml.cc b/source/lac/trilinos_precondition_ml.cc index 848315efaa74..1e65a430e9b4 100644 --- a/source/lac/trilinos_precondition_ml.cc +++ b/source/lac/trilinos_precondition_ml.cc @@ -178,18 +178,8 @@ namespace TrilinosWrappers parameter_list.set("null space: type", "pre-computed"); parameter_list.set("null space: dimension", distributed_constant_modes.NumVectors()); - if (my_size > 0) - parameter_list.set("null space: vectors", - distributed_constant_modes.Values()); - else - { - // We need to set a valid pointer to data even if there is no data - // on the current processor. Therefore, pass a dummy in that case - static std::vector dummy; - if (dummy.size() != constant_modes_dimension) - dummy.resize(constant_modes_dimension); - parameter_list.set("null space: vectors", dummy.data()); - } + parameter_list.set("null space: vectors", + distributed_constant_modes.Values()); } } diff --git a/tests/trilinos/precondition_amg_dgp_03.cc b/tests/trilinos/precondition_amg_dgp_03.cc new file mode 100644 index 000000000000..1fcf871403be --- /dev/null +++ b/tests/trilinos/precondition_amg_dgp_03.cc @@ -0,0 +1,273 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2013 - 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. +// +// --------------------------------------------------------------------- + + + +// solves a 2D Poisson equation for linear FE_DGP elements (SIP +// discretization) with AMG preconditioner. +// +// This variant of the test trilinos/precondition_amg_dgp_01 does not initialize +// the constant modes vector passes to the AMG preconditioner. + +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "../tests.h" + + + +template +class MatrixIntegrator : public MeshWorker::LocalIntegrator +{ +public: + void + cell(MeshWorker::DoFInfo & dinfo, + typename MeshWorker::IntegrationInfo &info) const; + void + boundary(MeshWorker::DoFInfo & dinfo, + typename MeshWorker::IntegrationInfo &info) const; + void + face(MeshWorker::DoFInfo & dinfo1, + MeshWorker::DoFInfo & dinfo2, + typename MeshWorker::IntegrationInfo &info1, + typename MeshWorker::IntegrationInfo &info2) const; +}; + +template +void +MatrixIntegrator::cell( + MeshWorker::DoFInfo & dinfo, + typename MeshWorker::IntegrationInfo &info) const +{ + LocalIntegrators::Laplace::cell_matrix(dinfo.matrix(0, false).matrix, + info.fe_values()); +} + +template +void +MatrixIntegrator::boundary( + MeshWorker::DoFInfo & dinfo, + typename MeshWorker::IntegrationInfo &info) const +{ + const unsigned int deg = info.fe_values(0).get_fe().degree; + LocalIntegrators::Laplace ::nitsche_matrix( + dinfo.matrix(0, false).matrix, + info.fe_values(0), + LocalIntegrators::Laplace::compute_penalty(dinfo, dinfo, deg, deg)); +} + +template +void +MatrixIntegrator::face( + MeshWorker::DoFInfo & dinfo1, + MeshWorker::DoFInfo & dinfo2, + typename MeshWorker::IntegrationInfo &info1, + typename MeshWorker::IntegrationInfo &info2) const +{ + const unsigned int deg = info1.fe_values(0).get_fe().degree; + LocalIntegrators::Laplace ::ip_matrix( + dinfo1.matrix(0, false).matrix, + dinfo1.matrix(0, true).matrix, + dinfo2.matrix(0, true).matrix, + dinfo2.matrix(0, false).matrix, + info1.fe_values(0), + info2.fe_values(0), + LocalIntegrators::Laplace::compute_penalty(dinfo1, dinfo2, deg, deg)); +} + + +template +class Step4 +{ +public: + Step4(); + void + run(); + +private: + void + make_grid(); + void + setup_system(); + void + solve(); + + Triangulation triangulation; + FE_DGP fe; + DoFHandler dof_handler; + + TrilinosWrappers::SparseMatrix system_matrix; + + Vector solution; + Vector system_rhs; +}; + + + +template +Step4::Step4() + : fe(1) + , dof_handler(triangulation) +{} + + +template +void +Step4::make_grid() +{ + GridGenerator::hyper_cube(triangulation, -1, 1); + triangulation.refine_global(6); +} + + + +template +void +Step4::setup_system() +{ + dof_handler.distribute_dofs(fe); + + DynamicSparsityPattern c_sparsity(dof_handler.n_dofs()); + DoFTools::make_flux_sparsity_pattern(dof_handler, c_sparsity); + system_matrix.reinit(c_sparsity); + + solution.reinit(dof_handler.n_dofs()); + system_rhs.reinit(dof_handler.n_dofs()); + + MappingQGeneric mapping(1); + MeshWorker::IntegrationInfoBox info_box; + UpdateFlags update_flags = update_values | update_gradients; + info_box.add_update_flags_all(update_flags); + info_box.initialize(fe, mapping); + + MeshWorker::DoFInfo dof_info(dof_handler); + MeshWorker::Assembler::MatrixSimple assembler; + assembler.initialize(system_matrix); + MatrixIntegrator integrator; + MeshWorker::integration_loop(dof_handler.begin_active(), + dof_handler.end(), + dof_info, + info_box, + integrator, + assembler); + + system_matrix.compress(VectorOperation::add); + + for (unsigned int i = 0; i < system_rhs.size(); ++i) + system_rhs(i) = 0.01 * i - 0.000001 * i * i; +} + + + +template +void +Step4::solve() +{ + deallog.push(Utilities::int_to_string(dof_handler.n_dofs(), 5)); + TrilinosWrappers::PreconditionAMG preconditioner; + TrilinosWrappers::PreconditionAMG::AdditionalData data; + data.smoother_sweeps = 2; + { + solution = 0; + SolverControl solver_control(1000, 1e-10); + SolverCG<> solver(solver_control); + preconditioner.initialize(system_matrix, data); + solver.solve(system_matrix, solution, system_rhs, preconditioner); + } + deallog.pop(); +} + + + +template +void +Step4::run() +{ + for (unsigned int cycle = 0; cycle < 2; ++cycle) + { + if (cycle == 0) + make_grid(); + else + triangulation.refine_global(1); + + setup_system(); + solve(); + } +} + + +int +main(int argc, char **argv) +{ + initlog(); + + Utilities::MPI::MPI_InitFinalize mpi_initialization( + argc, argv, testing_max_num_threads()); + + try + { + Step4<2> test; + test.run(); + } + catch (std::exception &exc) + { + deallog << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + deallog << "Exception on processing: " << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + return 1; + } + catch (...) + { + deallog << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + deallog << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + }; +} diff --git a/tests/trilinos/precondition_amg_dgp_03.with_64bit_indices=off.output b/tests/trilinos/precondition_amg_dgp_03.with_64bit_indices=off.output new file mode 100644 index 000000000000..5399b9277c21 --- /dev/null +++ b/tests/trilinos/precondition_amg_dgp_03.with_64bit_indices=off.output @@ -0,0 +1,5 @@ + +DEAL:12288:cg::Starting value 1970.22 +DEAL:12288:cg::Convergence step 121 value 0 +DEAL:49152:cg::Starting value 179304. +DEAL:49152:cg::Convergence step 271 value 0 From 7ca10c52d89ec0e201320acaa9b34822d47779df Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Fri, 15 Mar 2019 10:05:20 +0100 Subject: [PATCH 266/507] Only permit use of ld.lld linker when the Clang compiler is used. Fixes #7811 --- cmake/checks/check_02_compiler_features.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/checks/check_02_compiler_features.cmake b/cmake/checks/check_02_compiler_features.cmake index d108cc47672f..fae50833f9e4 100644 --- a/cmake/checks/check_02_compiler_features.cmake +++ b/cmake/checks/check_02_compiler_features.cmake @@ -460,7 +460,11 @@ CHECK_CXX_SOURCE_COMPILES( DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) RESET_CMAKE_REQUIRED() -IF(DEAL_II_COMPILER_HAS_FUSE_LD_LLD) +# +# The ld.lld linker is not compatible with GCC. So we only enable it when +# the Clang compiler is used. See https://github.com/dealii/dealii/issues/7811 +# +IF(DEAL_II_COMPILER_HAS_FUSE_LD_LLD AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") 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") From 234b815f4df093d4210a8b2efef6732493b7aa0e Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Fri, 15 Mar 2019 11:03:46 +0100 Subject: [PATCH 267/507] Fix SymEngine CMake module. --- cmake/modules/FindSYMENGINE.cmake | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cmake/modules/FindSYMENGINE.cmake b/cmake/modules/FindSYMENGINE.cmake index 4b7468f9eca8..b318dd5992fd 100644 --- a/cmake/modules/FindSYMENGINE.cmake +++ b/cmake/modules/FindSYMENGINE.cmake @@ -118,7 +118,19 @@ STRING(REGEX REPLACE ) REMOVE_DUPLICATES(_symengine_include_dirs) -SET(_symengine_libraries ${SYMENGINE_LIBRARIES}) +# +# The SYMENGINE_LIBRARIES variable configured by SymEngine only lists the +# libraries, but does not set their paths. So we configure this outselves. +# +FOREACH(SYMENGINE_LIBRARY_NAME ${SYMENGINE_LIBRARIES}) + DEAL_II_FIND_LIBRARY(SYMENGINE_LIBRARY + NAMES ${SYMENGINE_LIBRARY_NAME} + HINTS ${SYMENGINE_DIR} + PATH_SUFFIXES lib${LIB_SUFFIX} lib64 lib + ) + + SET(_symengine_libraries ${_symengine_libraries} ${SYMENGINE_LIBRARY}) +ENDFOREACH() DEAL_II_PACKAGE_HANDLE(SYMENGINE From 8f713e8f0f889cea3269404fb65742ddefd17d3a Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 14 Mar 2019 18:27:51 +0100 Subject: [PATCH 268/507] Add some initial tests for SymEngine --- tests/symengine/CMakeLists.txt | 6 + tests/symengine/basic_01.cc | 134 +++++++++++ tests/symengine/basic_01.output | 35 +++ tests/symengine/basic_02.cc | 152 +++++++++++++ tests/symengine/basic_02.output | 35 +++ tests/symengine/basic_03.cc | 211 ++++++++++++++++++ tests/symengine/basic_03.output | 62 +++++ tests/symengine/basic_04.cc | 170 ++++++++++++++ ...c_04.with_symengine_with_llvm=false.output | 4 + ...ic_04.with_symengine_with_llvm=true.output | 5 + tests/symengine/basic_05.cc | 190 ++++++++++++++++ ...c_05.with_symengine_with_llvm=false.output | 4 + ...ic_05.with_symengine_with_llvm=true.output | 5 + tests/symengine/basic_06.cc | 115 ++++++++++ tests/symengine/basic_06.output | 12 + tests/symengine/basic_07.cc | 123 ++++++++++ tests/symengine/basic_07.output | 12 + 17 files changed, 1275 insertions(+) create mode 100644 tests/symengine/CMakeLists.txt create mode 100644 tests/symengine/basic_01.cc create mode 100644 tests/symengine/basic_01.output create mode 100644 tests/symengine/basic_02.cc create mode 100644 tests/symengine/basic_02.output create mode 100644 tests/symengine/basic_03.cc create mode 100644 tests/symengine/basic_03.output create mode 100644 tests/symengine/basic_04.cc create mode 100644 tests/symengine/basic_04.with_symengine_with_llvm=false.output create mode 100644 tests/symengine/basic_04.with_symengine_with_llvm=true.output create mode 100644 tests/symengine/basic_05.cc create mode 100644 tests/symengine/basic_05.with_symengine_with_llvm=false.output create mode 100644 tests/symengine/basic_05.with_symengine_with_llvm=true.output create mode 100644 tests/symengine/basic_06.cc create mode 100644 tests/symengine/basic_06.output create mode 100644 tests/symengine/basic_07.cc create mode 100644 tests/symengine/basic_07.output diff --git a/tests/symengine/CMakeLists.txt b/tests/symengine/CMakeLists.txt new file mode 100644 index 000000000000..46145a04668f --- /dev/null +++ b/tests/symengine/CMakeLists.txt @@ -0,0 +1,6 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9) +INCLUDE(../setup_testsubproject.cmake) +PROJECT(testsuite CXX) +IF(DEAL_II_WITH_SYMENGINE AND DEAL_II_WITH_CXX11) + DEAL_II_PICKUP_TESTS() +ENDIF() diff --git a/tests/symengine/basic_01.cc b/tests/symengine/basic_01.cc new file mode 100644 index 000000000000..1022f6aa9eb5 --- /dev/null +++ b/tests/symengine/basic_01.cc @@ -0,0 +1,134 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 - 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 at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +// Check that all fundamental operations with primitive SymEngine number +// types work as expected + +// References: +// https://github.com/symengine/symengine/blob/master/symengine/tests/basic/test_basic.cpp +// https://github.com/symengine/symengine/blob/master/symengine/tests/basic/test_number.cpp + +#include "../tests.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra-semi" +#include +#include +#include +#include +#include +#include +#pragma clang diagnostic pop + +#include +#include + +using namespace dealii; +namespace SE = SymEngine; + +SE::RCP +make_symengine_rcp(const int &val) +{ + return SE::integer(val); +} + +SE::RCP +make_symengine_rcp(const float &val) +{ + return SE::real_double(val); +} + +SE::RCP +make_symengine_rcp(const double &val) +{ + return SE::real_double(val); +} + +template +SE::RCP +make_symengine_rcp(const std::complex &val) +{ + // Build complex from two SymEngine numbers + return SE::Complex::from_two_nums(*make_symengine_rcp(val.real()), + *make_symengine_rcp(val.imag())); +} + +template +void +test_number() +{ + SE::RCP a = make_symengine_rcp(NumberType(4.2)); + deallog << "a: " << *a << std::endl; + + SE::RCP b(make_symengine_rcp(NumberType(2.1))); + deallog << "b: " << *b << std::endl; + + SE::RCP c; + // deallog << "c (no constructor): " << *c << std::endl; // Fails + + c = SE::add(a, b); + deallog << "c = a+b: " << *c << std::endl; + + c = SE::sub(a, b); + deallog << "c = a-b: " << *c << std::endl; + + c = SE::mul(a, b); + deallog << "c = a*b: " << *c << std::endl; + + c = SE::div(a, b); + deallog << "c = a/b: " << *c << std::endl; + + c = a; + deallog << "c = a: " << *c << std::endl; + + c = SE::add(c, a); + deallog << "c += a: " << *c << std::endl; + + c = SE::sub(c, a); + deallog << "c -= a: " << *c << std::endl; + + c = SE::mul(c, a); + deallog << "c *= a: " << *c << std::endl; + + c = SE::div(c, a); + deallog << "c /= a: " << *c << std::endl; +} + +int +main() +{ + initlog(); + + deallog.push("Integer"); + test_number(); + deallog.pop(); + + deallog.push("Float"); + test_number(); + deallog.pop(); + + deallog.push("Double"); + test_number(); + deallog.pop(); + + // Not available yet + // SymEngine::SymEngineException: Invalid Format: Expected Integer or Rational + // deallog << "Complex double" << std::endl; + // test_number>(); + // deallog.pop(); + + deallog << "OK" << std::endl; +} diff --git a/tests/symengine/basic_01.output b/tests/symengine/basic_01.output new file mode 100644 index 000000000000..f6307bc99a8c --- /dev/null +++ b/tests/symengine/basic_01.output @@ -0,0 +1,35 @@ + +DEAL:Integer::a: 4 +DEAL:Integer::b: 2 +DEAL:Integer::c = a+b: 6 +DEAL:Integer::c = a-b: 2 +DEAL:Integer::c = a*b: 8 +DEAL:Integer::c = a/b: 2 +DEAL:Integer::c = a: 4 +DEAL:Integer::c += a: 8 +DEAL:Integer::c -= a: 4 +DEAL:Integer::c *= a: 16 +DEAL:Integer::c /= a: 4 +DEAL:Float::a: 4.19999980926514 +DEAL:Float::b: 2.09999990463257 +DEAL:Float::c = a+b: 6.29999971389771 +DEAL:Float::c = a-b: 2.09999990463257 +DEAL:Float::c = a*b: 8.81999919891359 +DEAL:Float::c = a/b: 2. +DEAL:Float::c = a: 4.19999980926514 +DEAL:Float::c += a: 8.39999961853027 +DEAL:Float::c -= a: 4.19999980926514 +DEAL:Float::c *= a: 17.6399983978272 +DEAL:Float::c /= a: 4.19999980926514 +DEAL:Double::a: 4.2 +DEAL:Double::b: 2.1 +DEAL:Double::c = a+b: 6.3 +DEAL:Double::c = a-b: 2.1 +DEAL:Double::c = a*b: 8.82 +DEAL:Double::c = a/b: 2. +DEAL:Double::c = a: 4.2 +DEAL:Double::c += a: 8.4 +DEAL:Double::c -= a: 4.2 +DEAL:Double::c *= a: 17.64 +DEAL:Double::c /= a: 4.2 +DEAL::OK diff --git a/tests/symengine/basic_02.cc b/tests/symengine/basic_02.cc new file mode 100644 index 000000000000..7284e26f9c67 --- /dev/null +++ b/tests/symengine/basic_02.cc @@ -0,0 +1,152 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 - 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 at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +// Check that SymEngine can perform symbolic differentiation correctly + +// References: +// https://github.com/symengine/symengine/blob/master/symengine/tests/basic/test_basic.cpp +// https://github.com/symengine/symengine/blob/master/symengine/tests/basic/test_number.cpp +// https://github.com/symengine/symengine/blob/master/symengine/tests/basic/test_subs.cpp +// https://github.com/symengine/symengine/blob/master/symengine/symengine_casts.h +// https://github.com/symengine/symengine/blob/master/symengine/symengine_rcp.h +// https://github.com/symengine/symengine/blob/master/symengine/derivative.h +// https://github.com/symengine/symengine/blob/master/symengine/subs.h + +#include "../tests.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra-semi" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma clang diagnostic pop + +#include +#include + +using namespace dealii; +namespace SE = SymEngine; + +SE::RCP +make_symengine_rcp(const int &val) +{ + return SE::integer(val); +} + +SE::RCP +make_symengine_rcp(const float &val) +{ + return SE::real_double(val); +} + +SE::RCP +make_symengine_rcp(const double &val) +{ + return SE::real_double(val); +} + +template +SE::RCP +make_symengine_rcp(const std::complex &val) +{ + // Build complex from two SymEngine numbers + return SE::Complex::from_two_nums(*make_symengine_rcp(val.real()), + *make_symengine_rcp(val.imag())); +} + +SE::RCP +make_symengine_rcp(const std::string &name) +{ + return SE::symbol(name); +} + +template +void +test_number() +{ + SE::RCP a = make_symengine_rcp(NumberType(3.1)); + SE::RCP b = make_symengine_rcp(NumberType(7.5)); + deallog << "a: " << *a << std::endl; + deallog << "b: " << *b << std::endl; + + SE::RCP x(make_symengine_rcp("x")); + SE::RCP y(make_symengine_rcp("y")); + deallog << "x: " << *x << std::endl; + deallog << "y: " << *y << std::endl; + + SE::RCP c; + // deallog << "c (no constructor): " << *c << std::endl; // Fails + + // Construction of symbolic function + c = SE::mul(y, SE::mul(SE::sub(y, b), SE::add(a, x))); + deallog << "c = y*(y-b)*(a+x): " << *c << std::endl; + + // Perform symbolic differentiation + SE::RCP dc_dx = c->diff(x); + // SE::RCP dc_dy = diff(c,SE::implicit_cast &>(y)); + SE::RCP dc_dy = + diff(c, SE::rcp_static_cast(y)); + SE::RCP dc_dy_2 = sdiff(c, y); + + deallog << "dc_dx = a*y*(y-b): " << *dc_dx << std::endl; + deallog << "dc_dy = 2*y*(a+x): " << *dc_dy << std::endl; + deallog << "dc_dy = 2*y*(a+x): " << *dc_dy_2 << std::endl; + + // Substitute values + SE::map_basic_basic sub_vals; + sub_vals[x] = make_symengine_rcp(NumberType(1)); + sub_vals[y] = make_symengine_rcp(NumberType(2.2)); + deallog << "dc_dx(x=1,y=2.2): " << *(dc_dx->subs(sub_vals)) << std::endl; + + sub_vals[x] = make_symengine_rcp(NumberType(0.75)); + sub_vals[y] = make_symengine_rcp(NumberType(-2.08)); + deallog << "dc_dy(x=0.75,y=-1.08): " << *(dc_dy->subs(sub_vals)) << std::endl; + + deallog << std::endl; +} + +int +main() +{ + initlog(); + + deallog.push("Integer"); + test_number(); + deallog.pop(); + + deallog.push("Float"); + test_number(); + deallog.pop(); + + deallog.push("Double"); + test_number(); + deallog.pop(); + + // Not available yet + // SymEngine::SymEngineException: Invalid Format: Expected Integer or Rational + // deallog << "Complex double" << std::endl; + // test_number>(); + // deallog.pop(); + + deallog << "OK" << std::endl; +} diff --git a/tests/symengine/basic_02.output b/tests/symengine/basic_02.output new file mode 100644 index 000000000000..a023eec9d8d3 --- /dev/null +++ b/tests/symengine/basic_02.output @@ -0,0 +1,35 @@ + +DEAL:Integer::a: 3 +DEAL:Integer::b: 7 +DEAL:Integer::x: x +DEAL:Integer::y: y +DEAL:Integer::c = y*(y-b)*(a+x): y*(-7 + y)*(3 + x) +DEAL:Integer::dc_dx = a*y*(y-b): y*(-7 + y) +DEAL:Integer::dc_dy = 2*y*(a+x): y*(3 + x) + (-7 + y)*(3 + x) +DEAL:Integer::dc_dy = 2*y*(a+x): y*(3 + x) + (-7 + y)*(3 + x) +DEAL:Integer::dc_dx(x=1,y=2.2): -10 +DEAL:Integer::dc_dy(x=0.75,y=-1.08): -33 +DEAL:Integer:: +DEAL:Float::a: 3.09999990463257 +DEAL:Float::b: 7.5 +DEAL:Float::x: x +DEAL:Float::y: y +DEAL:Float::c = y*(y-b)*(a+x): y*(3.09999990463257 + x)*(-7.5 + y) +DEAL:Float::dc_dx = a*y*(y-b): y*(-7.5 + y) +DEAL:Float::dc_dy = 2*y*(a+x): y*(3.09999990463257 + x) + (3.09999990463257 + x)*(-7.5 + y) +DEAL:Float::dc_dy = 2*y*(a+x): y*(3.09999990463257 + x) + (3.09999990463257 + x)*(-7.5 + y) +DEAL:Float::dc_dx(x=1,y=2.2): -11.6600001478195 +DEAL:Float::dc_dy(x=0.75,y=-1.08): -44.8909983005524 +DEAL:Float:: +DEAL:Double::a: 3.1 +DEAL:Double::b: 7.5 +DEAL:Double::x: x +DEAL:Double::y: y +DEAL:Double::c = y*(y-b)*(a+x): y*(3.1 + x)*(-7.5 + y) +DEAL:Double::dc_dx = a*y*(y-b): y*(-7.5 + y) +DEAL:Double::dc_dy = 2*y*(a+x): y*(3.1 + x) + (3.1 + x)*(-7.5 + y) +DEAL:Double::dc_dy = 2*y*(a+x): y*(3.1 + x) + (3.1 + x)*(-7.5 + y) +DEAL:Double::dc_dx(x=1,y=2.2): -11.66 +DEAL:Double::dc_dy(x=0.75,y=-1.08): -44.891 +DEAL:Double:: +DEAL::OK diff --git a/tests/symengine/basic_03.cc b/tests/symengine/basic_03.cc new file mode 100644 index 000000000000..3a11eb2be9fc --- /dev/null +++ b/tests/symengine/basic_03.cc @@ -0,0 +1,211 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 - 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 at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +// Check that SymEngine can perform symbolic differentiation using function +// symbols correctly + +// References: +// https://github.com/symengine/symengine/blob/master/symengine/tests/basic/test_functions.cpp +// https://github.com/symengine/symengine/blob/master/symengine/function.h +// https://github.com/symengine/symengine/blob/master/symengine/tests/basic/test_basic.cpp +// https://github.com/symengine/symengine/blob/master/symengine/tests/basic/test_number.cpp +// https://github.com/symengine/symengine/blob/master/symengine/tests/basic/test_subs.cpp +// https://github.com/symengine/symengine/blob/master/symengine/symengine_casts.h +// https://github.com/symengine/symengine/blob/master/symengine/symengine_rcp.h +// https://github.com/symengine/symengine/blob/master/symengine/derivative.h +// https://github.com/symengine/symengine/blob/master/symengine/subs.h + +#include "../tests.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra-semi" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma clang diagnostic pop + +#include +#include + +using namespace dealii; +namespace SE = SymEngine; + +SE::RCP +make_symengine_rcp(const int &val) +{ + return SE::integer(val); +} + +SE::RCP +make_symengine_rcp(const float &val) +{ + return SE::real_double(val); +} + +SE::RCP +make_symengine_rcp(const double &val) +{ + return SE::real_double(val); +} + +template +SE::RCP +make_symengine_rcp(const std::complex &val) +{ + // Build complex from two SymEngine numbers + return SE::Complex::from_two_nums(*make_symengine_rcp(val.real()), + *make_symengine_rcp(val.imag())); +} + +SE::RCP +make_symengine_rcp(const std::string &name) +{ + return SE::symbol(name); +} + +SE::RCP +make_symengine_rcp(const std::string & name, + const std::vector> &args) +{ + return SE::function_symbol(name, args); +} + +SE::RCP +make_symengine_rcp(const std::string &name, const SE::RCP &arg) +{ + return SE::function_symbol(name, arg); +} + +template +void +test_number() +{ + // Modified snippet from SymEngine test + // { + // SE::RCP x = SE::symbol("x"); + // SE::RCP _xi_1 = SE::symbol("_xi_1"); + // SE::RCP f = SE::function_symbol("f", x); + // SE::RCP r1, r2; + // + // f = function_symbol("f", SE::pow(x, SE::integer(2))); + // deallog << "f: " << *f << std::endl; + // r1 = f->diff(x); + // deallog << "r1: " << *r1 << std::endl; + // r2 = SE::Derivative::create(SE::function_symbol("f", _xi_1), {_xi_1}); + // deallog << "r2: " << *r2 << std::endl; + // r2 = SE::Subs::create(r2, {{_xi_1, SE::pow(x, SE::integer(2))}}); + // deallog << "r2: " << *r2 << std::endl; + // } + + // Normal symbols + SE::RCP x(make_symengine_rcp("x")); + SE::RCP y(make_symengine_rcp("y")); + deallog << "x: " << *x << std::endl; + deallog << "y: " << *y << std::endl; + + // Function symbols + SE::RCP f(make_symengine_rcp("f", x)); + SE::RCP g(make_symengine_rcp("g", {x, y})); + SE::RCP h( + make_symengine_rcp("h", {SE::add(x, y), SE::mul(x, y)})); + deallog << "f: " << *f << std::endl; + deallog << "g: " << *g << std::endl; + deallog << "h: " << *h << std::endl; + + // Perform symbolic differentiation + SE::RCP df_dx = f->diff(x); + SE::RCP dg_dx = g->diff(x); + SE::RCP dh_dx = h->diff(x); + deallog << "df_dx: " << *df_dx << std::endl; + deallog << "dg_dx: " << *dg_dx << std::endl; + deallog << "dh_dx: " << *dh_dx << std::endl; + SE::RCP df_dy = + f->diff(SE::rcp_static_cast(y)); + SE::RCP dg_dy = + g->diff(SE::rcp_static_cast(y)); + SE::RCP dh_dy = + h->diff(SE::rcp_static_cast(y)); + deallog << "df_dy: " << *df_dy << std::endl; + deallog << "dg_dy: " << *dg_dy << std::endl; + deallog << "dh_dy: " << *dh_dy << std::endl; + + // Substitute values + SE::map_basic_basic sub_vals; + sub_vals[x] = make_symengine_rcp(NumberType(1)); + sub_vals[y] = make_symengine_rcp(NumberType(2.2)); + sub_vals[f] = SE::pow(x, SE::integer(2)); + sub_vals[g] = SE::add(x, y); + sub_vals[h] = SE::sub(x, y); + + deallog << "f(x=1,y=2.2): " << *(f->subs(sub_vals)) + << std::endl; // ->subs(sub_vals) + deallog << "g(x=1,y=2.2): " << *(g->subs(sub_vals)) + << std::endl; // ->subs(sub_vals) + deallog << "h(x=1,y=2.2): " << *(h->subs(sub_vals)) + << std::endl; // ->subs(sub_vals) + deallog << "Eval: f(x=1,y=2.2): " + << eval_double(*(f->subs(sub_vals)->subs(sub_vals))) << std::endl; + deallog << "Eval: g(x=1,y=2.2): " + << eval_double(*(g->subs(sub_vals)->subs(sub_vals))) << std::endl; + deallog << "Eval: h(x=1,y=2.2): " + << eval_double(*(h->subs(sub_vals)->subs(sub_vals))) << std::endl; + + // Not yet implemented + deallog << "df_dx(x=1,y=2.2): " << *(df_dx->subs(sub_vals)) + << std::endl; // ->subs(sub_vals) + deallog << "dg_dx(x=1,y=2.2): " << *(dg_dx->subs(sub_vals)) + << std::endl; // ->subs(sub_vals) + deallog << "dh_dx(x=1,y=2.2): " << *(dh_dx->subs(sub_vals)) + << std::endl; // ->subs(sub_vals) + // deallog << "Eval: df_dx(x=1,y=2.2): " << + // eval_double(*(df_dx->subs(sub_vals)->subs(sub_vals))) << std::endl; deallog + // << "Eval: dg_dx(x=1,y=2.2): " << + // eval_double(*(dg_dx->subs(sub_vals)->subs(sub_vals))) << std::endl; deallog + // << "Eval: dh_dx(x=1,y=2.2): " << + // eval_double(*(dh_dx->subs(sub_vals)->subs(sub_vals))) << std::endl; +} + +int +main() +{ + initlog(); + + deallog.push("Integer"); + test_number(); + deallog.pop(); + + deallog.push("Float"); + test_number(); + deallog.pop(); + + deallog.push("Double"); + test_number(); + deallog.pop(); + + // Not available yet + // SymEngine::SymEngineException: Invalid Format: Expected Integer or Rational + // deallog << "Complex double" << std::endl; + // test_number>(); + // deallog.pop(); + + deallog << "OK" << std::endl; +} diff --git a/tests/symengine/basic_03.output b/tests/symengine/basic_03.output new file mode 100644 index 000000000000..d65a0e705c37 --- /dev/null +++ b/tests/symengine/basic_03.output @@ -0,0 +1,62 @@ + +DEAL:Integer::x: x +DEAL:Integer::y: y +DEAL:Integer::f: f(x) +DEAL:Integer::g: g(x, y) +DEAL:Integer::h: h(x + y, x*y) +DEAL:Integer::df_dx: Derivative(f(x), x) +DEAL:Integer::dg_dx: Derivative(g(x, y), x) +DEAL:Integer::dh_dx: y*Subs(Derivative(h(x + y, _xi_2), _xi_2), (_xi_2), (x*y)) + Subs(Derivative(h(_xi_1, x*y), _xi_1), (_xi_1), (x + y)) +DEAL:Integer::df_dy: 0 +DEAL:Integer::dg_dy: Derivative(g(x, y), y) +DEAL:Integer::dh_dy: x*Subs(Derivative(h(x + y, _xi_2), _xi_2), (_xi_2), (x*y)) + Subs(Derivative(h(_xi_1, x*y), _xi_1), (_xi_1), (x + y)) +DEAL:Integer::f(x=1,y=2.2): x**2 +DEAL:Integer::g(x=1,y=2.2): x + y +DEAL:Integer::h(x=1,y=2.2): x - y +DEAL:Integer::Eval: f(x=1,y=2.2): 1.00 +DEAL:Integer::Eval: g(x=1,y=2.2): 3.00 +DEAL:Integer::Eval: h(x=1,y=2.2): -1.00 +DEAL:Integer::df_dx(x=1,y=2.2): 2*x +DEAL:Integer::dg_dx(x=1,y=2.2): 1 +DEAL:Integer::dh_dx(x=1,y=2.2): 2*Subs(Derivative(h(3, _xi_2), _xi_2), (_xi_2), (2)) + Subs(Derivative(h(_xi_1, 2), _xi_1), (_xi_1), (3)) +DEAL:Float::x: x +DEAL:Float::y: y +DEAL:Float::f: f(x) +DEAL:Float::g: g(x, y) +DEAL:Float::h: h(x + y, x*y) +DEAL:Float::df_dx: Derivative(f(x), x) +DEAL:Float::dg_dx: Derivative(g(x, y), x) +DEAL:Float::dh_dx: y*Subs(Derivative(h(x + y, _xi_2), _xi_2), (_xi_2), (x*y)) + Subs(Derivative(h(_xi_1, x*y), _xi_1), (_xi_1), (x + y)) +DEAL:Float::df_dy: 0 +DEAL:Float::dg_dy: Derivative(g(x, y), y) +DEAL:Float::dh_dy: x*Subs(Derivative(h(x + y, _xi_2), _xi_2), (_xi_2), (x*y)) + Subs(Derivative(h(_xi_1, x*y), _xi_1), (_xi_1), (x + y)) +DEAL:Float::f(x=1,y=2.2): x**2 +DEAL:Float::g(x=1,y=2.2): x + y +DEAL:Float::h(x=1,y=2.2): x - y +DEAL:Float::Eval: f(x=1,y=2.2): 1.00 +DEAL:Float::Eval: g(x=1,y=2.2): 3.20 +DEAL:Float::Eval: h(x=1,y=2.2): -1.20 +DEAL:Float::df_dx(x=1,y=2.2): 2*x +DEAL:Float::dg_dx(x=1,y=2.2): 1 +DEAL:Float::dh_dx(x=1,y=2.2): 2.20000004768372*Subs(Derivative(h(3.20000004768372, _xi_2), _xi_2), (_xi_2), (2.20000004768372)) + Subs(Derivative(h(_xi_1, 2.20000004768372), _xi_1), (_xi_1), (3.20000004768372)) +DEAL:Double::x: x +DEAL:Double::y: y +DEAL:Double::f: f(x) +DEAL:Double::g: g(x, y) +DEAL:Double::h: h(x + y, x*y) +DEAL:Double::df_dx: Derivative(f(x), x) +DEAL:Double::dg_dx: Derivative(g(x, y), x) +DEAL:Double::dh_dx: y*Subs(Derivative(h(x + y, _xi_2), _xi_2), (_xi_2), (x*y)) + Subs(Derivative(h(_xi_1, x*y), _xi_1), (_xi_1), (x + y)) +DEAL:Double::df_dy: 0 +DEAL:Double::dg_dy: Derivative(g(x, y), y) +DEAL:Double::dh_dy: x*Subs(Derivative(h(x + y, _xi_2), _xi_2), (_xi_2), (x*y)) + Subs(Derivative(h(_xi_1, x*y), _xi_1), (_xi_1), (x + y)) +DEAL:Double::f(x=1,y=2.2): x**2 +DEAL:Double::g(x=1,y=2.2): x + y +DEAL:Double::h(x=1,y=2.2): x - y +DEAL:Double::Eval: f(x=1,y=2.2): 1.00 +DEAL:Double::Eval: g(x=1,y=2.2): 3.20 +DEAL:Double::Eval: h(x=1,y=2.2): -1.20 +DEAL:Double::df_dx(x=1,y=2.2): 2*x +DEAL:Double::dg_dx(x=1,y=2.2): 1 +DEAL:Double::dh_dx(x=1,y=2.2): 2.2*Subs(Derivative(h(3.2, _xi_2), _xi_2), (_xi_2), (2.2)) + Subs(Derivative(h(_xi_1, 2.2), _xi_1), (_xi_1), (3.2)) +DEAL::OK diff --git a/tests/symengine/basic_04.cc b/tests/symengine/basic_04.cc new file mode 100644 index 000000000000..9ffad422cf48 --- /dev/null +++ b/tests/symengine/basic_04.cc @@ -0,0 +1,170 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 - 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 at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +// Check that SymEngine can do some optimsation using lambda functions + +// References: +// https://github.com/symengine/symengine/blob/master/symengine/tests/eval/test_lambda_double.cpp + +#include "../tests.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wextra-semi" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic pop + +#include +#include +#include + +using namespace dealii; +namespace SE = SymEngine; + +int +main(int argc, char *argv[]) +{ + initlog(); + + const unsigned int n_runs = 1000; + + SE::RCP t_11 = SE::symbol("t_11"); + SE::RCP t_12 = SE::symbol("t_12"); + SE::RCP s = SE::symbol("s"); + SE::RCP t_02 = SE::symbol("t_02"); + SE::RCP v_0 = SE::symbol("v_0"); + SE::RCP v_1 = SE::symbol("v_1"); + SE::RCP v_2 = SE::symbol("v_2"); + SE::RCP t_10 = SE::symbol("t_10"); + SE::RCP t_00 = SE::symbol("t_00"); + SE::RCP t_01 = SE::symbol("t_01"); + SE::RCP t_20 = SE::symbol("t_20"); + SE::RCP t_21 = SE::symbol("t_21"); + SE::RCP t_22 = SE::symbol("t_22"); + + SE::vec_basic v = { + t_11, t_12, s, t_02, v_0, v_1, v_2, t_10, t_00, t_01, t_20, t_21, t_22}; + + SE::RCP h = + SE::parse("2.*s**2.2*(v_0**2 + v_1**2 + v_2**2)**3*" + "(-1.*t_20*(1.*t_01*t_12 - 1.*t_02*t_11) " + "+ 1.*t_21*(1.*t_00*t_12 - 1.*t_02*t_10) " + "- 1.*t_22*(1.*t_00*t_11 - 1.*t_01*t_10))" + "*(1.*t_21*t_12 - 1.*t_22*t_11)"); + + SE::map_basic_basic dict; + std::vector vals(v.size()); + for (unsigned i = 0; i < v.size(); i++) + { + dict[v[i]] = SE::real_double(i); + vals[i] = i; + } + + double res = 0.0, res1 = 0.0, res2 = 0.0; + + + // Standard substitution + + auto t1 = std::chrono::high_resolution_clock::now(); + for (unsigned j = 0; j < n_runs; j++) + { + res += static_cast(*h->subs(dict)).i; + } + auto t2 = std::chrono::high_resolution_clock::now(); + const double diff_symm_subs = + std::chrono::duration_cast(t2 - t1).count(); + std::cout + << "Subs " << n_runs << " calls :" + << std::chrono::duration_cast(t2 - t1).count() + << " us" << std::endl; + + deallog << "Value (subs): " << res << std::endl; + + // Optimisation via lambda functions + + t1 = std::chrono::high_resolution_clock::now(); + SE::LambdaRealDoubleVisitor l; + l.init(v, *h); + t2 = std::chrono::high_resolution_clock::now(); + const double diff_lambda_real_double_setup = + std::chrono::duration_cast(t2 - t1).count(); + std::cout + << "LambdaDoubleVisitor setup-time :" + << std::chrono::duration_cast(t2 - t1).count() + << " us" << std::endl; + + t1 = std::chrono::high_resolution_clock::now(); + for (unsigned j = 0; j < n_runs; j++) + { + res1 += l.call(vals); + } + t2 = std::chrono::high_resolution_clock::now(); + const double diff_lambda_real_double_call = + std::chrono::duration_cast(t2 - t1).count(); + std::cout + << "LambdaDoubleVisitor run-time :" + << std::chrono::duration_cast(t2 - t1).count() + << " us" << std::endl; + + deallog << "Value (lambda): " << res1 << std::endl; + + std::cout << "Timing ratio (subs/lambda_double): " + << (diff_symm_subs) / + (diff_lambda_real_double_setup + diff_lambda_real_double_call) + << std::endl; + +#ifdef HAVE_SYMENGINE_LLVM + // Optimisation via LLVM JIT optimiser + + t1 = std::chrono::high_resolution_clock::now(); + SE::LLVMDoubleVisitor l2; + l2.init(v, *h); + t2 = std::chrono::high_resolution_clock::now(); + std::cout + << "LLVMDoubleVisitor setup-time :" + << std::chrono::duration_cast(t2 - t1).count() + << " us" << std::endl; + + t1 = std::chrono::high_resolution_clock::now(); + for (unsigned j = 0; j < n_runs; j++) + { + res2 += l2.call(vals); + } + t2 = std::chrono::high_resolution_clock::now(); + std::cout + << "LLVMDoubleVisitor run-time :" + << std::chrono::duration_cast(t2 - t1).count() + << " us : Value: " << res2 << std::endl; + + deallog << "Value (llvm): " << res2 << std::endl; +#endif + + deallog << "OK" << std::endl; + + return 0; +} diff --git a/tests/symengine/basic_04.with_symengine_with_llvm=false.output b/tests/symengine/basic_04.with_symengine_with_llvm=false.output new file mode 100644 index 000000000000..7eb32c0d555c --- /dev/null +++ b/tests/symengine/basic_04.with_symengine_with_llvm=false.output @@ -0,0 +1,4 @@ + +DEAL::Value (subs): 2.41358e+13 +DEAL::Value (lambda): 2.41358e+13 +DEAL::OK diff --git a/tests/symengine/basic_04.with_symengine_with_llvm=true.output b/tests/symengine/basic_04.with_symengine_with_llvm=true.output new file mode 100644 index 000000000000..e230bb2c3478 --- /dev/null +++ b/tests/symengine/basic_04.with_symengine_with_llvm=true.output @@ -0,0 +1,5 @@ + +DEAL::Value (subs): 2.41358e+13 +DEAL::Value (lambda): 2.41358e+13 +DEAL::Value (llvm): 2.41358e+13 +DEAL::OK diff --git a/tests/symengine/basic_05.cc b/tests/symengine/basic_05.cc new file mode 100644 index 000000000000..41d59d174d84 --- /dev/null +++ b/tests/symengine/basic_05.cc @@ -0,0 +1,190 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 - 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 at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +// Check that SymEngine can do some optimsation on diffentiated expressions +// using lambda functions +// This is an extension of basic_04.cc + +// References: +// https://github.com/symengine/symengine/blob/master/symengine/tests/eval/test_lambda_double.cpp + +#include "../tests.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wextra-semi" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic pop + +#include +#include +#include + +using namespace dealii; +namespace SE = SymEngine; + +int +main(int argc, char *argv[]) +{ + initlog(); + + const unsigned int n_runs = 1000; + + SE::RCP t_11 = SE::symbol("t_11"); + SE::RCP t_12 = SE::symbol("t_12"); + SE::RCP s = SE::symbol("s"); + SE::RCP t_02 = SE::symbol("t_02"); + SE::RCP v_0 = SE::symbol("v_0"); + SE::RCP v_1 = SE::symbol("v_1"); + SE::RCP v_2 = SE::symbol("v_2"); + SE::RCP t_10 = SE::symbol("t_10"); + SE::RCP t_00 = SE::symbol("t_00"); + SE::RCP t_01 = SE::symbol("t_01"); + SE::RCP t_20 = SE::symbol("t_20"); + SE::RCP t_21 = SE::symbol("t_21"); + SE::RCP t_22 = SE::symbol("t_22"); + + SE::vec_basic v = { + t_11, t_12, s, t_02, v_0, v_1, v_2, t_10, t_00, t_01, t_20, t_21, t_22}; + + SE::RCP h = + SE::parse("2.*s**2.2*(v_0**2 + v_1**2 + v_2**2)**3*" + "(-1.*t_20*(1.*t_01*t_12 - 1.*t_02*t_11) " + "+ 1.*t_21*(1.*t_00*t_12 - 1.*t_02*t_10) " + "- 1.*t_22*(1.*t_00*t_11 - 1.*t_01*t_10))" + "*(1.*t_21*t_12 - 1.*t_22*t_11)"); + + SE::vec_basic diffs = {h->diff(t_20), + h->diff(t_21), + h->diff(t_22), + h->diff(t_10), + h->diff(t_11), + h->diff(t_12), + h->diff(t_00), + h->diff(t_01), + h->diff(t_02), + h->diff(s)}; + + std::cout << *h << std::endl; + + SE::map_basic_basic dict; + std::vector vals(v.size()); + for (unsigned i = 0; i < v.size(); i++) + { + dict[v[i]] = SE::real_double(i); + vals[i] = i; + } + + double res[10] = {}, res1[10] = {}, res2[10] = {}; + double r = 0.0, r2 = 0.0, r3 = 0.0; + + // Standard substitution + + auto t1 = std::chrono::high_resolution_clock::now(); + for (unsigned j = 0; j < n_runs; j++) + { + for (unsigned k = 0; k < diffs.size(); k++) + { + res[k] = static_cast(*diffs[k]->subs(dict)).i; + r += res[k]; + } + } + auto t2 = std::chrono::high_resolution_clock::now(); + const double diff_symm_subs = + std::chrono::duration_cast(t2 - t1).count(); + std::cout + << "Subs " << n_runs << " calls :" + << std::chrono::duration_cast(t2 - t1).count() + << " us" << std::endl; + + deallog << "Value (subs): " << r << std::endl; + + // Optimisation via lambda functions + + t1 = std::chrono::high_resolution_clock::now(); + SE::LambdaRealDoubleVisitor l; + l.init(v, diffs); + t2 = std::chrono::high_resolution_clock::now(); + const double diff_lambda_real_double_setup = + std::chrono::duration_cast(t2 - t1).count(); + std::cout + << "LambdaDoubleVisitor setup-time :" + << std::chrono::duration_cast(t2 - t1).count() + << " us" << std::endl; + + t1 = std::chrono::high_resolution_clock::now(); + for (unsigned j = 0; j < n_runs; j++) + { + l.call(res1, vals.data()); + for (unsigned k = 0; k < diffs.size(); k++) + { + r2 += res1[k]; + } + } + t2 = std::chrono::high_resolution_clock::now(); + const double diff_lambda_real_double_call = + std::chrono::duration_cast(t2 - t1).count(); + std::cout + << "LambdaDoubleVisitor run-time :" + << std::chrono::duration_cast(t2 - t1).count() + << " us" << std::endl; + + deallog << "Value (lambda): " << r2 << std::endl; + +#ifdef HAVE_SYMENGINE_LLVM + // Optimisation via LLVM JIT optimiser + + t1 = std::chrono::high_resolution_clock::now(); + SE::LLVMDoubleVisitor l2; + l2.init(v, diffs); + t2 = std::chrono::high_resolution_clock::now(); + std::cout + << "LLVMDoubleVisitor setup-time :" + << std::chrono::duration_cast(t2 - t1).count() + << " us" << std::endl; + + t1 = std::chrono::high_resolution_clock::now(); + for (unsigned j = 0; j < 1000; j++) + { + l2.call(res2, vals.data()); + for (unsigned k = 0; k < diffs.size(); k++) + { + r3 += res2[k]; + } + } + t2 = std::chrono::high_resolution_clock::now(); + std::cout + << "LLVMDoubleVisitor run-time :" + << std::chrono::duration_cast(t2 - t1).count() + << " us : Value: " << r3 << std::endl; + + deallog << "Value (llvm): " << r3 << std::endl; +#endif + + deallog << "OK" << std::endl; + + return 0; +} diff --git a/tests/symengine/basic_05.with_symengine_with_llvm=false.output b/tests/symengine/basic_05.with_symengine_with_llvm=false.output new file mode 100644 index 000000000000..b68d7bd3b6c4 --- /dev/null +++ b/tests/symengine/basic_05.with_symengine_with_llvm=false.output @@ -0,0 +1,4 @@ + +DEAL::Value (subs): 2.91338e+13 +DEAL::Value (lambda): 2.91338e+13 +DEAL::OK diff --git a/tests/symengine/basic_05.with_symengine_with_llvm=true.output b/tests/symengine/basic_05.with_symengine_with_llvm=true.output new file mode 100644 index 000000000000..14de91cc39e6 --- /dev/null +++ b/tests/symengine/basic_05.with_symengine_with_llvm=true.output @@ -0,0 +1,5 @@ + +DEAL::Value (subs): 2.91338e+13 +DEAL::Value (lambda): 2.91338e+13 +DEAL::Value (llvm): 2.91338e+13 +DEAL::OK diff --git a/tests/symengine/basic_06.cc b/tests/symengine/basic_06.cc new file mode 100644 index 000000000000..a664af2b46f7 --- /dev/null +++ b/tests/symengine/basic_06.cc @@ -0,0 +1,115 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 - 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 at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +// Check that SymEngine can do delayed substitution of explicitly dependent +// symbolic functions and evaluate their derivatives as well. +// This is inline with what is required to implement some material laws that +// have internal variables + +#include "../tests.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wextra-semi" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic pop + +#include +#include + +using namespace dealii; +namespace SE = SymEngine; + +int +main(int argc, char *argv[]) +{ + initlog(); + + // 0. Define some independent variables + // Here we have two definitions of Q: One it is treated as a completely + // indepdent variable, and the other where its dependence on C is + // explicitly defined + SE::RCP C = SE::symbol("C"); // Primary variable + SE::RCP Qi = SE::symbol("Qi"); // Some internal variable + SE::RCP Q = + SE::function_symbol("Q", C); // This sets up the dependence of Q on C + + deallog << *C << ", " << *Qi << ", " << *Q << std::endl; + + // 1. Define a function with Q being independent of C + SE::RCP f_CQ_symb = + SE::mul(SE::real_double(0.5), SE::mul(Qi, SE::pow(C, SE::integer(2)))); + + deallog << "f_CQ_symb: " << *f_CQ_symb << std::endl; + + // 2. Compute the partial derivative of f wrt C. This is a "partial + // derivative" as Q != Q(C). + SE::RCP df_CQ_dC_symb = f_CQ_symb->diff(C); + + deallog << "df_CQ_dC_symb: " << *df_CQ_dC_symb << std::endl; + + // 3. Substitute Qi -> Q=Q(C) to now make SymEngine aware of Q's dependence + // on C. + SE::map_basic_basic int_var_dict; + int_var_dict[Qi] = Q; + SE::RCP df_CQ_dC_symb_subs = + df_CQ_dC_symb->subs(int_var_dict); + + deallog << "df_CQ_dC_symb_subs: " << *df_CQ_dC_symb_subs << std::endl; + + // 4. Compute total derivative of df_dC wrt C. + SE::RCP D2f_CQ_DC_dC_symb = df_CQ_dC_symb_subs->diff(C); + + deallog << "D2f_CQ_DC_dC_symb: " << *D2f_CQ_DC_dC_symb << std::endl; + + // 5. Perform some numerical substitutions + SE::map_basic_basic all_var_dict; + all_var_dict[C] = SE::real_double(5); + all_var_dict[Qi] = SE::real_double(3); + all_var_dict[Q] = + SE::mul(SE::real_double(0.6), + C); // This explicitly defines the relationship between Q and C + + SE::RCP f_CQ_subs = f_CQ_symb->subs(all_var_dict); + deallog << "f_CQ_subs: " << *f_CQ_subs << std::endl; + + SE::RCP df_CQ_dC_subs = df_CQ_dC_symb->subs(all_var_dict); + deallog << "df_CQ_dC: subs: " << *df_CQ_dC_subs << std::endl + << "df_CQ_dC: eval: " << SE::eval_double(*df_CQ_dC_subs) << std::endl; + + // This first substitution should presumably convert Q(C)->0.6C and thus + // dQ(C)_dC into 0.6 + SE::RCP D2f_CQ_DC_dC_subs_1 = + D2f_CQ_DC_dC_symb->subs(all_var_dict); + // This second substitution should fill out the remaining entries for C + SE::RCP D2f_CQ_DC_dC_subs = + D2f_CQ_DC_dC_subs_1->subs(all_var_dict); + deallog << "D2f_CQ_DC_dC: subs 1: " << *D2f_CQ_DC_dC_subs_1 << std::endl + << "D2f_CQ_DC_dC: subs 2: " << *D2f_CQ_DC_dC_subs << std::endl + << "D2f_CQ_DC_dC: eval: " << SE::eval_double(*D2f_CQ_DC_dC_subs) + << std::endl; + + return 0; +} diff --git a/tests/symengine/basic_06.output b/tests/symengine/basic_06.output new file mode 100644 index 000000000000..ad5bc7ba117a --- /dev/null +++ b/tests/symengine/basic_06.output @@ -0,0 +1,12 @@ + +DEAL::C, Qi, Q(C) +DEAL::f_CQ_symb: 0.5*C**2*Qi +DEAL::df_CQ_dC_symb: 1.0*C*Qi +DEAL::df_CQ_dC_symb_subs: 1.0*C*Q(C) +DEAL::D2f_CQ_DC_dC_symb: 1.0*C*Derivative(Q(C), C) + 1.0*Q(C) +DEAL::f_CQ_subs: 37.5 +DEAL::df_CQ_dC: subs: 15. +DEAL::df_CQ_dC: eval: 15.0000 +DEAL::D2f_CQ_DC_dC: subs 1: 3.0 + 0.6*C +DEAL::D2f_CQ_DC_dC: subs 2: 6.0 +DEAL::D2f_CQ_DC_dC: eval: 6.00000 diff --git a/tests/symengine/basic_07.cc b/tests/symengine/basic_07.cc new file mode 100644 index 000000000000..2963db1902a9 --- /dev/null +++ b/tests/symengine/basic_07.cc @@ -0,0 +1,123 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 - 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 at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +// Check that SymEngine can do delayed substitution of implicitly dependent +// symbolic functions and evaluate their derivatives as well. +// This is inline with what is required to implement some material laws that +// have internal variables + +#include "../tests.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wextra-semi" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic pop + +#include +#include + +using namespace dealii; +namespace SE = SymEngine; + +int +main(int argc, char *argv[]) +{ + initlog(); + + // 0. Define some independent variables + // Here we have two definitions of Q: One it is treated as a completely + // independent variable, and the other where its dependence on C is + // implicitly defined + // That is to say, we'd have to compute Q=Q(C) using a nonlinear solution + // scheme, as might be the case for a viscoelastic material with a + // nonlinear evolution law. + SE::RCP C = SE::symbol("C"); // Primary variable + SE::RCP Qi = SE::symbol("Qi"); // Some internal variable + SE::RCP Q = + SE::function_symbol("Q", C); // This sets up the dependence of Q on C + + deallog << *C << ", " << *Qi << ", " << *Q << std::endl; + + // 1. Define a function with Q being independent of C + SE::RCP f_CQ_symb = + SE::mul(SE::real_double(0.5), SE::mul(Qi, SE::pow(C, SE::integer(2)))); + + deallog << "f_CQ_symb: " << *f_CQ_symb << std::endl; + + // 2. Compute the partial derivative of f wrt C. This is a "partial + // derivative" as Q != Q(C). + SE::RCP df_CQ_dC_symb = f_CQ_symb->diff(C); + + deallog << "df_CQ_dC_symb: " << *df_CQ_dC_symb << std::endl; + + // 3. Substitute Qi -> Q=Q(C) to now make SymEngine aware of Q's dependence + // on C. + SE::map_basic_basic int_var_dict; + int_var_dict[Qi] = Q; + SE::RCP df_CQ_dC_symb_subs = + df_CQ_dC_symb->subs(int_var_dict); + + deallog << "df_CQ_dC_symb_subs: " << *df_CQ_dC_symb_subs << std::endl; + + // 4. Compute total derivative of df_dC wrt C. + SE::RCP D2f_CQ_DC_dC_symb = df_CQ_dC_symb_subs->diff(C); + + deallog << "D2f_CQ_DC_dC_symb: " << *D2f_CQ_DC_dC_symb << std::endl; + + // 5. Perform some numerical substitutions + // Lets assume Q = 0.6*C*C + // Then dQ_dC = 1.2*C + SE::map_basic_basic all_var_dict; + all_var_dict[C] = SE::real_double(5); + all_var_dict[Qi] = + SE::real_double(0.6 * 5 * 5); // This would be the numerical end result of + // an internal nonlinear solver for Q + all_var_dict[Q] = Qi; // These are numerically the same thing + all_var_dict[Q->diff(C)] = + SE::mul(SE::real_double(1.2), + C); // This resolves the implicit relationship between Q and C + + SE::RCP f_CQ_subs = f_CQ_symb->subs(all_var_dict); + deallog << "f_CQ_subs: " << *f_CQ_subs << std::endl; + + SE::RCP df_CQ_dC_subs = df_CQ_dC_symb->subs(all_var_dict); + deallog << "df_CQ_dC: subs: " << *df_CQ_dC_subs << std::endl + << "df_CQ_dC: eval: " << SE::eval_double(*df_CQ_dC_subs) << std::endl; + + // This first substitution should presumably convert Q(C)->0.6C and thus + // dQ(C)_dC into 0.6 + SE::RCP D2f_CQ_DC_dC_subs_1 = + D2f_CQ_DC_dC_symb->subs(all_var_dict); + // This second substitution should fill out the remaining entries for C + SE::RCP D2f_CQ_DC_dC_subs = + D2f_CQ_DC_dC_subs_1->subs(all_var_dict); + deallog << "D2f_CQ_DC_dC: subs 1: " << *D2f_CQ_DC_dC_subs_1 << std::endl + << "D2f_CQ_DC_dC: subs 2: " << *D2f_CQ_DC_dC_subs << std::endl + << "D2f_CQ_DC_dC: eval: " << SE::eval_double(*D2f_CQ_DC_dC_subs) + << std::endl; + + return 0; +} diff --git a/tests/symengine/basic_07.output b/tests/symengine/basic_07.output new file mode 100644 index 000000000000..6b1e0b525cd5 --- /dev/null +++ b/tests/symengine/basic_07.output @@ -0,0 +1,12 @@ + +DEAL::C, Qi, Q(C) +DEAL::f_CQ_symb: 0.5*C**2*Qi +DEAL::df_CQ_dC_symb: 1.0*C*Qi +DEAL::df_CQ_dC_symb_subs: 1.0*C*Q(C) +DEAL::D2f_CQ_DC_dC_symb: 1.0*C*Derivative(Q(C), C) + 1.0*Q(C) +DEAL::f_CQ_subs: 187.5 +DEAL::df_CQ_dC: subs: 75. +DEAL::df_CQ_dC: eval: 75.0000 +DEAL::D2f_CQ_DC_dC: subs 1: 6.0*C + 1.0*Qi +DEAL::D2f_CQ_DC_dC: subs 2: 45.0 +DEAL::D2f_CQ_DC_dC: eval: 45.0000 From ae76d46602dee986943538700a1b4f1b0a69a723 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Fri, 15 Mar 2019 21:48:39 +0100 Subject: [PATCH 269/507] extend DoFRenumbering::cell_wise to parallel::Triangulation --- source/dofs/dof_renumbering.cc | 80 +++++++++++++++++----------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/source/dofs/dof_renumbering.cc b/source/dofs/dof_renumbering.cc index adc401e0f70d..087479b3dd25 100644 --- a/source/dofs/dof_renumbering.cc +++ b/source/dofs/dof_renumbering.cc @@ -1592,8 +1592,9 @@ namespace DoFRenumbering DoFHandlerType & dof, const std::vector &cells) { - std::vector renumbering(dof.n_dofs()); - std::vector reverse(dof.n_dofs()); + std::vector renumbering( + dof.n_locally_owned_dofs()); + std::vector reverse(dof.n_locally_owned_dofs()); compute_cell_wise(renumbering, reverse, dof, cells); dof.renumber_dofs(renumbering); @@ -1609,69 +1610,70 @@ namespace DoFRenumbering const typename std::vector &cells) { - Assert(cells.size() == dof.get_triangulation().n_active_cells(), - ExcDimensionMismatch(cells.size(), - dof.get_triangulation().n_active_cells())); + if (const parallel::Triangulation *p = + dynamic_cast< + const parallel::Triangulation *>( + &dof.get_triangulation())) + { + AssertDimension(cells.size(), p->n_locally_owned_active_cells()); + } + else + { + AssertDimension(cells.size(), dof.get_triangulation().n_active_cells()); + } - types::global_dof_index n_global_dofs = dof.n_dofs(); + const auto n_owned_dofs = dof.n_locally_owned_dofs(); - // Actually, we compute the - // inverse of the reordering - // vector, called reverse here. - // Later, irs inverse is computed - // into new_indices, which is the + // Actually, we compute the inverse of the reordering vector, called reverse + // here. Later, its inverse is computed into new_indices, which is the // return argument. - Assert(new_indices.size() == n_global_dofs, - ExcDimensionMismatch(new_indices.size(), n_global_dofs)); - Assert(reverse.size() == n_global_dofs, - ExcDimensionMismatch(reverse.size(), n_global_dofs)); + AssertDimension(new_indices.size(), n_owned_dofs); + AssertDimension(reverse.size(), n_owned_dofs); - // For continuous elements, we must - // make sure, that each dof is - // reordered only once. - std::vector already_sorted(n_global_dofs, false); + // For continuous elements, we must make sure, that each dof is reordered + // only once. + std::vector already_sorted(n_owned_dofs, false); std::vector cell_dofs; - unsigned int global_index = 0; + const auto &owned_dofs = dof.locally_owned_dofs(); - typename std::vector< - typename DoFHandlerType::active_cell_iterator>::const_iterator cell; + unsigned int index = 0; - for (cell = cells.begin(); cell != cells.end(); ++cell) + for (const auto &cell : cells) { - // Determine the number of dofs - // on this cell and reinit the - // vector storing these - // numbers. - unsigned int n_cell_dofs = (*cell)->get_fe().n_dofs_per_cell(); + // Determine the number of dofs on this cell and reinit the + // vector storing these numbers. + const unsigned int n_cell_dofs = cell->get_fe().n_dofs_per_cell(); cell_dofs.resize(n_cell_dofs); - (*cell)->get_active_or_mg_dof_indices(cell_dofs); + cell->get_active_or_mg_dof_indices(cell_dofs); - // Sort here to make sure that - // degrees of freedom inside a - // single cell are in the same - // order after renumbering. + // Sort here to make sure that degrees of freedom inside a single cell + // are in the same order after renumbering. std::sort(cell_dofs.begin(), cell_dofs.end()); - for (unsigned int i = 0; i < n_cell_dofs; ++i) + for (const auto dof : cell_dofs) { - if (!already_sorted[cell_dofs[i]]) + const auto local_dof = owned_dofs.index_within_set(dof); + if (local_dof != numbers::invalid_dof_index && + !already_sorted[local_dof]) { - already_sorted[cell_dofs[i]] = true; - reverse[global_index++] = cell_dofs[i]; + already_sorted[local_dof] = true; + reverse[index++] = local_dof; } } } - Assert(global_index == n_global_dofs, + Assert(index == n_owned_dofs, ExcMessage( "Traversing over the given set of cells did not cover all " "degrees of freedom in the DoFHandler. Does the set of cells " "not include all active cells?")); for (types::global_dof_index i = 0; i < reverse.size(); ++i) - new_indices[reverse[i]] = i; + new_indices[reverse[i]] = owned_dofs.nth_index_in_set(i); } From 9eaa95d30a4987173c9147215b6e08e91c9c86bf Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Sat, 16 Mar 2019 07:31:05 +0100 Subject: [PATCH 270/507] add a test for DoFRenumbering::cell_wise() with p::d::Tria --- tests/dofs/dof_renumbering_10.cc | 172 ++++++++++++++++++ ...mbering_10.with_p4est=true.mpirun=1.output | 19 ++ ...mbering_10.with_p4est=true.mpirun=3.output | 27 +++ 3 files changed, 218 insertions(+) create mode 100644 tests/dofs/dof_renumbering_10.cc create mode 100644 tests/dofs/dof_renumbering_10.with_p4est=true.mpirun=1.output create mode 100644 tests/dofs/dof_renumbering_10.with_p4est=true.mpirun=3.output diff --git a/tests/dofs/dof_renumbering_10.cc b/tests/dofs/dof_renumbering_10.cc new file mode 100644 index 000000000000..ff0204b52567 --- /dev/null +++ b/tests/dofs/dof_renumbering_10.cc @@ -0,0 +1,172 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// test cell_wise with p::d::Tria + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "../tests.h" + +template +void +test(const bool adaptive_ref = true) +{ + MPI_Comm mpi_communicator(MPI_COMM_WORLD); + const unsigned int this_mpi_core = + dealii::Utilities::MPI::this_mpi_process(mpi_communicator); + + parallel::distributed::Triangulation tria(mpi_communicator); + GridGenerator::hyper_cube(tria, 0, 1, true); + tria.refine_global(1); + if (adaptive_ref) + { + for (auto cell : tria.active_cell_iterators()) + if (cell->is_locally_owned()) + if (cell->center().norm() < 0.5) + cell->set_refine_flag(); + tria.execute_coarsening_and_refinement(); + for (auto cell : tria.active_cell_iterators()) + if (cell->is_locally_owned()) + if (cell->center()[0] < 0.2) + cell->set_refine_flag(); + tria.execute_coarsening_and_refinement(); + } + else + { + tria.refine_global(1); + } + + FE_Q fe(fe_degree); + DoFHandler dof(tria); + dof.distribute_dofs(fe); + + using CELL = typename DoFHandler::active_cell_iterator; + std::vector cell_order; + for (auto &cell : dof.active_cell_iterators()) + if (cell->is_locally_owned()) + cell_order.push_back(cell); + + std::sort(cell_order.begin(), + cell_order.end(), + [](const CELL &a, const CELL &b) { + std::vector p1(dim), p2(dim); + for (unsigned int d = 0; d < dim; ++d) + { + p1[d] = a->center()[d]; + p2[d] = b->center()[d]; + } + return std::lexicographical_compare(p1.begin(), + p1.end(), + p2.begin(), + p2.end()); + }); + + DoFRenumbering::cell_wise(dof, cell_order); + + deallog << std::endl << "cell order:" << std::endl; + std::vector cell_dofs(fe.n_dofs_per_cell()); + for (const auto &c : cell_order) + { + c->get_active_or_mg_dof_indices(cell_dofs); + deallog << c->center() << ":"; + for (const auto d : cell_dofs) + deallog << " " << d; + deallog << std::endl; + } + + IndexSet owned_set = dof.locally_owned_dofs(); + + // output in Gnuplot for visual inspection + if (dim == 2) + { + std::map> support_points; + MappingQ1 mapping; + DoFTools::map_dofs_to_support_points(mapping, dof, support_points); + + const std::string href = (adaptive_ref ? "" : "global_"); + const std::string base_filename = + href + "grid" + dealii::Utilities::int_to_string(dim) + "_" + + dealii::Utilities::int_to_string(fe_degree) + "_p" + + dealii::Utilities::int_to_string(this_mpi_core); + + const std::string filename = base_filename + ".gp"; + std::ofstream f(filename.c_str()); + + f << "set terminal png size 400,410 enhanced font \"Helvetica,8\"" + << std::endl + << "set output \"" << base_filename << ".png\"" << std::endl + << "set size square" << std::endl + << "set view equal xy" << std::endl + << "unset xtics" << std::endl + << "unset ytics" << std::endl + << "unset grid" << std::endl + << "unset border" << std::endl + << "plot '-' using 1:2 with lines notitle, '-' with labels tc rgb 'red' nopoint notitle, '-' with labels point pt 4 offset 1,1 notitle" + << std::endl; + GridOut().write_gnuplot(tria, f); + f << "e" << std::endl; + + // output cell order + for (unsigned int index = 0; index < cell_order.size(); ++index) + f << cell_order[index]->center() << " \"" << index << "\"\n"; + + f << std::flush; + f << "e" << std::endl << std::endl; + + // output only owned support points + for (auto it = support_points.cbegin(); it != support_points.cend();) + { + if (owned_set.is_element(it->first)) + ++it; + else + support_points.erase(it++); + } + + DoFTools::write_gnuplot_dof_support_point_info(f, support_points); + + f << "e" << std::endl; + } +} + + +int +main(int argc, char **argv) +{ + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + MPILogInitAll log; + + test<2>(false); + + return 0; +} diff --git a/tests/dofs/dof_renumbering_10.with_p4est=true.mpirun=1.output b/tests/dofs/dof_renumbering_10.with_p4est=true.mpirun=1.output new file mode 100644 index 000000000000..2801b5dd09ec --- /dev/null +++ b/tests/dofs/dof_renumbering_10.with_p4est=true.mpirun=1.output @@ -0,0 +1,19 @@ + +DEAL:0:: +DEAL:0::cell order: +DEAL:0::0.125000 0.125000: 0 1 2 3 +DEAL:0::0.125000 0.375000: 2 3 4 5 +DEAL:0::0.125000 0.625000: 4 5 6 7 +DEAL:0::0.125000 0.875000: 6 7 8 9 +DEAL:0::0.375000 0.125000: 1 10 3 11 +DEAL:0::0.375000 0.375000: 3 11 5 12 +DEAL:0::0.375000 0.625000: 5 12 7 13 +DEAL:0::0.375000 0.875000: 7 13 9 14 +DEAL:0::0.625000 0.125000: 10 15 11 16 +DEAL:0::0.625000 0.375000: 11 16 12 17 +DEAL:0::0.625000 0.625000: 12 17 13 18 +DEAL:0::0.625000 0.875000: 13 18 14 19 +DEAL:0::0.875000 0.125000: 15 20 16 21 +DEAL:0::0.875000 0.375000: 16 21 17 22 +DEAL:0::0.875000 0.625000: 17 22 18 23 +DEAL:0::0.875000 0.875000: 18 23 19 24 diff --git a/tests/dofs/dof_renumbering_10.with_p4est=true.mpirun=3.output b/tests/dofs/dof_renumbering_10.with_p4est=true.mpirun=3.output new file mode 100644 index 000000000000..bba8f1109583 --- /dev/null +++ b/tests/dofs/dof_renumbering_10.with_p4est=true.mpirun=3.output @@ -0,0 +1,27 @@ + +DEAL:0:: +DEAL:0::cell order: +DEAL:0::0.125000 0.125000: 0 1 2 3 +DEAL:0::0.125000 0.375000: 2 3 4 5 +DEAL:0::0.375000 0.125000: 1 6 3 7 +DEAL:0::0.375000 0.375000: 3 7 5 8 + +DEAL:1:: +DEAL:1::cell order: +DEAL:1::0.125000 0.625000: 4 5 9 10 +DEAL:1::0.125000 0.875000: 9 10 11 12 +DEAL:1::0.375000 0.625000: 5 8 10 13 +DEAL:1::0.375000 0.875000: 10 13 12 14 +DEAL:1::0.625000 0.125000: 6 15 7 16 +DEAL:1::0.625000 0.375000: 7 16 8 17 +DEAL:1::0.875000 0.125000: 15 18 16 19 +DEAL:1::0.875000 0.375000: 16 19 17 20 + + +DEAL:2:: +DEAL:2::cell order: +DEAL:2::0.625000 0.625000: 8 17 13 21 +DEAL:2::0.625000 0.875000: 13 21 14 22 +DEAL:2::0.875000 0.625000: 17 20 21 23 +DEAL:2::0.875000 0.875000: 21 23 22 24 + From f7e260e613fe4466862d45d99a0d4a75b094f005 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Sat, 16 Mar 2019 07:33:08 +0100 Subject: [PATCH 271/507] rename changelog --- .../changes/minor/{20190411TimoHeister => 20190311TimoHeister} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/news/changes/minor/{20190411TimoHeister => 20190311TimoHeister} (100%) diff --git a/doc/news/changes/minor/20190411TimoHeister b/doc/news/changes/minor/20190311TimoHeister similarity index 100% rename from doc/news/changes/minor/20190411TimoHeister rename to doc/news/changes/minor/20190311TimoHeister From 6cdac1935475d6fdf4a9cfce8a20beccd77b185e Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Sat, 16 Mar 2019 07:42:03 +0100 Subject: [PATCH 272/507] adjust documentation and add a changelog --- doc/news/changes/minor/20190316DenisDavydov | 3 ++ include/deal.II/dofs/dof_renumbering.h | 54 ++++++++++++--------- 2 files changed, 33 insertions(+), 24 deletions(-) create mode 100644 doc/news/changes/minor/20190316DenisDavydov 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/include/deal.II/dofs/dof_renumbering.h b/include/deal.II/dofs/dof_renumbering.h index 445fedd07883..cfd883283752 100644 --- a/include/deal.II/dofs/dof_renumbering.h +++ b/include/deal.II/dofs/dof_renumbering.h @@ -838,10 +838,10 @@ namespace DoFRenumbering /** * Renumber degrees of freedom by cell. The function takes a vector of cell - * iterators (which needs to list all active cells of the DoF handler - * objects) and will give degrees of freedom new indices based on where in - * the given list of cells the cell is on which the degree of freedom is - * located. Degrees of freedom that exist at the interface between two or + * iterators (which needs to list all locally owned active cells of the + * DoF handler objects) and will give degrees of freedom new indices based on + * where in the given list of cells the cell is on which the degree of freedom + * is located. Degrees of freedom that exist at the interface between two or * more cells will be numbered when they are encountered first. * * Degrees of freedom that are encountered first on the same cell retain @@ -852,10 +852,12 @@ namespace DoFRenumbering * @param[in] cell_order A vector that contains the order of the cells that * defines the order in which degrees of freedom should be renumbered. * - * @pre @p cell_order must have size - * dof_handler.get_triangulation().n_active_cells(). Every - * active cell iterator of that triangulation needs to be present in @p - * cell_order exactly once. + * @pre for serial triangulation @p cell_order must have size + * dof_handler.get_triangulation().n_active_cells(), whereas + * in case of parallel triangulation its size should be + * parallel::Triangulation::n_locally_owned_active_cells(). Every active cell + * iterator of that triangulation needs to be present in @p cell_order exactly + * once. */ template void @@ -865,34 +867,38 @@ namespace DoFRenumbering /** * Compute a renumbering of degrees of freedom by cell. The function takes a - * vector of cell iterators (which needs to list all active cells of - * the DoF handler objects) and will give degrees of freedom new indices - * based on where in the given list of cells the cell is on which the degree - * of freedom is located. Degrees of freedom that exist at the interface - * between two or more cells will be numbered when they are encountered - * first. + * vector of cell iterators (which needs to list all locally owned + * active cells of the DoF handler objects) and will give degrees of freedom + * new indices based on where in the given list of cells the cell is on which + * the degree of freedom is located. Degrees of freedom that exist at the + * interface between two or more cells will be numbered when they are + * encountered first. * * Degrees of freedom that are encountered first on the same cell retain * their original ordering before the renumbering step. * * @param[out] renumbering A vector of length - * dof_handler.n_dofs() that contains for each degree of - * freedom (in their current numbering) their future DoF index. This vector - * therefore presents a (very particular) permutation of the current - * DoF indices. + * dof_handler.n_locally_owned_dofs() that contains for each + * degree of freedom (in their current numbering) their future DoF index. This + * vector therefore presents a (very particular) permutation of the + * current DoF indices. * @param[out] inverse_renumbering The reverse of the permutation returned - * in the previous argument. + * in the previous argument. In case of parallel::Triangulation the inverse + * is within locally owned DoFs. * @param[in] dof_handler The DoFHandler whose degrees of freedom are to be * renumbered. * @param[in] cell_order A vector that contains the order of the cells that * defines the order in which degrees of freedom should be renumbered. * - * @pre @p cell_order must have size - * dof_handler.get_triangulation().n_active_cells(). Every - * active cell iterator of that triangulation needs to be present in @p + * @pre for serial triangulation @p cell_order must have size + * dof_handler.get_triangulation().n_active_cells(), whereas + * in case of parallel triangulation its size should be + * parallel::Triangulation::n_locally_owned_active_cells(). Every active cell + * iterator of that triangulation needs to be present in @p * cell_order exactly once. @post For each @p i between zero and - * dof_handler.n_dofs(), the condition - * renumbering[inverse_renumbering[i]] == i will hold. + * dof_handler.n_locally_owned_dofs(), the condition + * renumbering[inverse_renumbering[i]] == + * dof_handler.locally_owned_dofs().nth_index_in_set(i) will hold. */ template void From df1a79ab3abd6f126e7000972eea4c1c3779bb42 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 16 Mar 2019 01:11:58 +0100 Subject: [PATCH 273/507] Set cell manifold ids when the apply_all_indicators_to_manifold flag is used. --- doc/news/changes/minor/20190316Arndt | 4 ++ include/deal.II/grid/grid_in.h | 3 +- source/grid/grid_in.cc | 3 + tests/grid/grid_in_ucd_02.cc | 77 ++++++++++++++++++++++ tests/grid/grid_in_ucd_02.output | 53 +++++++++++++++ tests/grid/grid_in_ucd_02_grids/grid_1.inp | 4 ++ tests/grid/grid_in_ucd_02_grids/grid_2.inp | 11 ++++ tests/grid/grid_in_ucd_02_grids/grid_3.inp | 29 ++++++++ tests/hp/step-5.cc | 2 +- 9 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 doc/news/changes/minor/20190316Arndt create mode 100644 tests/grid/grid_in_ucd_02.cc create mode 100644 tests/grid/grid_in_ucd_02.output create mode 100644 tests/grid/grid_in_ucd_02_grids/grid_1.inp create mode 100644 tests/grid/grid_in_ucd_02_grids/grid_2.inp create mode 100644 tests/grid/grid_in_ucd_02_grids/grid_3.inp 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/include/deal.II/grid/grid_in.h b/include/deal.II/grid/grid_in.h index d646ead8f41f..73c4be4a3d0d 100644 --- a/include/deal.II/grid/grid_in.h +++ b/include/deal.II/grid/grid_in.h @@ -417,7 +417,8 @@ class GridIn * manifold_id for the same cell. Yet it is possible to use * the flag apply_all_indicators_to_manifolds to decide if * the indicators in the file refer to manifolds (flag set to true) - * or boundaries (flag set to false). + * or boundaries (flag set to false). If the flag is set, the + * indicators are used for cells as manifold id, too. */ void read_ucd(std::istream &in, diff --git a/source/grid/grid_in.cc b/source/grid/grid_in.cc index ad18740f2849..28f2907258f8 100644 --- a/source/grid/grid_in.cc +++ b/source/grid/grid_in.cc @@ -834,6 +834,9 @@ GridIn::read_ucd(std::istream &in, Assert(material_id < numbers::invalid_material_id, ExcIndexRange(material_id, 0, numbers::invalid_material_id)); + if (apply_all_indicators_to_manifolds) + cells.back().manifold_id = + static_cast(material_id); cells.back().material_id = static_cast(material_id); diff --git a/tests/grid/grid_in_ucd_02.cc b/tests/grid/grid_in_ucd_02.cc new file mode 100644 index 000000000000..365849a14d3d --- /dev/null +++ b/tests/grid/grid_in_ucd_02.cc @@ -0,0 +1,77 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Test that cell manifold ids are also set for the +// "apply_all_indicators_to_manifolds" option in GridIn::read_ucd + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../tests.h" + +template +void +test(const std::string &filename) +{ + std::ifstream tmp_in(filename); + Triangulation tria; + GridIn gi; + gi.attach_triangulation(tria); + gi.read_ucd(tmp_in, true); + deallog << "Testing dim=" << dim << " spacedim=" << spacedim << std::endl; + for (const auto &cell : tria.active_cell_iterators()) + { + deallog << "cell->manifold_id: " << cell->manifold_id() << std::endl; + if (dim > 1) + for (unsigned int face_no = 0; + face_no < GeometryInfo::faces_per_cell; + ++face_no) + deallog << "cell->face(" << face_no + << ")->manifold_id: " << cell->face(face_no)->manifold_id() + << std::endl; + if (dim > 1) + for (unsigned int line_no = 0; + line_no < GeometryInfo::lines_per_cell; + ++line_no) + deallog << "cell->line(" << line_no + << ")->manifold_id: " << cell->line(line_no)->manifold_id() + << std::endl; + } + deallog << std::endl; +} + +int +main() +{ + initlog(); + deallog.get_file_stream() << std::setprecision(2); + + test<1, 1>(SOURCE_DIR "/grid_in_ucd_02_grids/grid_1.inp"); + test<1, 2>(SOURCE_DIR "/grid_in_ucd_02_grids/grid_1.inp"); + test<1, 3>(SOURCE_DIR "/grid_in_ucd_02_grids/grid_1.inp"); + test<2, 2>(SOURCE_DIR "/grid_in_ucd_02_grids/grid_2.inp"); + test<2, 3>(SOURCE_DIR "/grid_in_ucd_02_grids/grid_2.inp"); + test<3, 3>(SOURCE_DIR "/grid_in_ucd_02_grids/grid_3.inp"); +} diff --git a/tests/grid/grid_in_ucd_02.output b/tests/grid/grid_in_ucd_02.output new file mode 100644 index 000000000000..0c2306278d36 --- /dev/null +++ b/tests/grid/grid_in_ucd_02.output @@ -0,0 +1,53 @@ + +DEAL::Testing dim=1 spacedim=1 +DEAL::cell->manifold_id: 99 +DEAL:: +DEAL::Testing dim=1 spacedim=2 +DEAL::cell->manifold_id: 99 +DEAL:: +DEAL::Testing dim=1 spacedim=3 +DEAL::cell->manifold_id: 99 +DEAL:: +DEAL::Testing dim=2 spacedim=2 +DEAL::cell->manifold_id: 99 +DEAL::cell->face(0)->manifold_id: 100 +DEAL::cell->face(1)->manifold_id: 100 +DEAL::cell->face(2)->manifold_id: 100 +DEAL::cell->face(3)->manifold_id: 100 +DEAL::cell->line(0)->manifold_id: 100 +DEAL::cell->line(1)->manifold_id: 100 +DEAL::cell->line(2)->manifold_id: 100 +DEAL::cell->line(3)->manifold_id: 100 +DEAL:: +DEAL::Testing dim=2 spacedim=3 +DEAL::cell->manifold_id: 99 +DEAL::cell->face(0)->manifold_id: 100 +DEAL::cell->face(1)->manifold_id: 100 +DEAL::cell->face(2)->manifold_id: 100 +DEAL::cell->face(3)->manifold_id: 100 +DEAL::cell->line(0)->manifold_id: 100 +DEAL::cell->line(1)->manifold_id: 100 +DEAL::cell->line(2)->manifold_id: 100 +DEAL::cell->line(3)->manifold_id: 100 +DEAL:: +DEAL::Testing dim=3 spacedim=3 +DEAL::cell->manifold_id: 99 +DEAL::cell->face(0)->manifold_id: 100 +DEAL::cell->face(1)->manifold_id: 100 +DEAL::cell->face(2)->manifold_id: 100 +DEAL::cell->face(3)->manifold_id: 100 +DEAL::cell->face(4)->manifold_id: 100 +DEAL::cell->face(5)->manifold_id: 100 +DEAL::cell->line(0)->manifold_id: 101 +DEAL::cell->line(1)->manifold_id: 101 +DEAL::cell->line(2)->manifold_id: 101 +DEAL::cell->line(3)->manifold_id: 101 +DEAL::cell->line(4)->manifold_id: 101 +DEAL::cell->line(5)->manifold_id: 101 +DEAL::cell->line(6)->manifold_id: 101 +DEAL::cell->line(7)->manifold_id: 101 +DEAL::cell->line(8)->manifold_id: 101 +DEAL::cell->line(9)->manifold_id: 101 +DEAL::cell->line(10)->manifold_id: 101 +DEAL::cell->line(11)->manifold_id: 101 +DEAL:: diff --git a/tests/grid/grid_in_ucd_02_grids/grid_1.inp b/tests/grid/grid_in_ucd_02_grids/grid_1.inp new file mode 100644 index 000000000000..f6446ee5320a --- /dev/null +++ b/tests/grid/grid_in_ucd_02_grids/grid_1.inp @@ -0,0 +1,4 @@ +2 1 0 0 0 +1 0 0 0 +2 1 0 0 +1 99 line 1 2 diff --git a/tests/grid/grid_in_ucd_02_grids/grid_2.inp b/tests/grid/grid_in_ucd_02_grids/grid_2.inp new file mode 100644 index 000000000000..41efaf5f68d1 --- /dev/null +++ b/tests/grid/grid_in_ucd_02_grids/grid_2.inp @@ -0,0 +1,11 @@ +4 5 0 0 0 +1 0 0 0 +2 1 0 0 +3 0 1 0 +4 1 1 0 +1 99 quad 1 2 4 3 +2 100 line 1 2 +3 100 line 2 4 +4 100 line 4 3 +5 100 line 3 1 + diff --git a/tests/grid/grid_in_ucd_02_grids/grid_3.inp b/tests/grid/grid_in_ucd_02_grids/grid_3.inp new file mode 100644 index 000000000000..5218408f06a8 --- /dev/null +++ b/tests/grid/grid_in_ucd_02_grids/grid_3.inp @@ -0,0 +1,29 @@ +8 19 0 0 0 +1 0 0 0 +2 1 0 0 +3 0 1 0 +4 1 1 0 +5 0 0 1 +6 1 0 1 +7 0 1 1 +8 1 1 1 +1 99 hex 1 2 6 5 3 4 8 7 +2 100 quad 1 2 4 3 +3 100 quad 5 6 8 7 +4 100 quad 1 2 6 5 +5 100 quad 3 4 8 7 +6 100 quad 1 3 7 5 +7 100 quad 2 4 8 6 +8 101 line 1 2 +9 101 line 2 4 +10 101 line 4 3 +11 101 line 3 1 +12 101 line 5 6 +13 101 line 6 8 +14 101 line 8 7 +15 101 line 7 5 +16 101 line 1 5 +17 101 line 2 6 +18 101 line 3 7 +19 101 line 4 8 + diff --git a/tests/hp/step-5.cc b/tests/hp/step-5.cc index 17d2393719a8..af23e503353f 100644 --- a/tests/hp/step-5.cc +++ b/tests/hp/step-5.cc @@ -306,7 +306,7 @@ LaplaceProblem::run() std::ifstream input_file(SOURCE_DIR "/grids/circle-grid.inp"); Assert(dim == 2, ExcInternalError()); - grid_in.read_ucd(input_file, true); + grid_in.read_ucd(input_file); GridTools::copy_boundary_to_manifold_id(triangulation); static const SphericalManifold boundary; From 2ce8a65aa17fe34b799702c01ae95b92a73025f5 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 16 Mar 2019 13:50:01 +0100 Subject: [PATCH 274/507] Check SCALAPACK symbols --- cmake/configure/configure_scalapack.cmake | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/cmake/configure/configure_scalapack.cmake b/cmake/configure/configure_scalapack.cmake index 86ac09a3ab1a..273689bf1c28 100644 --- a/cmake/configure/configure_scalapack.cmake +++ b/cmake/configure/configure_scalapack.cmake @@ -26,6 +26,44 @@ MACRO(FEATURE_SCALAPACK_FIND_EXTERNAL var) IF(SCALAPACK_FOUND) SET(${var} TRUE) CHECK_MPI_INTERFACE(SCALAPACK ${var}) + + IF (${var}) + CHECK_LIBRARY_EXISTS (${SCALAPACK_LIBRARY} pdsyevr_ {SCALAPACK_DIR} DEAL_II_SCALAPACK_HAS_PDSYEVR) + IF(NOT DEAL_II_SCALAPACK_HAS_PDSYEVR) + MESSAGE(STATUS "Could not find a sufficient SCALAPACK installation: " + "The required symbol pdsyevr_ was not found." + ) + SET(SCALAPACK_ADDITIONAL_ERROR_STRING + ${SCALAPACK_ADDITIONAL_ERROR_STRING} + "Could not find a sufficient SCALAPACK installation: \n" + "SCALAPACK symbol check for pdsyevr_ 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() + + IF(${var}) + CHECK_LIBRARY_EXISTS (${SCALAPACK_LIBRARY} pssyevr_ {SCALAPACK_DIR} DEAL_II_SCALAPACK_HAS_PSSYEVR) + IF(NOT DEAL_II_SCALAPACK_HAS_PSSYEVR) + MESSAGE(STATUS "Could not find a sufficient SCALAPACK installation: " + "The required symbol pssyevr_ was not found." + ) + SET(SCALAPACK_ADDITIONAL_ERROR_STRING + ${SCALAPACK_ADDITIONAL_ERROR_STRING} + "Could not find a sufficient SCALAPACK installation: \n" + "SCALAPACK symbol check for 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() From 8d8fb9c8388ff35237ba183cd2af698e20ac2ec2 Mon Sep 17 00:00:00 2001 From: Sebastian Stark Date: Fri, 22 Feb 2019 15:09:35 +0200 Subject: [PATCH 275/507] interpolate_to_different_mesh for hp::DoFHandler Make interpolate_to_different_mesh work with hp::DoFHandler objects. Added also four tests for the implementation as well as the relevant instantiations. --- doc/news/changes/minor/20190316SebastianStark | 3 + .../deal.II/numerics/vector_tools.templates.h | 34 +- .../numerics/vector_tools_interpolate.inst.in | 23 + .../interpolate_to_different_mesh_01.cc | 152 ++ .../interpolate_to_different_mesh_01.output | 1069 ++++++++ .../interpolate_to_different_mesh_02.cc | 164 ++ .../interpolate_to_different_mesh_02.output | 2173 +++++++++++++++++ .../interpolate_to_different_mesh_03.cc | 109 + .../interpolate_to_different_mesh_03.output | 17 + .../interpolate_to_different_mesh_04.cc | 133 + .../interpolate_to_different_mesh_04.output | 25 + 11 files changed, 3891 insertions(+), 11 deletions(-) create mode 100644 doc/news/changes/minor/20190316SebastianStark create mode 100644 tests/numerics/interpolate_to_different_mesh_01.cc create mode 100644 tests/numerics/interpolate_to_different_mesh_01.output create mode 100644 tests/numerics/interpolate_to_different_mesh_02.cc create mode 100644 tests/numerics/interpolate_to_different_mesh_02.output create mode 100644 tests/numerics/interpolate_to_different_mesh_03.cc create mode 100644 tests/numerics/interpolate_to_different_mesh_03.output create mode 100644 tests/numerics/interpolate_to_different_mesh_04.cc create mode 100644 tests/numerics/interpolate_to_different_mesh_04.output 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/include/deal.II/numerics/vector_tools.templates.h b/include/deal.II/numerics/vector_tools.templates.h index 30e5fa5f1fe5..3b74b1b5cb30 100644 --- a/include/deal.II/numerics/vector_tools.templates.h +++ b/include/deal.II/numerics/vector_tools.templates.h @@ -812,7 +812,6 @@ namespace VectorTools } } // namespace internal - template active() && !cell2->is_locally_owned()) continue; - Assert( - cell1->get_fe().get_name() == cell2->get_fe().get_name(), - ExcMessage( - "Source and destination cells need to use the same finite element")); - - cache.reinit(cell1->get_fe().dofs_per_cell); - // Get and set the corresponding // dof_values by interpolation. - cell1->get_interpolated_dof_values(u1, cache); - cell2->set_dof_values_by_interpolation(cache, u2); + if (cell1->active()) + { + cache.reinit(cell1->get_fe().dofs_per_cell); + cell1->get_interpolated_dof_values(u1, + cache, + cell1->active_fe_index()); + cell2->set_dof_values_by_interpolation(cache, + u2, + cell1->active_fe_index()); + } + else + { + cache.reinit(cell2->get_fe().dofs_per_cell); + cell1->get_interpolated_dof_values(u1, + cache, + cell2->active_fe_index()); + cell2->set_dof_values_by_interpolation(cache, + u2, + cell2->active_fe_index()); + } } // finish the work on parallel vectors @@ -893,7 +906,6 @@ namespace VectorTools constraints.distribute(u2); } - namespace internal { /** diff --git a/source/numerics/vector_tools_interpolate.inst.in b/source/numerics/vector_tools_interpolate.inst.in index 2fe1aba08087..7d08e95194c8 100644 --- a/source/numerics/vector_tools_interpolate.inst.in +++ b/source/numerics/vector_tools_interpolate.inst.in @@ -132,6 +132,29 @@ for (VEC : VECTOR_TYPES; deal_II_dimension : DIMENSIONS; const VEC &, const AffineConstraints &, VEC &); + + template void + interpolate_to_different_mesh( + const hp::DoFHandler &, + const VEC &, + const hp::DoFHandler &, + VEC &); + + template void + interpolate_to_different_mesh( + const hp::DoFHandler &, + const VEC &, + const hp::DoFHandler &, + const AffineConstraints &, + VEC &); + + template void + interpolate_to_different_mesh( + const InterGridMap< + hp::DoFHandler> &, + const VEC &, + const AffineConstraints &, + VEC &); \} #endif } diff --git a/tests/numerics/interpolate_to_different_mesh_01.cc b/tests/numerics/interpolate_to_different_mesh_01.cc new file mode 100644 index 000000000000..08663a9041c8 --- /dev/null +++ b/tests/numerics/interpolate_to_different_mesh_01.cc @@ -0,0 +1,152 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2000 - 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. +// +// --------------------------------------------------------------------- + +// test for interpolate_to_different_mesh with dealii::DoFHandler + +#include + +#include + +#include +#include + +#include + +#include + +#include +#include + +#include "../tests.h" + +using namespace std; +using namespace dealii; + +template +class F1 : public Function +{ +public: + F1() + : Function() + {} + virtual double + value(const Point &p, const unsigned int component = 0) const + { + return p(0) * p(0); + } +}; + +template +void +check(const unsigned int refinement_1, const unsigned int refinement_2) +{ + MappingQGeneric mapping(1); + + Triangulation tria_1, tria_2; + GridGenerator::hyper_cube(tria_1); + GridGenerator::hyper_cube(tria_2); + + tria_1.refine_global(refinement_1); + tria_2.refine_global(refinement_2); + + DoFHandler dof_handler_1(tria_1); + DoFHandler dof_handler_2(tria_2); + + FE_Q fe(1); + dof_handler_1.distribute_dofs(fe); + dof_handler_2.distribute_dofs(fe); + + Vector u_1(dof_handler_1.n_dofs()), u_2(dof_handler_2.n_dofs()); + F1 f_1; + VectorTools::interpolate(mapping, dof_handler_1, f_1, u_1); + VectorTools::interpolate_to_different_mesh(dof_handler_1, + u_1, + dof_handler_2, + u_2); + + Point support_point, unit_support_point; + vector local_dof_indices(fe.n_dofs_per_cell()); + deallog << "dof values of dof_handler_1:" << endl; + for (const auto &cell : dof_handler_1.active_cell_iterators()) + { + cell->get_dof_indices(local_dof_indices); + for (unsigned int shapefun = 0; + shapefun < cell->get_fe().n_dofs_per_cell(); + ++shapefun) + { + unit_support_point = cell->get_fe().unit_support_point(shapefun); + support_point = + mapping.transform_unit_to_real_cell(cell, unit_support_point); + deallog << " " << support_point << ":\n " + << u_1[local_dof_indices[shapefun]] << endl + << endl; + } + } + deallog << endl << "dof values of dof_handler_2:" << endl; + for (const auto &cell : dof_handler_2.active_cell_iterators()) + + { + cell->get_dof_indices(local_dof_indices); + for (unsigned int shapefun = 0; + shapefun < cell->get_fe().n_dofs_per_cell(); + ++shapefun) + { + unit_support_point = cell->get_fe().unit_support_point(shapefun); + support_point = + mapping.transform_unit_to_real_cell(cell, unit_support_point); + deallog << " " << support_point << ":\n " + << u_2[local_dof_indices[shapefun]] << endl + << endl; + } + } +} + +int +main(int argc, char **argv) +{ + initlog(); + + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + deallog + << "### 2D-Case, first cell refined once, second cell unrefined###\n\n"; + check<2>(1, 0); + deallog << endl; + + deallog + << "### 2D-Case, first cell unrefined, second cell refined once###\n\n"; + check<2>(0, 1); + deallog << endl; + + deallog + << "### 2D-Case, first cell refined once, second cell refined once###\n\n"; + check<2>(1, 1); + deallog << endl; + + deallog + << "### 3D-Case, first cell refined once, second cell unrefined###\n\n"; + check<3>(1, 0); + deallog << endl; + + deallog + << "### 3D-Case, first cell unrefined, second cell refined once###\n\n"; + check<3>(0, 1); + deallog << endl; + + deallog + << "### 3D-Case, first cell refined once, second cell refined once###\n\n"; + check<3>(1, 1); + deallog << endl; +} diff --git a/tests/numerics/interpolate_to_different_mesh_01.output b/tests/numerics/interpolate_to_different_mesh_01.output new file mode 100644 index 000000000000..e413654cda02 --- /dev/null +++ b/tests/numerics/interpolate_to_different_mesh_01.output @@ -0,0 +1,1069 @@ + +DEAL::### 2D-Case, first cell refined once, second cell unrefined### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::### 2D-Case, first cell unrefined, second cell refined once### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.500000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.500000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.500000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::### 2D-Case, first cell refined once, second cell refined once### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::### 3D-Case, first cell refined once, second cell unrefined### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::### 3D-Case, first cell unrefined, second cell refined once### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.500000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.500000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.500000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.500000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.500000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.500000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.500000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.500000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.500000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.500000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.500000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.500000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.500000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.500000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.500000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.500000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.500000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::### 3D-Case, first cell refined once, second cell refined once### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: diff --git a/tests/numerics/interpolate_to_different_mesh_02.cc b/tests/numerics/interpolate_to_different_mesh_02.cc new file mode 100644 index 000000000000..1d58e9a31849 --- /dev/null +++ b/tests/numerics/interpolate_to_different_mesh_02.cc @@ -0,0 +1,164 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2000 - 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. +// +// --------------------------------------------------------------------- + +// test for interpolate_to_different_mesh with dealii::hp::DoFHandler + +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +#include "../tests.h" + +using namespace std; +using namespace dealii; + +template +class F1 : public Function +{ +public: + F1() + : Function() + {} + virtual double + value(const Point &p, const unsigned int component = 0) const + { + return p(0) * p(0); + } +}; + +template +void +check(const unsigned int refinement_1, const unsigned int refinement_2) +{ + MappingQGeneric mapping(1); + + Triangulation tria_1, tria_2; + GridGenerator::hyper_cube(tria_1); + GridGenerator::hyper_cube(tria_2); + + tria_1.refine_global(refinement_1); + tria_2.refine_global(refinement_2); + + hp::DoFHandler dof_handler_1(tria_1); + hp::DoFHandler dof_handler_2(tria_2); + + hp::FECollection fe_collection; + fe_collection.push_back(FE_Q(2)); + fe_collection.push_back(FE_Q(1)); + + for (const auto &cell : dof_handler_1.active_cell_iterators()) + cell->set_active_fe_index(0); + + for (const auto &cell : dof_handler_2.active_cell_iterators()) + cell->set_active_fe_index(1); + + dof_handler_1.distribute_dofs(fe_collection); + dof_handler_2.distribute_dofs(fe_collection); + + Vector u_1(dof_handler_1.n_dofs()), u_2(dof_handler_2.n_dofs()); + F1 f_1; + VectorTools::interpolate(mapping, dof_handler_1, f_1, u_1); + VectorTools::interpolate_to_different_mesh(dof_handler_1, + u_1, + dof_handler_2, + u_2); + + Point support_point, unit_support_point; + vector local_dof_indices_1( + fe_collection[0].n_dofs_per_cell()); + vector local_dof_indices_2( + fe_collection[1].n_dofs_per_cell()); + deallog << "dof values of dof_handler_1:" << endl; + for (const auto &cell : dof_handler_1.active_cell_iterators()) + { + cell->get_dof_indices(local_dof_indices_1); + for (unsigned int shapefun = 0; + shapefun < cell->get_fe().n_dofs_per_cell(); + ++shapefun) + { + unit_support_point = cell->get_fe().unit_support_point(shapefun); + support_point = + mapping.transform_unit_to_real_cell(cell, unit_support_point); + deallog << " " << support_point << ":\n " + << u_1[local_dof_indices_1[shapefun]] << endl + << endl; + } + } + deallog << endl << "dof values of dof_handler_2:" << endl; + for (const auto &cell : dof_handler_2.active_cell_iterators()) + { + cell->get_dof_indices(local_dof_indices_2); + for (unsigned int shapefun = 0; + shapefun < cell->get_fe().n_dofs_per_cell(); + ++shapefun) + { + unit_support_point = cell->get_fe().unit_support_point(shapefun); + support_point = + mapping.transform_unit_to_real_cell(cell, unit_support_point); + deallog << " " << support_point << ":\n " + << u_2[local_dof_indices_2[shapefun]] << endl + << endl; + } + } +} + +int +main(int argc, char **argv) +{ + initlog(); + + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + deallog + << "### 2D-Case, first cell refined once, second cell unrefined###\n\n"; + check<2>(1, 0); + deallog << endl; + + deallog + << "### 2D-Case, first cell unrefined, second cell refined once###\n\n"; + check<2>(0, 1); + deallog << endl; + + deallog + << "### 2D-Case, first cell refined once, second cell refined once###\n\n"; + check<2>(1, 1); + deallog << endl; + + deallog + << "### 3D-Case, first cell refined once, second cell unrefined###\n\n"; + check<3>(1, 0); + deallog << endl; + + deallog + << "### 3D-Case, first cell unrefined, second cell refined once###\n\n"; + check<3>(0, 1); + deallog << endl; + + deallog + << "### 3D-Case, first cell refined once, second cell refined once###\n\n"; + check<3>(1, 1); + deallog << endl; +} diff --git a/tests/numerics/interpolate_to_different_mesh_02.output b/tests/numerics/interpolate_to_different_mesh_02.output new file mode 100644 index 000000000000..cc4e6eab72ef --- /dev/null +++ b/tests/numerics/interpolate_to_different_mesh_02.output @@ -0,0 +1,2173 @@ + +DEAL::### 2D-Case, first cell refined once, second cell unrefined### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000: + 0.562500 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::### 2D-Case, first cell unrefined, second cell refined once### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::### 2D-Case, first cell refined once, second cell refined once### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000: + 0.562500 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::### 3D-Case, first cell refined once, second cell unrefined### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.250000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.250000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.00000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.250000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.250000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.00000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.750000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.750000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.500000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.750000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.750000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.250000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.250000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.00000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.250000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.250000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.00000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 0.750000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 0.750000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 0.750000: + 0.562500 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.750000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.750000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.500000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.750000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.750000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 0.750000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 0.750000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 0.750000: + 0.562500 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::### 3D-Case, first cell unrefined, second cell refined once### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: +DEAL::### 3D-Case, first cell refined once, second cell refined once### + +dof values of dof_handler_1: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.250000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.250000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.00000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.250000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.250000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.00000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.750000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.750000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.500000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.750000 0.250000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.250000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 0.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 0.250000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.750000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.500000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.250000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 0.250000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 0.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 0.250000: + 0.562500 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.250000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.250000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.00000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.250000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.00000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.500000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.250000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.250000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.00000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.250000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.250000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.00000 0.750000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.500000 0.750000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.250000 0.750000: + 0.562500 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.750000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.750000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.00000 0.500000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.750000 0.750000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.750000: + 0.250000 +DEAL:: +DEAL:: 0.250000 0.500000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 1.00000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 0.500000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 1.00000: + 0.0625000 +DEAL:: +DEAL:: 0.250000 0.750000 0.750000: + 0.0625000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.750000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.500000 0.500000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.750000 0.750000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.750000 0.750000: + 1.00000 +DEAL:: +DEAL:: 0.750000 0.500000 0.750000: + 0.562500 +DEAL:: +DEAL:: 0.750000 1.00000 0.750000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 0.500000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 1.00000: + 0.562500 +DEAL:: +DEAL:: 0.750000 0.750000 0.750000: + 0.562500 +DEAL:: +DEAL:: +DEAL::dof values of dof_handler_2: +DEAL:: 0.00000 0.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.00000 0.500000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 0.500000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 0.00000 0.500000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.00000 1.00000 1.00000: + 0.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 0.500000 0.500000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 0.500000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 0.500000: + 1.00000 +DEAL:: +DEAL:: 0.500000 0.500000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 0.500000 1.00000: + 1.00000 +DEAL:: +DEAL:: 0.500000 1.00000 1.00000: + 0.250000 +DEAL:: +DEAL:: 1.00000 1.00000 1.00000: + 1.00000 +DEAL:: +DEAL:: diff --git a/tests/numerics/interpolate_to_different_mesh_03.cc b/tests/numerics/interpolate_to_different_mesh_03.cc new file mode 100644 index 000000000000..0d34358e6acb --- /dev/null +++ b/tests/numerics/interpolate_to_different_mesh_03.cc @@ -0,0 +1,109 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2000 - 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. +// +// --------------------------------------------------------------------- + +// test for interpolate_to_different_mesh with dealii::DoFHandler +// checks that interpolation from coarse to fine and back to coarse +// is the identity operation + +#include + +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include "../tests.h" + +using namespace std; +using namespace dealii; + +template +void +check(const unsigned int refinement_1, const unsigned int refinement_2) +{ + MappingQGeneric mapping(1); + + Triangulation tria_1, tria_2; + GridGenerator::hyper_cube(tria_1); + GridGenerator::hyper_cube(tria_2); + + tria_1.refine_global(refinement_1); + tria_2.refine_global(refinement_2); + + DoFHandler dof_handler_1(tria_1); + DoFHandler dof_handler_2(tria_2); + + FE_Q fe(1); + dof_handler_1.distribute_dofs(fe); + dof_handler_2.distribute_dofs(fe); + + Vector u_1(dof_handler_1.n_dofs()), u_2(dof_handler_2.n_dofs()), + u_1_back(dof_handler_1.n_dofs()), d(dof_handler_1.n_dofs()); + for (unsigned int i1 = 0; i1 < u_1.size(); ++i1) + u_1[i1] = 2. * rand() / RAND_MAX - 1.; + + VectorTools::interpolate_to_different_mesh(dof_handler_1, + u_1, + dof_handler_2, + u_2); + + VectorTools::interpolate_to_different_mesh(dof_handler_2, + u_2, + dof_handler_1, + u_1_back); + + d = u_1; + d.sadd(-1.0, u_1_back); + deallog << "distance=" << d.l2_norm() << endl; +} + +int +main(int argc, char **argv) +{ + initlog(); + + srand(static_cast(clock())); + + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + deallog + << "### 2D-Case, first cell unrefined, second cell refined once###\n\n"; + check<2>(0, 1); + deallog << endl; + + deallog + << "### 2D-Case, first cell refined once, second cell refined three times###\n\n"; + check<2>(1, 3); + deallog << endl; + + deallog + << "### 3D-Case, first cell unrefined, second cell refined once###\n\n"; + check<3>(0, 1); + deallog << endl; + + deallog + << "### 3D-Case, first cell refined once, second cell refined three times###\n\n"; + check<3>(1, 3); + deallog << endl; +} diff --git a/tests/numerics/interpolate_to_different_mesh_03.output b/tests/numerics/interpolate_to_different_mesh_03.output new file mode 100644 index 000000000000..9803fd2d684c --- /dev/null +++ b/tests/numerics/interpolate_to_different_mesh_03.output @@ -0,0 +1,17 @@ + +DEAL::### 2D-Case, first cell unrefined, second cell refined once### + +distance=0.00000 +DEAL:: +DEAL::### 2D-Case, first cell refined once, second cell refined three times### + +distance=0.00000 +DEAL:: +DEAL::### 3D-Case, first cell unrefined, second cell refined once### + +distance=0.00000 +DEAL:: +DEAL::### 3D-Case, first cell refined once, second cell refined three times### + +distance=0.00000 +DEAL:: diff --git a/tests/numerics/interpolate_to_different_mesh_04.cc b/tests/numerics/interpolate_to_different_mesh_04.cc new file mode 100644 index 000000000000..f47e03980faf --- /dev/null +++ b/tests/numerics/interpolate_to_different_mesh_04.cc @@ -0,0 +1,133 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2000 - 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. +// +// --------------------------------------------------------------------- + +// test for interpolate_to_different_mesh with dealii::hp::DoFHandler +// checks that interpolation from coarse to fine and back to coarse +// is the identity operation + +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include "../tests.h" + +using namespace std; +using namespace dealii; + +template +void +check(const unsigned int refinement_1, const unsigned int refinement_2) +{ + MappingQGeneric mapping(1); + + Triangulation tria_1, tria_2; + GridGenerator::hyper_cube(tria_1); + GridGenerator::hyper_cube(tria_2); + + tria_1.refine_global(refinement_1); + tria_2.refine_global(refinement_2); + + hp::DoFHandler dof_handler_1(tria_1); + hp::DoFHandler dof_handler_2(tria_2); + + hp::FECollection fe_collection; + fe_collection.push_back(FE_Q(1)); + fe_collection.push_back(FE_Q(2)); + + for (const auto &cell : dof_handler_1.active_cell_iterators()) + cell->set_active_fe_index(0); + + for (const auto &cell : dof_handler_2.active_cell_iterators()) + cell->set_active_fe_index(1); + + dof_handler_1.distribute_dofs(fe_collection); + dof_handler_2.distribute_dofs(fe_collection); + + Vector u_1(dof_handler_1.n_dofs()), u_2(dof_handler_2.n_dofs()), + u_1_back(dof_handler_1.n_dofs()), d(dof_handler_1.n_dofs()); + for (unsigned int i1 = 0; i1 < u_1.size(); ++i1) + u_1[i1] = 2. * rand() / RAND_MAX - 1.; + + VectorTools::interpolate_to_different_mesh(dof_handler_1, + u_1, + dof_handler_2, + u_2); + + VectorTools::interpolate_to_different_mesh(dof_handler_2, + u_2, + dof_handler_1, + u_1_back); + + d = u_1; + d.sadd(-1.0, u_1_back); + deallog << "distance=" << d.l2_norm() << endl; +} + +int +main(int argc, char **argv) +{ + initlog(); + + srand(static_cast(clock())); + + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + deallog + << "### 2D-Case, first cell unrefined, second cell refined once###\n\n"; + check<2>(0, 1); + deallog << endl; + + deallog + << "### 2D-Case, first cell refined once, second cell refined three times###\n\n"; + check<2>(1, 3); + deallog << endl; + + // this should still be an identity operation although interpolation is from + // fine to coarse mesh because second mesh uses quadratic elements + deallog + << "### 2D-Case, first cell refined twice, second cell refined once###\n\n"; + check<2>(2, 1); + deallog << endl; + + deallog + << "### 3D-Case, first cell unrefined, second cell refined once###\n\n"; + check<3>(0, 1); + deallog << endl; + + deallog + << "### 3D-Case, first cell refined once, second cell refined three times###\n\n"; + check<3>(1, 3); + deallog << endl; + + // this should still be an identity operation although interpolation is from + // fine to coarse mesh because second mesh uses quadratic elements + deallog + << "### 3D-Case, first cell refined twice, second cell refined once###\n\n"; + check<3>(2, 1); + deallog << endl; +} diff --git a/tests/numerics/interpolate_to_different_mesh_04.output b/tests/numerics/interpolate_to_different_mesh_04.output new file mode 100644 index 000000000000..b199f69ae925 --- /dev/null +++ b/tests/numerics/interpolate_to_different_mesh_04.output @@ -0,0 +1,25 @@ + +DEAL::### 2D-Case, first cell unrefined, second cell refined once### + +distance=0.00000 +DEAL:: +DEAL::### 2D-Case, first cell refined once, second cell refined three times### + +distance=0.00000 +DEAL:: +DEAL::### 2D-Case, first cell refined twice, second cell refined once### + +distance=0.00000 +DEAL:: +DEAL::### 3D-Case, first cell unrefined, second cell refined once### + +distance=0.00000 +DEAL:: +DEAL::### 3D-Case, first cell refined once, second cell refined three times### + +distance=0.00000 +DEAL:: +DEAL::### 3D-Case, first cell refined twice, second cell refined once### + +distance=0.00000 +DEAL:: From 4fb26ab50ad1adba87b052fd65f315239f326324 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Mon, 18 Mar 2019 12:51:55 +0100 Subject: [PATCH 276/507] Simplify setting of CMake SymEngine version variable --- cmake/modules/FindSYMENGINE.cmake | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmake/modules/FindSYMENGINE.cmake b/cmake/modules/FindSYMENGINE.cmake index b318dd5992fd..ad0624507365 100644 --- a/cmake/modules/FindSYMENGINE.cmake +++ b/cmake/modules/FindSYMENGINE.cmake @@ -84,9 +84,8 @@ IF(EXISTS ${SYMENGINE_SETTINGS_H}) STRING(REGEX REPLACE "^.*SYMENGINE_PATCH_VERSION.*([0-9]+).*" "\\1" SYMENGINE_VERSION_PATCH "${SYMENGINE_VERSION_PATCH_STRING}" ) - SET(SYMENGINE_VERSION - "${SYMENGINE_VERSION_MAJOR}.${SYMENGINE_VERSION_MINOR}.${SYMENGINE_VERSION_PATCH}" - ) + + SET(SYMENGINE_VERSION ${SymEngine_VERSION}) ENDIF() # From 3dd93e4ca588c1876b3eb09e43b87eb3487702ab Mon Sep 17 00:00:00 2001 From: David Wells Date: Tue, 26 Feb 2019 20:58:14 -0500 Subject: [PATCH 277/507] Reflow comments. --- source/grid/grid_tools_dof_handlers.cc | 48 ++++++++------------------ 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/source/grid/grid_tools_dof_handlers.cc b/source/grid/grid_tools_dof_handlers.cc index 16012d59e543..208ece7de102 100644 --- a/source/grid/grid_tools_dof_handlers.cc +++ b/source/grid/grid_tools_dof_handlers.cc @@ -1136,20 +1136,12 @@ namespace GridTools ExcMessage("The two meshes must be represent triangulations that " "have the same coarse meshes")); - // the algorithm goes as follows: - // first, we fill a list with pairs - // of iterators common to the two - // meshes on the coarsest - // level. then we traverse the - // list; each time, we find a pair - // of iterators for which both - // correspond to non-active cells, - // we delete this item and push the - // pairs of iterators to their - // children to the back. if these - // again both correspond to - // non-active cells, we will get to - // the later on for further + // the algorithm goes as follows: first, we fill a list with pairs of + // iterators common to the two meshes on the coarsest level. then we + // traverse the list; each time, we find a pair of iterators for which + // both correspond to non-active cells, we delete this item and push the + // pairs of iterators to their children to the back. if these again both + // correspond to non-active cells, we will get to the later on for further // consideration using CellList = std::list>; @@ -1161,15 +1153,12 @@ namespace GridTools for (; cell_1 != mesh_1.end(0); ++cell_1, ++cell_2) cell_list.emplace_back(cell_1, cell_2); - // then traverse list as described - // above + // then traverse list as described above typename CellList::iterator cell_pair = cell_list.begin(); while (cell_pair != cell_list.end()) { - // if both cells in this pair - // have children, then erase - // this element and push their - // children instead + // if both cells in this pair have children, then erase this element + // and push their children instead if (cell_pair->first->has_children() && cell_pair->second->has_children()) { @@ -1180,28 +1169,21 @@ namespace GridTools cell_list.emplace_back(cell_pair->first->child(c), cell_pair->second->child(c)); - // erasing an iterator - // keeps other iterators - // valid, so already - // advance the present - // iterator by one and then - // delete the element we've - // visited before + // erasing an iterator keeps other iterators valid, so already + // advance the present iterator by one and then delete the element + // we've visited before const typename CellList::iterator previous_cell_pair = cell_pair; ++cell_pair; cell_list.erase(previous_cell_pair); } else - // both cells are active, do - // nothing + // both cells are active, do nothing ++cell_pair; } - // just to make sure everything is ok, - // validate that all pairs have at least one - // active iterator or have different - // refinement_cases + // just to make sure everything is ok, validate that all pairs have at + // least one active iterator or have different refinement_cases for (cell_pair = cell_list.begin(); cell_pair != cell_list.end(); ++cell_pair) Assert(cell_pair->first->active() || cell_pair->second->active() || From 1ee851f4cbec17bb980c845ca415721d8598ec04 Mon Sep 17 00:00:00 2001 From: David Wells Date: Wed, 27 Feb 2019 17:13:25 -0500 Subject: [PATCH 278/507] Fix a bug in make_sparsity_pattern(dh, dh, sp). This function relied GridTools::get_finest_common_cells which was written before any of the parallel triangulations were implemented and thus assumed that all cells without children were active. This commit modifies that function to only return active cells that are also locally owned, which fixes the sparsity pattern function. --- doc/news/changes/minor/20190304DavidWells | 5 + include/deal.II/grid/grid_tools.h | 5 + source/dofs/dof_tools_sparsity.cc | 65 +++++-- source/grid/grid_tools_dof_handlers.cc | 45 ++++- tests/dofs/sparsity_pattern_06.cc | 147 +++++++++++++++ ...y_pattern_06.with_p4est=on.mpirun=1.output | 45 +++++ ...y_pattern_06.with_p4est=on.mpirun=2.output | 59 +++++++ tests/dofs/sparsity_pattern_07.cc | 164 +++++++++++++++++ .../dofs/sparsity_pattern_07.mpirun=1.output | 45 +++++ .../dofs/sparsity_pattern_07.mpirun=2.output | 59 +++++++ tests/grid/get_finest_common_cells_04.cc | 104 +++++++++++ ...n_cells_04.with_p4est=true.mpirun=1.output | 83 +++++++++ ...n_cells_04.with_p4est=true.mpirun=2.output | 167 ++++++++++++++++++ 13 files changed, 976 insertions(+), 17 deletions(-) create mode 100644 doc/news/changes/minor/20190304DavidWells create mode 100644 tests/dofs/sparsity_pattern_06.cc create mode 100644 tests/dofs/sparsity_pattern_06.with_p4est=on.mpirun=1.output create mode 100644 tests/dofs/sparsity_pattern_06.with_p4est=on.mpirun=2.output create mode 100644 tests/dofs/sparsity_pattern_07.cc create mode 100644 tests/dofs/sparsity_pattern_07.mpirun=1.output create mode 100644 tests/dofs/sparsity_pattern_07.mpirun=2.output create mode 100644 tests/grid/get_finest_common_cells_04.cc create mode 100644 tests/grid/get_finest_common_cells_04.with_p4est=true.mpirun=1.output create mode 100644 tests/grid/get_finest_common_cells_04.with_p4est=true.mpirun=2.output 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/include/deal.II/grid/grid_tools.h b/include/deal.II/grid/grid_tools.h index 00e434cc3af2..df3711d54f44 100644 --- a/include/deal.II/grid/grid_tools.h +++ b/include/deal.II/grid/grid_tools.h @@ -2018,6 +2018,11 @@ namespace GridTools * * @tparam MeshType A type that satisfies the requirements of the * @ref ConceptMeshType "MeshType concept". + * + * @note This function can only be used with + * parallel::distributed::Triangulation when both meshes use the same + * Triangulation since, with a distributed Triangulation, not all cells are + * stored locally, so the resulting list may not cover the entire domain. */ template std::list #include +#include +#include + #include #include #include @@ -222,23 +225,59 @@ namespace DoFTools Assert(sparsity.n_cols() == n_dofs_col, ExcDimensionMismatch(sparsity.n_cols(), n_dofs_col)); - // TODO: Looks like wasteful memory management here - - const std::list> - cell_list = GridTools::get_finest_common_cells(dof_row, dof_col); + // It doesn't make sense to assemble sparsity patterns when the + // Triangulations are both parallel (i.e., different cells are assigned to + // different processors) and unequal: no processor will be responsible for + // assembling coupling terms between dofs on a cell owned by one processor + // and dofs on a cell owned by a different processor. + constexpr int dim = DoFHandlerType::dimension; + constexpr int spacedim = DoFHandlerType::space_dimension; + if (dynamic_cast *>( + &dof_row.get_triangulation()) != nullptr || + dynamic_cast *>( + &dof_col.get_triangulation()) != nullptr) + { + Assert(&dof_row.get_triangulation() == &dof_col.get_triangulation(), + ExcMessage("This function can only be used with with parallel " + "Triangulations when the Triangulations are equal.")); + } + // TODO: Looks like wasteful memory management here - typename std::list>:: - const_iterator cell_iter = cell_list.begin(); + using cell_iterator = typename DoFHandlerType::cell_iterator; + std::list> cell_list = + GridTools::get_finest_common_cells(dof_row, dof_col); + +#ifdef DEAL_II_WITH_MPI + // get_finest_common_cells returns all cells (locally owned and otherwise) + // for shared::Tria, but we don't want to assemble on cells that are not + // locally owned so remove them + if (dynamic_cast *>( + &dof_row.get_triangulation()) != nullptr || + dynamic_cast *>( + &dof_col.get_triangulation()) != nullptr) + { + const types::subdomain_id this_subdomain_id = + dof_row.get_triangulation().locally_owned_subdomain(); + Assert(this_subdomain_id == + dof_col.get_triangulation().locally_owned_subdomain(), + ExcInternalError()); + cell_list.erase( + std::remove_if( + cell_list.begin(), + cell_list.end(), + [=](const std::pair &pair) { + return pair.first->subdomain_id() != this_subdomain_id || + pair.second->subdomain_id() != this_subdomain_id; + }), + cell_list.end()); + } +#endif - for (; cell_iter != cell_list.end(); ++cell_iter) + for (const auto &cell_pair : cell_list) { - const typename DoFHandlerType::cell_iterator cell_row = - cell_iter->first; - const typename DoFHandlerType::cell_iterator cell_col = - cell_iter->second; + const cell_iterator cell_row = cell_pair.first; + const cell_iterator cell_col = cell_pair.second; if (!cell_row->has_children() && !cell_col->has_children()) { diff --git a/source/grid/grid_tools_dof_handlers.cc b/source/grid/grid_tools_dof_handlers.cc index 208ece7de102..ba09b68e1dca 100644 --- a/source/grid/grid_tools_dof_handlers.cc +++ b/source/grid/grid_tools_dof_handlers.cc @@ -1135,6 +1135,30 @@ namespace GridTools Assert(have_same_coarse_mesh(mesh_1, mesh_2), ExcMessage("The two meshes must be represent triangulations that " "have the same coarse meshes")); + // We will allow the output to contain ghost cells when we have shared + // Triangulations (i.e., so that each processor will get exactly the same + // list of cell pairs), but not when we have two distributed + // Triangulations (so that all active cells are partitioned by processor). + // Non-parallel Triangulations have no ghost or artificial cells, so they + // work the same way as shared Triangulations here. + bool remove_ghost_cells = false; +#ifdef DEAL_II_WITH_MPI + { + constexpr int dim = MeshType::dimension; + constexpr int spacedim = MeshType::space_dimension; + if (dynamic_cast + *>(&mesh_1.get_triangulation()) != nullptr || + dynamic_cast + *>(&mesh_2.get_triangulation()) != nullptr) + { + Assert(&mesh_1.get_triangulation() == &mesh_2.get_triangulation(), + ExcMessage("This function can only be used with meshes " + "corresponding to distributed Triangulations when " + "both Triangulations are equal.")); + remove_ghost_cells = true; + } + } +#endif // the algorithm goes as follows: first, we fill a list with pairs of // iterators common to the two meshes on the coarsest level. then we @@ -1172,14 +1196,27 @@ namespace GridTools // erasing an iterator keeps other iterators valid, so already // advance the present iterator by one and then delete the element // we've visited before - const typename CellList::iterator previous_cell_pair = cell_pair; + const auto previous_cell_pair = cell_pair; ++cell_pair; - cell_list.erase(previous_cell_pair); } else - // both cells are active, do nothing - ++cell_pair; + { + // at least one cell is active + if (remove_ghost_cells && + ((cell_pair->first->active() && + !cell_pair->first->is_locally_owned()) || + (cell_pair->second->active() && + !cell_pair->second->is_locally_owned()))) + { + // we only exclude ghost cells for distributed Triangulations + const auto previous_cell_pair = cell_pair; + ++cell_pair; + cell_list.erase(previous_cell_pair); + } + else + ++cell_pair; + } } // just to make sure everything is ok, validate that all pairs have at diff --git a/tests/dofs/sparsity_pattern_06.cc b/tests/dofs/sparsity_pattern_06.cc new file mode 100644 index 000000000000..3a98472f1c14 --- /dev/null +++ b/tests/dofs/sparsity_pattern_06.cc @@ -0,0 +1,147 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Check that we can create a sparsity pattern from two DoFHandlers with the +// same distributed mesh. This previously failed since the implementation +// called a GridTools function that assumed all cells without children were +// active (which is not the case for distributed meshes). + +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "../tests.h" + + +int +main(int argc, char **argv) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + MPILogInitAll all; + + parallel::distributed::Triangulation<2> triangulation(MPI_COMM_WORLD); + GridGenerator::subdivided_hyper_rectangle(triangulation, + {4u, 1u}, + {0.0, 0.0}, + {4.0, 1.0}); + triangulation.refine_global(1); + deallog << "global number of active cells: " + << triangulation.n_global_active_cells() << std::endl; + deallog << "local number of active cells: " << triangulation.n_active_cells() + << std::endl; + deallog << "number of locally owned active cells: " + << triangulation.n_locally_owned_active_cells() << std::endl; + + FE_DGQ<2> fe_0(0); + DoFHandler<2> dof_handler_0; + FE_Q<2> fe_1(1); + DoFHandler<2> dof_handler_1; + dof_handler_0.initialize(triangulation, fe_0); + dof_handler_1.initialize(triangulation, fe_1); + + IndexSet locally_relevant_dofs_0; + IndexSet locally_relevant_dofs_1; + DoFTools::extract_locally_relevant_dofs(dof_handler_0, + locally_relevant_dofs_0); + DoFTools::extract_locally_relevant_dofs(dof_handler_1, + locally_relevant_dofs_1); + deallog << "locally owned dofs 0: "; + dof_handler_0.locally_owned_dofs().print(deallog); + deallog << std::endl; + deallog << "locally owned dofs 1: "; + dof_handler_1.locally_owned_dofs().print(deallog); + deallog << std::endl; + deallog << "locally relevant dofs 0: "; + locally_relevant_dofs_0.print(deallog); + deallog << std::endl; + deallog << "locally relevant dofs 1: "; + locally_relevant_dofs_1.print(deallog); + deallog << std::endl; + +#if 0 // reenable this to see where the DoFs are + MappingCartesian<2> mapping; + { + deallog << "support points of dofs 0:" << std::endl; + std::vector cell_dofs(fe_0.dofs_per_cell); + std::size_t cell_n = 0; + for (const auto &cell : dof_handler_0.active_cell_iterators()) + { + if (cell->is_locally_owned()) + { + deallog << "cell_n = " << cell_n << std::endl; + const std::vector> &support_points = fe_0.get_unit_support_points(); + cell->get_dof_indices(cell_dofs); + for (std::size_t dof_n = 0; dof_n < fe_0.dofs_per_cell; ++dof_n) + { + deallog << "dof " << std::setw(2) << cell_dofs[dof_n] << ": " + << mapping.transform_unit_to_real_cell(cell, support_points[dof_n]) + << std::endl; + } + ++cell_n; + } + } + } + + { + deallog << "support points of dofs 1:" << std::endl; + std::vector cell_dofs(fe_1.dofs_per_cell); + std::size_t cell_n = 0; + for (const auto &cell : dof_handler_1.active_cell_iterators()) + { + if (cell->is_locally_owned()) + { + deallog << "cell_n = " << cell_n << std::endl; + const std::vector> &support_points = fe_1.get_unit_support_points(); + cell->get_dof_indices(cell_dofs); + for (std::size_t dof_n = 0; dof_n < fe_1.dofs_per_cell; ++dof_n) + { + deallog << "dof " << std::setw(2) << cell_dofs[dof_n] << ": " + << mapping.transform_unit_to_real_cell(cell, support_points[dof_n]) + << std::endl; + } + ++cell_n; + } + } + } +#endif + + DynamicSparsityPattern dynamic_sparsity_pattern( + dof_handler_0.locally_owned_dofs().size(), + dof_handler_1.locally_owned_dofs().size(), + dof_handler_0.locally_owned_dofs()); + DoFTools::make_sparsity_pattern(dof_handler_0, + dof_handler_1, + dynamic_sparsity_pattern); + dynamic_sparsity_pattern.print(deallog.get_file_stream()); + SparsityTools::distribute_sparsity_pattern( + dynamic_sparsity_pattern, + dof_handler_0.n_locally_owned_dofs_per_processor(), + MPI_COMM_WORLD, + dof_handler_0.locally_owned_dofs()); + dynamic_sparsity_pattern.print(deallog.get_file_stream()); + + deallog << "OK" << std::endl; +} diff --git a/tests/dofs/sparsity_pattern_06.with_p4est=on.mpirun=1.output b/tests/dofs/sparsity_pattern_06.with_p4est=on.mpirun=1.output new file mode 100644 index 000000000000..64245124db23 --- /dev/null +++ b/tests/dofs/sparsity_pattern_06.with_p4est=on.mpirun=1.output @@ -0,0 +1,45 @@ + +DEAL:0::global number of active cells: 16 +DEAL:0::local number of active cells: 16 +DEAL:0::number of locally owned active cells: 16 +DEAL:0::locally owned dofs 0: {[0,15]} +DEAL:0:: +DEAL:0::locally owned dofs 1: {[0,26]} +DEAL:0:: +DEAL:0::locally relevant dofs 0: {[0,15]} +DEAL:0:: +DEAL:0::locally relevant dofs 1: {[0,26]} +DEAL:0:: +[0,0,1,2,3] +[1,1,3,4,5] +[2,2,3,6,7] +[3,3,5,7,8] +[4,4,5,9,10] +[5,9,10,11,12] +[6,5,8,10,13] +[7,10,12,13,14] +[8,11,12,15,16] +[9,15,16,17,18] +[10,12,14,16,19] +[11,16,18,19,20] +[12,17,18,21,22] +[13,21,22,23,24] +[14,18,20,22,25] +[15,22,24,25,26] +[0,0,1,2,3] +[1,1,3,4,5] +[2,2,3,6,7] +[3,3,5,7,8] +[4,4,5,9,10] +[5,9,10,11,12] +[6,5,8,10,13] +[7,10,12,13,14] +[8,11,12,15,16] +[9,15,16,17,18] +[10,12,14,16,19] +[11,16,18,19,20] +[12,17,18,21,22] +[13,21,22,23,24] +[14,18,20,22,25] +[15,22,24,25,26] +DEAL:0::OK diff --git a/tests/dofs/sparsity_pattern_06.with_p4est=on.mpirun=2.output b/tests/dofs/sparsity_pattern_06.with_p4est=on.mpirun=2.output new file mode 100644 index 000000000000..f715e4d77498 --- /dev/null +++ b/tests/dofs/sparsity_pattern_06.with_p4est=on.mpirun=2.output @@ -0,0 +1,59 @@ + +DEAL:0::global number of active cells: 16 +DEAL:0::local number of active cells: 13 +DEAL:0::number of locally owned active cells: 8 +DEAL:0::locally owned dofs 0: {[0,7]} +DEAL:0:: +DEAL:0::locally owned dofs 1: {[0,14]} +DEAL:0:: +DEAL:0::locally relevant dofs 0: {[0,8], 10} +DEAL:0:: +DEAL:0::locally relevant dofs 1: {[0,16], 19} +DEAL:0:: +[0,0,1,2,3] +[1,1,3,4,5] +[2,2,3,6,7] +[3,3,5,7,8] +[4,4,5,9,10] +[5,9,10,11,12] +[6,5,8,10,13] +[7,10,12,13,14] +[0,0,1,2,3] +[1,1,3,4,5] +[2,2,3,6,7] +[3,3,5,7,8] +[4,4,5,9,10] +[5,9,10,11,12] +[6,5,8,10,13] +[7,10,12,13,14] +DEAL:0::OK + +DEAL:1::global number of active cells: 16 +DEAL:1::local number of active cells: 13 +DEAL:1::number of locally owned active cells: 8 +DEAL:1::locally owned dofs 0: {[8,15]} +DEAL:1:: +DEAL:1::locally owned dofs 1: {[15,26]} +DEAL:1:: +DEAL:1::locally relevant dofs 0: {5, [7,15]} +DEAL:1:: +DEAL:1::locally relevant dofs 1: {[9,26]} +DEAL:1:: +[8,11,12,15,16] +[9,15,16,17,18] +[10,12,14,16,19] +[11,16,18,19,20] +[12,17,18,21,22] +[13,21,22,23,24] +[14,18,20,22,25] +[15,22,24,25,26] +[8,11,12,15,16] +[9,15,16,17,18] +[10,12,14,16,19] +[11,16,18,19,20] +[12,17,18,21,22] +[13,21,22,23,24] +[14,18,20,22,25] +[15,22,24,25,26] +DEAL:1::OK + diff --git a/tests/dofs/sparsity_pattern_07.cc b/tests/dofs/sparsity_pattern_07.cc new file mode 100644 index 000000000000..53d154bf20f9 --- /dev/null +++ b/tests/dofs/sparsity_pattern_07.cc @@ -0,0 +1,164 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Check that we can create a sparsity pattern from two DoFHandlers with the +// same parallel mesh. This previously failed since the implementation +// called a GridTools function that assumed all cells without children were +// active (which is not the case for distributed meshes). +// +// This is the same as sparsity_pattern_06 but checks with a shared +// triangulation instead of a distributed one. + +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "../tests.h" + + +int +main(int argc, char **argv) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + MPILogInitAll all; + + parallel::shared::Triangulation<2> triangulation(MPI_COMM_WORLD); + GridGenerator::subdivided_hyper_rectangle(triangulation, + {4u, 1u}, + {0.0, 0.0}, + {4.0, 1.0}); + triangulation.refine_global(1); + const unsigned int n_processes = + Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD); + Assert(n_processes == 1 || n_processes == 2, ExcInternalError()); + if (n_processes == 2) + { + for (auto &cell : triangulation.active_cell_iterators()) + { + if (cell->center()[0] < 2.0) + cell->set_subdomain_id(0); + else + cell->set_subdomain_id(1); + } + } + + deallog << "global number of active cells: " + << triangulation.n_global_active_cells() << std::endl; + deallog << "local number of active cells: " << triangulation.n_active_cells() + << std::endl; + deallog << "number of locally owned active cells: " + << triangulation.n_locally_owned_active_cells() << std::endl; + + FE_DGQ<2> fe_0(0); + DoFHandler<2> dof_handler_0; + FE_Q<2> fe_1(1); + DoFHandler<2> dof_handler_1; + dof_handler_0.initialize(triangulation, fe_0); + dof_handler_1.initialize(triangulation, fe_1); + + IndexSet locally_relevant_dofs_0; + IndexSet locally_relevant_dofs_1; + DoFTools::extract_locally_relevant_dofs(dof_handler_0, + locally_relevant_dofs_0); + DoFTools::extract_locally_relevant_dofs(dof_handler_1, + locally_relevant_dofs_1); + deallog << "locally owned dofs 0: "; + dof_handler_0.locally_owned_dofs().print(deallog); + deallog << std::endl; + deallog << "locally owned dofs 1: "; + dof_handler_1.locally_owned_dofs().print(deallog); + deallog << std::endl; + deallog << "locally relevant dofs 0: "; + locally_relevant_dofs_0.print(deallog); + deallog << std::endl; + deallog << "locally relevant dofs 1: "; + locally_relevant_dofs_1.print(deallog); + deallog << std::endl; + +#if 0 // reenable this to see where the DoFs are + MappingCartesian<2> mapping; + { + deallog << "support points of dofs 0:" << std::endl; + std::vector cell_dofs(fe_0.dofs_per_cell); + std::size_t cell_n = 0; + for (const auto &cell : dof_handler_0.active_cell_iterators()) + { + if (cell->is_locally_owned()) + { + deallog << "cell_n = " << cell_n << std::endl; + const std::vector> &support_points = fe_0.get_unit_support_points(); + cell->get_dof_indices(cell_dofs); + for (std::size_t dof_n = 0; dof_n < fe_0.dofs_per_cell; ++dof_n) + { + deallog << "dof " << std::setw(2) << cell_dofs[dof_n] << ": " + << mapping.transform_unit_to_real_cell(cell, support_points[dof_n]) + << std::endl; + } + ++cell_n; + } + } + } + + { + deallog << "support points of dofs 1:" << std::endl; + std::vector cell_dofs(fe_1.dofs_per_cell); + std::size_t cell_n = 0; + for (const auto &cell : dof_handler_1.active_cell_iterators()) + { + if (cell->is_locally_owned()) + { + deallog << "cell_n = " << cell_n << std::endl; + const std::vector> &support_points = fe_1.get_unit_support_points(); + cell->get_dof_indices(cell_dofs); + for (std::size_t dof_n = 0; dof_n < fe_1.dofs_per_cell; ++dof_n) + { + deallog << "dof " << std::setw(2) << cell_dofs[dof_n] << ": " + << mapping.transform_unit_to_real_cell(cell, support_points[dof_n]) + << std::endl; + } + ++cell_n; + } + } + } +#endif + + DynamicSparsityPattern dynamic_sparsity_pattern( + dof_handler_0.locally_owned_dofs().size(), + dof_handler_1.locally_owned_dofs().size(), + dof_handler_0.locally_owned_dofs()); + DoFTools::make_sparsity_pattern(dof_handler_0, + dof_handler_1, + dynamic_sparsity_pattern); + dynamic_sparsity_pattern.print(deallog.get_file_stream()); + SparsityTools::distribute_sparsity_pattern( + dynamic_sparsity_pattern, + dof_handler_0.n_locally_owned_dofs_per_processor(), + MPI_COMM_WORLD, + dof_handler_0.locally_owned_dofs()); + dynamic_sparsity_pattern.print(deallog.get_file_stream()); + + deallog << "OK" << std::endl; +} diff --git a/tests/dofs/sparsity_pattern_07.mpirun=1.output b/tests/dofs/sparsity_pattern_07.mpirun=1.output new file mode 100644 index 000000000000..64245124db23 --- /dev/null +++ b/tests/dofs/sparsity_pattern_07.mpirun=1.output @@ -0,0 +1,45 @@ + +DEAL:0::global number of active cells: 16 +DEAL:0::local number of active cells: 16 +DEAL:0::number of locally owned active cells: 16 +DEAL:0::locally owned dofs 0: {[0,15]} +DEAL:0:: +DEAL:0::locally owned dofs 1: {[0,26]} +DEAL:0:: +DEAL:0::locally relevant dofs 0: {[0,15]} +DEAL:0:: +DEAL:0::locally relevant dofs 1: {[0,26]} +DEAL:0:: +[0,0,1,2,3] +[1,1,3,4,5] +[2,2,3,6,7] +[3,3,5,7,8] +[4,4,5,9,10] +[5,9,10,11,12] +[6,5,8,10,13] +[7,10,12,13,14] +[8,11,12,15,16] +[9,15,16,17,18] +[10,12,14,16,19] +[11,16,18,19,20] +[12,17,18,21,22] +[13,21,22,23,24] +[14,18,20,22,25] +[15,22,24,25,26] +[0,0,1,2,3] +[1,1,3,4,5] +[2,2,3,6,7] +[3,3,5,7,8] +[4,4,5,9,10] +[5,9,10,11,12] +[6,5,8,10,13] +[7,10,12,13,14] +[8,11,12,15,16] +[9,15,16,17,18] +[10,12,14,16,19] +[11,16,18,19,20] +[12,17,18,21,22] +[13,21,22,23,24] +[14,18,20,22,25] +[15,22,24,25,26] +DEAL:0::OK diff --git a/tests/dofs/sparsity_pattern_07.mpirun=2.output b/tests/dofs/sparsity_pattern_07.mpirun=2.output new file mode 100644 index 000000000000..3138fa982231 --- /dev/null +++ b/tests/dofs/sparsity_pattern_07.mpirun=2.output @@ -0,0 +1,59 @@ + +DEAL:0::global number of active cells: 16 +DEAL:0::local number of active cells: 16 +DEAL:0::number of locally owned active cells: 8 +DEAL:0::locally owned dofs 0: {[0,7]} +DEAL:0:: +DEAL:0::locally owned dofs 1: {[0,14]} +DEAL:0:: +DEAL:0::locally relevant dofs 0: {[0,15]} +DEAL:0:: +DEAL:0::locally relevant dofs 1: {[0,26]} +DEAL:0:: +[0,0,1,2,3] +[1,1,3,4,5] +[2,2,3,6,7] +[3,3,5,7,8] +[4,4,5,9,10] +[5,9,10,11,12] +[6,5,8,10,13] +[7,10,12,13,14] +[0,0,1,2,3] +[1,1,3,4,5] +[2,2,3,6,7] +[3,3,5,7,8] +[4,4,5,9,10] +[5,9,10,11,12] +[6,5,8,10,13] +[7,10,12,13,14] +DEAL:0::OK + +DEAL:1::global number of active cells: 16 +DEAL:1::local number of active cells: 16 +DEAL:1::number of locally owned active cells: 8 +DEAL:1::locally owned dofs 0: {[8,15]} +DEAL:1:: +DEAL:1::locally owned dofs 1: {[15,26]} +DEAL:1:: +DEAL:1::locally relevant dofs 0: {[0,15]} +DEAL:1:: +DEAL:1::locally relevant dofs 1: {[0,26]} +DEAL:1:: +[8,11,12,15,16] +[9,15,16,17,18] +[10,12,14,16,19] +[11,16,18,19,20] +[12,17,18,21,22] +[13,21,22,23,24] +[14,18,20,22,25] +[15,22,24,25,26] +[8,11,12,15,16] +[9,15,16,17,18] +[10,12,14,16,19] +[11,16,18,19,20] +[12,17,18,21,22] +[13,21,22,23,24] +[14,18,20,22,25] +[15,22,24,25,26] +DEAL:1::OK + diff --git a/tests/grid/get_finest_common_cells_04.cc b/tests/grid/get_finest_common_cells_04.cc new file mode 100644 index 000000000000..cab08b18c555 --- /dev/null +++ b/tests/grid/get_finest_common_cells_04.cc @@ -0,0 +1,104 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2006 - 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 + +#include + +#include +#include +#include + +#include "../tests.h" + + + +template +void +test() +{ + // create 2 triangulations with the + // same coarse grid, and refine + // them differently + parallel::shared::Triangulation tria_0(MPI_COMM_WORLD); + parallel::shared::Triangulation tria_1(MPI_COMM_WORLD); + GridGenerator::hyper_cube(tria_0); + GridGenerator::hyper_cube(tria_1); + + tria_0.refine_global(2); + tria_1.refine_global(2); + + tria_0.begin_active()->set_refine_flag(); + tria_0.execute_coarsening_and_refinement(); + + tria_1.last_active()->set_refine_flag(); + tria_1.execute_coarsening_and_refinement(); + + tria_1.last_active()->set_refine_flag(); + tria_1.execute_coarsening_and_refinement(); + +#if 0 // turn this block back on to get plots of grids and locally owned cells + if (dim == 2) + { + std::string tria_0_out = + "tria-0-" + std::to_string(Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)) + ".svg"; + std::ofstream tria_0_out_stream(tria_0_out); + std::string tria_1_out = + "tria-1-" + std::to_string(Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)) + ".svg"; + std::ofstream tria_1_out_stream(tria_1_out); + GridOut().write_svg(tria_0, tria_0_out_stream); + GridOut().write_svg(tria_1, tria_1_out_stream); + } + + deallog << "tria 0 cells:" << std::endl; + for (const auto &cell : tria_0.active_cell_iterators()) + { + if (cell->is_locally_owned()) + deallog << cell << std::endl; + } + + deallog << "tria 1 cells:" << std::endl; + for (const auto &cell : tria_1.active_cell_iterators()) + { + if (cell->is_locally_owned()) + deallog << cell << std::endl; + } +#endif + + typedef std::list::cell_iterator, + typename Triangulation::cell_iterator>> + CellList; + + deallog << "number of locally owned cells in tria 0 and tria 1: " + << tria_0.n_active_cells() << ' ' << tria_1.n_active_cells() + << std::endl; + const CellList cell_list = GridTools::get_finest_common_cells(tria_0, tria_1); + for (typename CellList::const_iterator cell_pair = cell_list.begin(); + cell_pair != cell_list.end(); + ++cell_pair) + deallog << cell_pair->first << ' ' << cell_pair->second << std::endl; +} + + +int +main(int argc, char **argv) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + MPILogInitAll all; + + test<2>(); + test<3>(); +} diff --git a/tests/grid/get_finest_common_cells_04.with_p4est=true.mpirun=1.output b/tests/grid/get_finest_common_cells_04.with_p4est=true.mpirun=1.output new file mode 100644 index 000000000000..993a4a6e7c11 --- /dev/null +++ b/tests/grid/get_finest_common_cells_04.with_p4est=true.mpirun=1.output @@ -0,0 +1,83 @@ + +DEAL:0::number of locally owned cells in tria 0 and tria 1: 19 22 +DEAL:0::2.0 2.0 +DEAL:0::2.1 2.1 +DEAL:0::2.2 2.2 +DEAL:0::2.3 2.3 +DEAL:0::2.4 2.4 +DEAL:0::2.5 2.5 +DEAL:0::2.6 2.6 +DEAL:0::2.7 2.7 +DEAL:0::2.8 2.8 +DEAL:0::2.9 2.9 +DEAL:0::2.10 2.10 +DEAL:0::2.11 2.11 +DEAL:0::2.12 2.12 +DEAL:0::2.13 2.13 +DEAL:0::2.14 2.14 +DEAL:0::2.15 2.15 +DEAL:0::number of locally owned cells in tria 0 and tria 1: 71 78 +DEAL:0::2.0 2.0 +DEAL:0::2.1 2.1 +DEAL:0::2.2 2.2 +DEAL:0::2.3 2.3 +DEAL:0::2.4 2.4 +DEAL:0::2.5 2.5 +DEAL:0::2.6 2.6 +DEAL:0::2.7 2.7 +DEAL:0::2.8 2.8 +DEAL:0::2.9 2.9 +DEAL:0::2.10 2.10 +DEAL:0::2.11 2.11 +DEAL:0::2.12 2.12 +DEAL:0::2.13 2.13 +DEAL:0::2.14 2.14 +DEAL:0::2.15 2.15 +DEAL:0::2.16 2.16 +DEAL:0::2.17 2.17 +DEAL:0::2.18 2.18 +DEAL:0::2.19 2.19 +DEAL:0::2.20 2.20 +DEAL:0::2.21 2.21 +DEAL:0::2.22 2.22 +DEAL:0::2.23 2.23 +DEAL:0::2.24 2.24 +DEAL:0::2.25 2.25 +DEAL:0::2.26 2.26 +DEAL:0::2.27 2.27 +DEAL:0::2.28 2.28 +DEAL:0::2.29 2.29 +DEAL:0::2.30 2.30 +DEAL:0::2.31 2.31 +DEAL:0::2.32 2.32 +DEAL:0::2.33 2.33 +DEAL:0::2.34 2.34 +DEAL:0::2.35 2.35 +DEAL:0::2.36 2.36 +DEAL:0::2.37 2.37 +DEAL:0::2.38 2.38 +DEAL:0::2.39 2.39 +DEAL:0::2.40 2.40 +DEAL:0::2.41 2.41 +DEAL:0::2.42 2.42 +DEAL:0::2.43 2.43 +DEAL:0::2.44 2.44 +DEAL:0::2.45 2.45 +DEAL:0::2.46 2.46 +DEAL:0::2.47 2.47 +DEAL:0::2.48 2.48 +DEAL:0::2.49 2.49 +DEAL:0::2.50 2.50 +DEAL:0::2.51 2.51 +DEAL:0::2.52 2.52 +DEAL:0::2.53 2.53 +DEAL:0::2.54 2.54 +DEAL:0::2.55 2.55 +DEAL:0::2.56 2.56 +DEAL:0::2.57 2.57 +DEAL:0::2.58 2.58 +DEAL:0::2.59 2.59 +DEAL:0::2.60 2.60 +DEAL:0::2.61 2.61 +DEAL:0::2.62 2.62 +DEAL:0::2.63 2.63 diff --git a/tests/grid/get_finest_common_cells_04.with_p4est=true.mpirun=2.output b/tests/grid/get_finest_common_cells_04.with_p4est=true.mpirun=2.output new file mode 100644 index 000000000000..87c5e343e319 --- /dev/null +++ b/tests/grid/get_finest_common_cells_04.with_p4est=true.mpirun=2.output @@ -0,0 +1,167 @@ + +DEAL:0::number of locally owned cells in tria 0 and tria 1: 19 22 +DEAL:0::2.0 2.0 +DEAL:0::2.1 2.1 +DEAL:0::2.2 2.2 +DEAL:0::2.3 2.3 +DEAL:0::2.4 2.4 +DEAL:0::2.5 2.5 +DEAL:0::2.6 2.6 +DEAL:0::2.7 2.7 +DEAL:0::2.8 2.8 +DEAL:0::2.9 2.9 +DEAL:0::2.10 2.10 +DEAL:0::2.11 2.11 +DEAL:0::2.12 2.12 +DEAL:0::2.13 2.13 +DEAL:0::2.14 2.14 +DEAL:0::2.15 2.15 +DEAL:0::number of locally owned cells in tria 0 and tria 1: 71 78 +DEAL:0::2.0 2.0 +DEAL:0::2.1 2.1 +DEAL:0::2.2 2.2 +DEAL:0::2.3 2.3 +DEAL:0::2.4 2.4 +DEAL:0::2.5 2.5 +DEAL:0::2.6 2.6 +DEAL:0::2.7 2.7 +DEAL:0::2.8 2.8 +DEAL:0::2.9 2.9 +DEAL:0::2.10 2.10 +DEAL:0::2.11 2.11 +DEAL:0::2.12 2.12 +DEAL:0::2.13 2.13 +DEAL:0::2.14 2.14 +DEAL:0::2.15 2.15 +DEAL:0::2.16 2.16 +DEAL:0::2.17 2.17 +DEAL:0::2.18 2.18 +DEAL:0::2.19 2.19 +DEAL:0::2.20 2.20 +DEAL:0::2.21 2.21 +DEAL:0::2.22 2.22 +DEAL:0::2.23 2.23 +DEAL:0::2.24 2.24 +DEAL:0::2.25 2.25 +DEAL:0::2.26 2.26 +DEAL:0::2.27 2.27 +DEAL:0::2.28 2.28 +DEAL:0::2.29 2.29 +DEAL:0::2.30 2.30 +DEAL:0::2.31 2.31 +DEAL:0::2.32 2.32 +DEAL:0::2.33 2.33 +DEAL:0::2.34 2.34 +DEAL:0::2.35 2.35 +DEAL:0::2.36 2.36 +DEAL:0::2.37 2.37 +DEAL:0::2.38 2.38 +DEAL:0::2.39 2.39 +DEAL:0::2.40 2.40 +DEAL:0::2.41 2.41 +DEAL:0::2.42 2.42 +DEAL:0::2.43 2.43 +DEAL:0::2.44 2.44 +DEAL:0::2.45 2.45 +DEAL:0::2.46 2.46 +DEAL:0::2.47 2.47 +DEAL:0::2.48 2.48 +DEAL:0::2.49 2.49 +DEAL:0::2.50 2.50 +DEAL:0::2.51 2.51 +DEAL:0::2.52 2.52 +DEAL:0::2.53 2.53 +DEAL:0::2.54 2.54 +DEAL:0::2.55 2.55 +DEAL:0::2.56 2.56 +DEAL:0::2.57 2.57 +DEAL:0::2.58 2.58 +DEAL:0::2.59 2.59 +DEAL:0::2.60 2.60 +DEAL:0::2.61 2.61 +DEAL:0::2.62 2.62 +DEAL:0::2.63 2.63 + +DEAL:1::number of locally owned cells in tria 0 and tria 1: 19 22 +DEAL:1::2.0 2.0 +DEAL:1::2.1 2.1 +DEAL:1::2.2 2.2 +DEAL:1::2.3 2.3 +DEAL:1::2.4 2.4 +DEAL:1::2.5 2.5 +DEAL:1::2.6 2.6 +DEAL:1::2.7 2.7 +DEAL:1::2.8 2.8 +DEAL:1::2.9 2.9 +DEAL:1::2.10 2.10 +DEAL:1::2.11 2.11 +DEAL:1::2.12 2.12 +DEAL:1::2.13 2.13 +DEAL:1::2.14 2.14 +DEAL:1::2.15 2.15 +DEAL:1::number of locally owned cells in tria 0 and tria 1: 71 78 +DEAL:1::2.0 2.0 +DEAL:1::2.1 2.1 +DEAL:1::2.2 2.2 +DEAL:1::2.3 2.3 +DEAL:1::2.4 2.4 +DEAL:1::2.5 2.5 +DEAL:1::2.6 2.6 +DEAL:1::2.7 2.7 +DEAL:1::2.8 2.8 +DEAL:1::2.9 2.9 +DEAL:1::2.10 2.10 +DEAL:1::2.11 2.11 +DEAL:1::2.12 2.12 +DEAL:1::2.13 2.13 +DEAL:1::2.14 2.14 +DEAL:1::2.15 2.15 +DEAL:1::2.16 2.16 +DEAL:1::2.17 2.17 +DEAL:1::2.18 2.18 +DEAL:1::2.19 2.19 +DEAL:1::2.20 2.20 +DEAL:1::2.21 2.21 +DEAL:1::2.22 2.22 +DEAL:1::2.23 2.23 +DEAL:1::2.24 2.24 +DEAL:1::2.25 2.25 +DEAL:1::2.26 2.26 +DEAL:1::2.27 2.27 +DEAL:1::2.28 2.28 +DEAL:1::2.29 2.29 +DEAL:1::2.30 2.30 +DEAL:1::2.31 2.31 +DEAL:1::2.32 2.32 +DEAL:1::2.33 2.33 +DEAL:1::2.34 2.34 +DEAL:1::2.35 2.35 +DEAL:1::2.36 2.36 +DEAL:1::2.37 2.37 +DEAL:1::2.38 2.38 +DEAL:1::2.39 2.39 +DEAL:1::2.40 2.40 +DEAL:1::2.41 2.41 +DEAL:1::2.42 2.42 +DEAL:1::2.43 2.43 +DEAL:1::2.44 2.44 +DEAL:1::2.45 2.45 +DEAL:1::2.46 2.46 +DEAL:1::2.47 2.47 +DEAL:1::2.48 2.48 +DEAL:1::2.49 2.49 +DEAL:1::2.50 2.50 +DEAL:1::2.51 2.51 +DEAL:1::2.52 2.52 +DEAL:1::2.53 2.53 +DEAL:1::2.54 2.54 +DEAL:1::2.55 2.55 +DEAL:1::2.56 2.56 +DEAL:1::2.57 2.57 +DEAL:1::2.58 2.58 +DEAL:1::2.59 2.59 +DEAL:1::2.60 2.60 +DEAL:1::2.61 2.61 +DEAL:1::2.62 2.62 +DEAL:1::2.63 2.63 + From cadba6b200a3a1f0335edd93c0bd1166dc5a7af2 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Fri, 15 Mar 2019 12:14:45 -0500 Subject: [PATCH 279/507] CMake: Reorganize MPI sanity check --- cmake/configure/configure_1_mpi.cmake | 80 +++++++++++++++++++-------- 1 file changed, 58 insertions(+), 22 deletions(-) diff --git a/cmake/configure/configure_1_mpi.cmake b/cmake/configure/configure_1_mpi.cmake index f5e349b1126e..f3f27eb92e5f 100644 --- a/cmake/configure/configure_1_mpi.cmake +++ b/cmake/configure/configure_1_mpi.cmake @@ -39,42 +39,78 @@ MACRO(FEATURE_MPI_FIND_EXTERNAL var) SET(${var} FALSE) ENDIF() + # + # Check that we can link with the full MPI interface: + # + + SET(_linker_flags "${DEAL_II_LINKER_FLAGS}") + 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}" + "${_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." + IF(NOT MPI_WORKING_COMPILER AND DEAL_II_COMPILER_HAS_FUSE_LD_LLD) + MESSAGE(STATUS + "Unable to compile a simple test program. " + "Trying to drop \"-fuse-ld=lld\" from the linker flags." ) - STRING(REPLACE "-fuse-ld=gold" "" _filtered_flags "${DEAL_II_LINKER_FLAGS}") + + IF(DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) + STRING(REPLACE "-fuse-ld=lld" "-fuse-ld=gold" + _linker_flags "${_linker_flags}" + ) + ELSE() + STRING(REPLACE "-fuse-ld=lld" "" + _linker_flags "${_linker_flags}" + ) + ENDIF() + + SET(DEAL_II_COMPILER_HAS_FUSE_LD_LLD FALSE CACHE INTERNAL "" FORCE) + SET(DEAL_II_COMPILER_HAS_FUSE_LD_LLD FALSE) 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}" + "${_linker_flags} ${DEAL_II_LINKER_FLAGS_SAVED} ${MPI_LINKER_FLAGS}" MPI_WORKING_COMPILER ${DEAL_II_LIBRARIES} ${MPI_LIBRARIES} ) + ENDIF() - 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() + IF(NOT MPI_WORKING_COMPILER AND DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) + MESSAGE(STATUS + "Unable to compile a simple test program. " + "Trying to drop \"-fuse-ld=gold\" from the linker flags." + ) + + STRING(REPLACE "-fuse-ld=gold" "" + _linker_flags "${_linker_flags}" + ) + + SET(DEAL_II_COMPILER_HAS_FUSE_LD_GOLD FALSE CACHE INTERNAL "" FORCE) + SET(DEAL_II_COMPILER_HAS_FUSE_LD_GOLD FALSE) + + CHECK_COMPILER_SETUP( + "${DEAL_II_CXX_FLAGS} ${DEAL_II_CXX_FLAGS_SAVED} ${MPI_CXX_FLAGS}" + "${_linker_flags} ${DEAL_II_LINKER_FLAGS_SAVED} ${MPI_LINKER_FLAGS}" + MPI_WORKING_COMPILER + ${DEAL_II_LIBRARIES} ${MPI_LIBRARIES} + ) + ENDIF() + + IF(MPI_WORKING_COMPILER) + SET(DEAL_II_LINKER_FLAGS "${_linker_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() From b9e55a520462b53a646b418701ccdb3a1befb633 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Fri, 15 Mar 2019 12:20:58 -0500 Subject: [PATCH 280/507] Revert "Only permit use of ld.lld linker when the Clang compiler is used." This reverts commit 7ca10c52d89ec0e201320acaa9b34822d47779df. --- cmake/checks/check_02_compiler_features.cmake | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmake/checks/check_02_compiler_features.cmake b/cmake/checks/check_02_compiler_features.cmake index fae50833f9e4..d108cc47672f 100644 --- a/cmake/checks/check_02_compiler_features.cmake +++ b/cmake/checks/check_02_compiler_features.cmake @@ -460,11 +460,7 @@ CHECK_CXX_SOURCE_COMPILES( DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) RESET_CMAKE_REQUIRED() -# -# The ld.lld linker is not compatible with GCC. So we only enable it when -# the Clang compiler is used. See https://github.com/dealii/dealii/issues/7811 -# -IF(DEAL_II_COMPILER_HAS_FUSE_LD_LLD AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") +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") From 06a02074212136dd533c23d5c8460a22179a40e0 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Mon, 18 Mar 2019 13:06:20 -0500 Subject: [PATCH 281/507] CMake: Refactor MPI sanity check into setup_finalize.cmake --- cmake/configure/configure_1_mpi.cmake | 74 --------------------------- cmake/setup_finalize.cmake | 52 ++++++++++++++++--- 2 files changed, 46 insertions(+), 80 deletions(-) diff --git a/cmake/configure/configure_1_mpi.cmake b/cmake/configure/configure_1_mpi.cmake index f3f27eb92e5f..a5929c590838 100644 --- a/cmake/configure/configure_1_mpi.cmake +++ b/cmake/configure/configure_1_mpi.cmake @@ -39,80 +39,6 @@ MACRO(FEATURE_MPI_FIND_EXTERNAL var) SET(${var} FALSE) ENDIF() - # - # Check that we can link with the full MPI interface: - # - - SET(_linker_flags "${DEAL_II_LINKER_FLAGS}") - - CHECK_COMPILER_SETUP( - "${DEAL_II_CXX_FLAGS} ${DEAL_II_CXX_FLAGS_SAVED} ${MPI_CXX_FLAGS}" - "${_linker_flags} ${DEAL_II_LINKER_FLAGS_SAVED} ${MPI_LINKER_FLAGS}" - MPI_WORKING_COMPILER - ${DEAL_II_LIBRARIES} ${MPI_LIBRARIES} - ) - - IF(NOT MPI_WORKING_COMPILER AND DEAL_II_COMPILER_HAS_FUSE_LD_LLD) - MESSAGE(STATUS - "Unable to compile a simple test program. " - "Trying to drop \"-fuse-ld=lld\" from the linker flags." - ) - - IF(DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) - STRING(REPLACE "-fuse-ld=lld" "-fuse-ld=gold" - _linker_flags "${_linker_flags}" - ) - ELSE() - STRING(REPLACE "-fuse-ld=lld" "" - _linker_flags "${_linker_flags}" - ) - ENDIF() - - SET(DEAL_II_COMPILER_HAS_FUSE_LD_LLD FALSE CACHE INTERNAL "" FORCE) - SET(DEAL_II_COMPILER_HAS_FUSE_LD_LLD FALSE) - - CHECK_COMPILER_SETUP( - "${DEAL_II_CXX_FLAGS} ${DEAL_II_CXX_FLAGS_SAVED} ${MPI_CXX_FLAGS}" - "${_linker_flags} ${DEAL_II_LINKER_FLAGS_SAVED} ${MPI_LINKER_FLAGS}" - MPI_WORKING_COMPILER - ${DEAL_II_LIBRARIES} ${MPI_LIBRARIES} - ) - ENDIF() - - IF(NOT MPI_WORKING_COMPILER AND DEAL_II_COMPILER_HAS_FUSE_LD_GOLD) - MESSAGE(STATUS - "Unable to compile a simple test program. " - "Trying to drop \"-fuse-ld=gold\" from the linker flags." - ) - - STRING(REPLACE "-fuse-ld=gold" "" - _linker_flags "${_linker_flags}" - ) - - SET(DEAL_II_COMPILER_HAS_FUSE_LD_GOLD FALSE CACHE INTERNAL "" FORCE) - SET(DEAL_II_COMPILER_HAS_FUSE_LD_GOLD FALSE) - - CHECK_COMPILER_SETUP( - "${DEAL_II_CXX_FLAGS} ${DEAL_II_CXX_FLAGS_SAVED} ${MPI_CXX_FLAGS}" - "${_linker_flags} ${DEAL_II_LINKER_FLAGS_SAVED} ${MPI_LINKER_FLAGS}" - MPI_WORKING_COMPILER - ${DEAL_II_LIBRARIES} ${MPI_LIBRARIES} - ) - ENDIF() - - IF(MPI_WORKING_COMPILER) - SET(DEAL_II_LINKER_FLAGS "${_linker_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() ENDMACRO() diff --git a/cmake/setup_finalize.cmake b/cmake/setup_finalize.cmake index da1d0b9e77da..1df5d7b27141 100644 --- a/cmake/setup_finalize.cmake +++ b/cmake/setup_finalize.cmake @@ -84,12 +84,52 @@ 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." + ) + STRING(REPLACE "${_linker_flag}" "${_replacement_flag}" + DEAL_II_LINKER_FLAGS "${DEAL_II_LINKER_FLAGS}" + ) + STRING(REPLACE "${_linker_flag}" "${_replacement_flag}" + DEAL_II_LINKER_FLAGS_${build} "${DEAL_II_LINKER_FLAGS_${_build}}" + ) + 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 " From fb8efca2364e89b0fbda3fc5640bc66985f043ea Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Mon, 18 Mar 2019 14:40:14 -0400 Subject: [PATCH 282/507] Add missing #ifdef DEAL_II_WITH_THREADS around tbb calls --- include/deal.II/base/parallel.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/deal.II/base/parallel.h b/include/deal.II/base/parallel.h index 8b9d5cc49159..3fd86d2df1a6 100644 --- a/include/deal.II/base/parallel.h +++ b/include/deal.II/base/parallel.h @@ -147,6 +147,7 @@ namespace parallel +#ifdef DEAL_II_WITH_THREADS /** * Encapsulate tbb::parallel_for. */ @@ -179,6 +180,7 @@ namespace parallel functor, *partitioner); } +#endif } // namespace internal /** From 8f0c085303964852cd393b87b132b3395f6d7758 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 19 Mar 2019 01:08:45 +0100 Subject: [PATCH 283/507] Unify two symbol checks --- cmake/configure/configure_scalapack.cmake | 42 +++++++++-------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/cmake/configure/configure_scalapack.cmake b/cmake/configure/configure_scalapack.cmake index 273689bf1c28..919a311c4fc1 100644 --- a/cmake/configure/configure_scalapack.cmake +++ b/cmake/configure/configure_scalapack.cmake @@ -28,36 +28,28 @@ MACRO(FEATURE_SCALAPACK_FIND_EXTERNAL var) CHECK_MPI_INTERFACE(SCALAPACK ${var}) IF (${var}) - CHECK_LIBRARY_EXISTS (${SCALAPACK_LIBRARY} pdsyevr_ {SCALAPACK_DIR} DEAL_II_SCALAPACK_HAS_PDSYEVR) - IF(NOT DEAL_II_SCALAPACK_HAS_PDSYEVR) + SET(CMAKE_REQUIRED_LIBRARIES ${SCALAPACK_LIBRARY}) + 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 symbol pdsyevr_ was not found." + "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_ 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() - - IF(${var}) - CHECK_LIBRARY_EXISTS (${SCALAPACK_LIBRARY} pssyevr_ {SCALAPACK_DIR} DEAL_II_SCALAPACK_HAS_PSSYEVR) - IF(NOT DEAL_II_SCALAPACK_HAS_PSSYEVR) - MESSAGE(STATUS "Could not find a sufficient SCALAPACK installation: " - "The required symbol pssyevr_ was not found." - ) - SET(SCALAPACK_ADDITIONAL_ERROR_STRING - ${SCALAPACK_ADDITIONAL_ERROR_STRING} - "Could not find a sufficient SCALAPACK installation: \n" - "SCALAPACK symbol check for pssyevr_ failed! This usually means that " - "your SCALAPACK installation is incomplete or the link line is " - "broken. Consult\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" ) From 4df736333d9b07bb80bd757f2f98aa74a5a581b3 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 19 Mar 2019 11:19:03 +0100 Subject: [PATCH 284/507] Fix Tpetra test for std::fabs without std::complex overload --- tests/trilinos/tpetra_vector_02.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/trilinos/tpetra_vector_02.cc b/tests/trilinos/tpetra_vector_02.cc index ff5bfc4f16fb..105e435c8605 100644 --- a/tests/trilinos/tpetra_vector_02.cc +++ b/tests/trilinos/tpetra_vector_02.cc @@ -196,7 +196,7 @@ test() AssertThrow(b.l1_norm() == 95., ExcMessage("Problem in l1_norm.")); const double eps = 1e-6; - AssertThrow(std::fabs(b.l2_norm() - Number(31.3847096)) < eps, + AssertThrow(std::fabs(b.l2_norm() - 31.3847096) < eps, ExcMessage("Problem in l2_norm")); AssertThrow(b.linfty_norm() == 14., ExcMessage("Problem in linfty_norm.")); From 1794dc428948d94f1f44074495036990426b5477 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Tue, 19 Mar 2019 10:48:18 +0100 Subject: [PATCH 285/507] Update CMake configuration of SymEngine libraries. --- cmake/modules/FindSYMENGINE.cmake | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/modules/FindSYMENGINE.cmake b/cmake/modules/FindSYMENGINE.cmake index ad0624507365..9c9dbbba071f 100644 --- a/cmake/modules/FindSYMENGINE.cmake +++ b/cmake/modules/FindSYMENGINE.cmake @@ -118,15 +118,15 @@ STRING(REGEX REPLACE REMOVE_DUPLICATES(_symengine_include_dirs) # -# The SYMENGINE_LIBRARIES variable configured by SymEngine only lists the -# libraries, but does not set their paths. So we configure this outselves. +# 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}) - DEAL_II_FIND_LIBRARY(SYMENGINE_LIBRARY - NAMES ${SYMENGINE_LIBRARY_NAME} - HINTS ${SYMENGINE_DIR} - PATH_SUFFIXES lib${LIB_SUFFIX} lib64 lib - ) + 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() From 3e8fd73e32eb19dffd9b51df72fb58037ab0e78d Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Tue, 19 Mar 2019 11:55:48 +0100 Subject: [PATCH 286/507] Add quick test for SymEngine --- tests/quick_tests/CMakeLists.txt | 5 +++ tests/quick_tests/symengine.cc | 75 ++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 tests/quick_tests/symengine.cc diff --git a/tests/quick_tests/CMakeLists.txt b/tests/quick_tests/CMakeLists.txt index f76cfc008b7a..b9530cb5309b 100644 --- a/tests/quick_tests/CMakeLists.txt +++ b/tests/quick_tests/CMakeLists.txt @@ -193,6 +193,11 @@ IF (DEAL_II_WITH_GMSH) make_quicktest("gmsh" ${_mybuild} "") ENDIF() +# Test SymEngine +IF (DEAL_II_WITH_SYMENGINE) + make_quicktest("symengine" ${_mybuild} "") +ENDIF() + # A custom test target: ADD_CUSTOM_TARGET(test COMMAND ${CMAKE_COMMAND} -D ALL_TESTS="${ALL_TESTS}" -P ${CMAKE_CURRENT_SOURCE_DIR}/run.cmake diff --git a/tests/quick_tests/symengine.cc b/tests/quick_tests/symengine.cc new file mode 100644 index 000000000000..3cd221b159bf --- /dev/null +++ b/tests/quick_tests/symengine.cc @@ -0,0 +1,75 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Adaptation of symengine/basic_[01,02].cc for a quick test + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace dealii; +namespace SE = SymEngine; + +int +main() +{ + { + const SE::RCP a = SE::integer(2); + const SE::RCP b = SE::real_double(4.2); + + const SE::RCP c = SE::add(a, b); + deallog << "c = a+b: " << *c << std::endl; + } + + { + const SE::RCP a = SE::real_double(3.1); + const SE::RCP b = SE::real_double(7.5); + + const SE::RCP x = (SE::symbol("x")); + const SE::RCP y = (SE::symbol("y")); + + // Construction of symbolic function + const SE::RCP c = + SE::mul(y, SE::mul(SE::sub(y, b), SE::add(a, x))); + deallog << "c = y*(y-b)*(a+x): " << *c << std::endl; + + // Perform symbolic differentiation + const SE::RCP dc_dx = c->diff(x); + const SE::RCP dc_dy = c->diff(y); + + deallog << "dc_dx = y*(y-b): " << *dc_dx << std::endl; + deallog << "dc_dy = (2*y+1)*(a+x): " << *dc_dy << std::endl; + + const SE::RCP dc_dx_check = SE::mul(y, SE::sub(y, b)); + const SE::RCP dc_dy_check = + SE::mul(SE::sub(SE::mul(SE::integer(2), y), b), SE::add(a, x)); + Assert(SE::eq(*dc_dx, *dc_dx_check), ExcMessage("Should be equal!")); + // Although these two *values* are the same, the underlying + // *representation* is different. So we'd need to match the representation + // exactly, and I'm too lazy to do this right now. + // Assert(SE::eq(*dc_dy, *dc_dy_check), ExcMessage("Should be equal!")); + } + + deallog << "OK" << std::endl; +} From 9363cab6b03d1bac6d139a3d828a4ebff92fa055 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Tue, 19 Mar 2019 17:55:41 +0100 Subject: [PATCH 287/507] use Utilities::MPI::some_to_some() in SparsityTools::distribute_sparsity_pattern(), improve const-correctness --- source/lac/dynamic_sparsity_pattern.cc | 5 ++ source/lac/sparsity_tools.cc | 116 ++++++------------------- 2 files changed, 30 insertions(+), 91 deletions(-) diff --git a/source/lac/dynamic_sparsity_pattern.cc b/source/lac/dynamic_sparsity_pattern.cc index dcf53e1bbcef..95ca12cdc4b7 100644 --- a/source/lac/dynamic_sparsity_pattern.cc +++ b/source/lac/dynamic_sparsity_pattern.cc @@ -612,6 +612,11 @@ template void DynamicSparsityPattern::Line::add_entries(std::vector::iterator, std::vector::iterator, const bool); +template void +DynamicSparsityPattern::Line::add_entries( + std::vector::const_iterator, + std::vector::const_iterator, + const bool); #endif template void diff --git a/source/lac/sparsity_tools.cc b/source/lac/sparsity_tools.cc index e04c9e54f4fa..eeba2592de4b 100644 --- a/source/lac/sparsity_tools.cc +++ b/source/lac/sparsity_tools.cc @@ -925,21 +925,19 @@ namespace SparsityTools for (DynamicSparsityPattern::size_type i = 0; i < rows_per_cpu.size(); ++i) start_index[i + 1] = start_index[i] + rows_per_cpu[i]; - using map_vec_t = std::map>; + using map_vec_t = + std::map>; map_vec_t send_data; { - unsigned int dest_cpu = 0; - - DynamicSparsityPattern::size_type n_local_rel_rows = myrange.n_elements(); + unsigned int dest_cpu = 0; + const auto n_local_rel_rows = myrange.n_elements(); for (DynamicSparsityPattern::size_type row_idx = 0; row_idx < n_local_rel_rows; ++row_idx) { - DynamicSparsityPattern::size_type row = - myrange.nth_index_in_set(row_idx); + const auto row = myrange.nth_index_in_set(row_idx); // calculate destination CPU while (row >= start_index[dest_cpu + 1]) @@ -952,109 +950,45 @@ namespace SparsityTools continue; } - DynamicSparsityPattern::size_type rlen = dsp.row_length(row); + const auto rlen = dsp.row_length(row); // skip empty lines if (!rlen) continue; // save entries - std::vector &dst = - send_data[dest_cpu]; + auto &dst = send_data[dest_cpu]; dst.push_back(rlen); // number of entries dst.push_back(row); // row index for (DynamicSparsityPattern::size_type c = 0; c < rlen; ++c) { // columns - DynamicSparsityPattern::size_type column = - dsp.column_number(row, c); + const auto column = dsp.column_number(row, c); dst.push_back(column); } } } - unsigned int num_receive = 0; - { - std::vector send_to; - send_to.reserve(send_data.size()); - for (const auto &sparsity_line : send_data) - send_to.push_back(sparsity_line.first); - - num_receive = - Utilities::MPI::compute_n_point_to_point_communications(mpi_comm, - send_to); - } - - std::vector requests(send_data.size()); + const auto receive_data = Utilities::MPI::some_to_some(mpi_comm, send_data); - - // send data - { - unsigned int idx = 0; - for (const auto &sparsity_line : send_data) - { - const int ierr = - MPI_Isend(DEAL_II_MPI_CONST_CAST(sparsity_line.second.data()), - sparsity_line.second.size(), - DEAL_II_DOF_INDEX_MPI_TYPE, - sparsity_line.first, - 124, - mpi_comm, - &requests[idx++]); - AssertThrowMPI(ierr); - } - } - - { - // receive - std::vector recv_buf; - for (unsigned int index = 0; index < num_receive; ++index) - { - MPI_Status status; - int len; - int ierr = MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, mpi_comm, &status); - AssertThrowMPI(ierr); - Assert(status.MPI_TAG == 124, ExcInternalError()); - - ierr = MPI_Get_count(&status, DEAL_II_DOF_INDEX_MPI_TYPE, &len); - AssertThrowMPI(ierr); - recv_buf.resize(len); - ierr = MPI_Recv(recv_buf.data(), - len, - DEAL_II_DOF_INDEX_MPI_TYPE, - status.MPI_SOURCE, - status.MPI_TAG, - mpi_comm, - &status); - AssertThrowMPI(ierr); - - std::vector::const_iterator ptr = - recv_buf.begin(); - std::vector::const_iterator end = - recv_buf.end(); - while (ptr != end) - { - DynamicSparsityPattern::size_type num = *(ptr++); - Assert(ptr != end, ExcInternalError()); - DynamicSparsityPattern::size_type row = *(ptr++); - for (unsigned int c = 0; c < num; ++c) - { - Assert(ptr != end, ExcInternalError()); - dsp.add(row, *ptr); - ++ptr; - } - } - Assert(ptr == end, ExcInternalError()); - } - } - - // complete all sends, so that we can safely destroy the buffers. - if (requests.size()) + // add what we received + for (const auto &data : receive_data) { - const int ierr = - MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE); - AssertThrowMPI(ierr); + const auto &recv_buf = data.second; + auto ptr = recv_buf.begin(); + const auto end = recv_buf.end(); + while (ptr != end) + { + const DynamicSparsityPattern::size_type num = *(ptr++); + Assert(ptr != end, ExcInternalError()); + const DynamicSparsityPattern::size_type row = *(ptr++); + + Assert(ptr + (num - 1) != end, ExcInternalError()); + dsp.add_entries(row, ptr, ptr + num, true); + ptr += num; + } + Assert(ptr == end, ExcInternalError()); } } From e9cd64520adbbaff38b818be928c0ef470336703 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Tue, 19 Mar 2019 12:30:41 -0600 Subject: [PATCH 288/507] step-15: doc update --- examples/step-15/doc/results.dox | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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

    From 2122c20d0e62bb9483d4a8c118af262f439ee85f Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Tue, 19 Mar 2019 14:10:02 -0600 Subject: [PATCH 289/507] fix tbb range size type --- include/deal.II/lac/vector_operations_internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/deal.II/lac/vector_operations_internal.h b/include/deal.II/lac/vector_operations_internal.h index bd13406faac5..95ea6bc18cae 100644 --- a/include/deal.II/lac/vector_operations_internal.h +++ b/include/deal.II/lac/vector_operations_internal.h @@ -149,7 +149,7 @@ namespace internal } void - operator()(const tbb::blocked_range &range) const + operator()(const tbb::blocked_range &range) const { const size_type r_begin = start + range.begin() * chunk_size; const size_type r_end = std::min(start + range.end() * chunk_size, end); @@ -1317,7 +1317,7 @@ namespace internal * [range.begin(), range.end()). */ void - operator()(const tbb::blocked_range &range) const + operator()(const tbb::blocked_range &range) const { for (size_type i = range.begin(); i < range.end(); ++i) accumulate_recursive(op, From c4df921001d536ef327184e290cf58365e34f36a Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 19 Mar 2019 21:57:40 +0100 Subject: [PATCH 290/507] Fix SCALAPACK symbol check --- cmake/configure/configure_scalapack.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/configure/configure_scalapack.cmake b/cmake/configure/configure_scalapack.cmake index 919a311c4fc1..a91457f379c2 100644 --- a/cmake/configure/configure_scalapack.cmake +++ b/cmake/configure/configure_scalapack.cmake @@ -28,7 +28,7 @@ MACRO(FEATURE_SCALAPACK_FIND_EXTERNAL var) CHECK_MPI_INTERFACE(SCALAPACK ${var}) IF (${var}) - SET(CMAKE_REQUIRED_LIBRARIES ${SCALAPACK_LIBRARY}) + SET(CMAKE_REQUIRED_LIBRARIES ${SCALAPACK_LIBRARIES}) CHECK_C_SOURCE_COMPILES(" void pdsyevr_(); void pssyevr_(); @@ -47,7 +47,7 @@ MACRO(FEATURE_SCALAPACK_FIND_EXTERNAL var) 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! " + "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" From f1fc309538dcb6becd9e1a71065040867013b4ea Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Tue, 19 Mar 2019 16:37:34 -0500 Subject: [PATCH 291/507] CMake: also update BASE_LINKER_FLAGS* when dropping -fuse-ld=... --- cmake/setup_finalize.cmake | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cmake/setup_finalize.cmake b/cmake/setup_finalize.cmake index 1df5d7b27141..716093a7b3b5 100644 --- a/cmake/setup_finalize.cmake +++ b/cmake/setup_finalize.cmake @@ -99,12 +99,14 @@ FOREACH(build ${DEAL_II_BUILD_TYPES}) "Unable to compile a simple test program. " "Trying to drop \"${_linker_flag}\" from the linker flags." ) - STRING(REPLACE "${_linker_flag}" "${_replacement_flag}" - DEAL_II_LINKER_FLAGS "${DEAL_II_LINKER_FLAGS}" - ) - STRING(REPLACE "${_linker_flag}" "${_replacement_flag}" - DEAL_II_LINKER_FLAGS_${build} "${DEAL_II_LINKER_FLAGS_${_build}}" - ) + 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() From 3b486e3e6089c1cd268c12585182af5d0fbd2b72 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Wed, 20 Mar 2019 11:59:53 +0100 Subject: [PATCH 292/507] use range loop in SparsityTools::distribute_sparsity_pattern() --- source/lac/sparsity_tools.cc | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/source/lac/sparsity_tools.cc b/source/lac/sparsity_tools.cc index eeba2592de4b..2ec2422ad64f 100644 --- a/source/lac/sparsity_tools.cc +++ b/source/lac/sparsity_tools.cc @@ -925,30 +925,27 @@ namespace SparsityTools for (DynamicSparsityPattern::size_type i = 0; i < rows_per_cpu.size(); ++i) start_index[i + 1] = start_index[i] + rows_per_cpu[i]; + IndexSet owned(start_index.back()); + owned.add_range(start_index[myid], start_index[myid] + rows_per_cpu[myid]); + + IndexSet myrange_non_owned(myrange); + myrange_non_owned.subtract_set(owned); + using map_vec_t = std::map>; map_vec_t send_data; { - unsigned int dest_cpu = 0; - const auto n_local_rel_rows = myrange.n_elements(); - for (DynamicSparsityPattern::size_type row_idx = 0; - row_idx < n_local_rel_rows; - ++row_idx) + unsigned int dest_cpu = 0; + for (const auto &row : myrange_non_owned) { - const auto row = myrange.nth_index_in_set(row_idx); - // calculate destination CPU while (row >= start_index[dest_cpu + 1]) ++dest_cpu; - // skip myself - if (dest_cpu == myid) - { - row_idx += rows_per_cpu[myid] - 1; - continue; - } + // we removed owned, thus shall not hit ourselves + Assert(dest_cpu != myid, ExcInternalError()); const auto rlen = dsp.row_length(row); From 574c41753c62d8524018649dcab58da1cb8cac7a Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 20 Mar 2019 16:20:44 +0100 Subject: [PATCH 293/507] Remove IndexSet overloads in DataOut --- .../incompatibilities/20190320DanielArndt | 4 + examples/step-41/step-41.cc | 14 +- examples/step-42/step-42.cc | 25 +- include/deal.II/fe/fe_values.h | 20 +- include/deal.II/numerics/data_out_dof_data.h | 8 +- source/fe/fe_values.inst.in | 292 ------------------ source/numerics/data_out_dof_data.inst.in | 76 ----- .../numerics/data_out_dof_data_codim.inst.in | 30 -- 8 files changed, 34 insertions(+), 435 deletions(-) create mode 100644 doc/news/changes/incompatibilities/20190320DanielArndt 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/examples/step-41/step-41.cc b/examples/step-41/step-41.cc index 41d2e233aeda..662829c1507b 100644 --- a/examples/step-41/step-41.cc +++ b/examples/step-41/step-41.cc @@ -101,6 +101,7 @@ namespace Step41 TrilinosWrappers::SparseMatrix complete_system_matrix; TrilinosWrappers::MPI::Vector solution; + TrilinosWrappers::MPI::Vector active_set_vector; TrilinosWrappers::MPI::Vector system_rhs; TrilinosWrappers::MPI::Vector complete_system_rhs; TrilinosWrappers::MPI::Vector diagonal_of_mass_matrix; @@ -261,6 +262,7 @@ namespace Step41 IndexSet solution_index_set = dof_handler.locally_owned_dofs(); solution.reinit(solution_index_set, MPI_COMM_WORLD); + active_set_vector.reinit(solution_index_set, MPI_COMM_WORLD); system_rhs.reinit(solution_index_set, MPI_COMM_WORLD); complete_system_rhs.reinit(solution_index_set, MPI_COMM_WORLD); contact_force.reinit(solution_index_set, MPI_COMM_WORLD); @@ -542,6 +544,10 @@ namespace Step41 BoundaryValues(), constraints); constraints.close(); + + active_set_vector = 0.; + for (const auto index : active_set) + active_set_vector[index] = 1.; } // @sect4{ObstacleProblem::solve} @@ -576,11 +582,7 @@ 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 { @@ -590,7 +592,7 @@ namespace Step41 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 94cc9e445aa9..ec2b52df7944 100644 --- a/examples/step-42/step-42.cc +++ b/examples/step-42/step-42.cc @@ -701,6 +701,7 @@ namespace Step42 TrilinosWrappers::SparseMatrix newton_matrix; TrilinosWrappers::MPI::Vector solution; + TrilinosWrappers::MPI::Vector active_set_vector; TrilinosWrappers::MPI::Vector newton_rhs; TrilinosWrappers::MPI::Vector newton_rhs_uncondensed; TrilinosWrappers::MPI::Vector diag_mass_matrix_vector; @@ -1022,6 +1023,7 @@ namespace Step42 { TimerOutput::Scope t(computing_timer, "Setup: vectors"); solution.reinit(locally_relevant_dofs, mpi_communicator); + active_set_vector.reinit(locally_relevant_dofs, MPI_COMM_WORLD); newton_rhs.reinit(locally_owned_dofs, mpi_communicator); newton_rhs_uncondensed.reinit(locally_owned_dofs, mpi_communicator); diag_mass_matrix_vector.reinit(locally_owned_dofs, mpi_communicator); @@ -1339,6 +1341,14 @@ namespace Step42 all_constraints.close(); all_constraints.merge(constraints_dirichlet_and_hanging_nodes); + // We misuse distributed_solution for updating active_set_vector. + // We can do that because distributed_solution has a compatible underlying + // IndexSet and we don't need the vector anymore. + distributed_solution = 0.; + for (const auto index : active_set) + distributed_solution[index] = 1.; + active_set_vector = distributed_solution; + pcout << " Size of active set: " << Utilities::MPI::sum((active_set & locally_owned_dofs).n_elements(), mpi_communicator) @@ -1388,13 +1398,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,10 +1559,9 @@ 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; + auto cell = dof_handler.begin_active(); + const auto endc = dof_handler.end(); + unsigned int cell_number = 0; for (; cell != endc; ++cell, ++cell_number) if (cell->is_locally_owned()) { @@ -2048,7 +2053,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/include/deal.II/fe/fe_values.h b/include/deal.II/fe/fe_values.h index 713f1c64adad..d810d3b6fb8f 100644 --- a/include/deal.II/fe/fe_values.h +++ b/include/deal.II/fe/fe_values.h @@ -2290,9 +2290,7 @@ class FEValuesBase : public Subscriptor * Vector<T>, BlockVector<T>, or one of the PETSc or Trilinos * vector wrapper classes. It represents a global vector of DoF values * associated with the DoFHandler object with which this FEValues object was - * last initialized. Alternatively, if the vector argument is of type - * IndexSet, then the function is represented as one that is either zero or - * one, depending on whether a DoF index is in the set or not. + * last initialized. * * @dealiiRequiresUpdateFlags{update_values} */ @@ -2449,9 +2447,7 @@ class FEValuesBase : public Subscriptor * Vector<T>, BlockVector<T>, or one of the PETSc or Trilinos * vector wrapper classes. It represents a global vector of DoF values * associated with the DoFHandler object with which this FEValues object was - * last initialized. Alternatively, if the vector argument is of type - * IndexSet, then the function is represented as one that is either zero or - * one, depending on whether a DoF index is in the set or not. + * last initialized. * * @dealiiRequiresUpdateFlags{update_gradients} */ @@ -2554,9 +2550,7 @@ class FEValuesBase : public Subscriptor * Vector<T>, BlockVector<T>, or one of the PETSc or Trilinos * vector wrapper classes. It represents a global vector of DoF values * associated with the DoFHandler object with which this FEValues object was - * last initialized. Alternatively, if the vector argument is of type - * IndexSet, then the function is represented as one that is either zero or - * one, depending on whether a DoF index is in the set or not. + * last initialized. * * @dealiiRequiresUpdateFlags{update_hessians} */ @@ -2657,9 +2651,7 @@ class FEValuesBase : public Subscriptor * Vector<T>, BlockVector<T>, or one of the PETSc or Trilinos * vector wrapper classes. It represents a global vector of DoF values * associated with the DoFHandler object with which this FEValues object was - * last initialized. Alternatively, if the vector argument is of type - * IndexSet, then the function is represented as one that is either zero or - * one, depending on whether a DoF index is in the set or not. + * last initialized. * * @dealiiRequiresUpdateFlags{update_hessians} */ @@ -2772,9 +2764,7 @@ class FEValuesBase : public Subscriptor * Vector<T>, BlockVector<T>, or one of the PETSc or Trilinos * vector wrapper classes. It represents a global vector of DoF values * associated with the DoFHandler object with which this FEValues object was - * last initialized. Alternatively, if the vector argument is of type - * IndexSet, then the function is represented as one that is either zero or - * one, depending on whether a DoF index is in the set or not. + * last initialized. * * @dealiiRequiresUpdateFlags{update_3rd_derivatives} */ diff --git a/include/deal.II/numerics/data_out_dof_data.h b/include/deal.II/numerics/data_out_dof_data.h index ea11144f7e3f..cdf385c1ccc9 100644 --- a/include/deal.II/numerics/data_out_dof_data.h +++ b/include/deal.II/numerics/data_out_dof_data.h @@ -730,9 +730,7 @@ class DataOut_DoFData : public DataOutInterface * * @note The actual type for the vector argument may be any vector type from * which FEValues can extract values on a cell using the - * FEValuesBase::get_function_values() function. In particular, this - * includes all of the usual vector types, but also IndexSet (see step-41 - * for a use of this). + * FEValuesBase::get_function_values() function. */ template void @@ -824,9 +822,7 @@ class DataOut_DoFData : public DataOutInterface * * @note The actual type for the vector argument may be any vector type from * which FEValues can extract values on a cell using the - * FEValuesBase::get_function_values() function. In particular, this - * includes all of the usual vector types, but also IndexSet (see step-41 - * for a use of this). + * FEValuesBase::get_function_values() function. * * @note The DataPostprocessor object (i.e., in reality the object of your * derived class) has to live until the DataOut object is destroyed as the diff --git a/source/fe/fe_values.inst.in b/source/fe/fe_values.inst.in index 863a55f233b3..5073c4d06b22 100644 --- a/source/fe/fe_values.inst.in +++ b/source/fe/fe_values.inst.in @@ -485,295 +485,3 @@ for (VEC : VECTOR_TYPES; deal_II_dimension : DIMENSIONS; #endif } - - -// instantiations for VEC=IndexSet - -for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : DIMENSIONS) - { -#if deal_II_dimension <= deal_II_space_dimension - template void - FEValuesViews::Scalar:: - get_function_values( - const dealii::IndexSet &, - std::vector::type> &) const; - template void - FEValuesViews::Scalar:: - get_function_gradients( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; - template void - FEValuesViews::Scalar:: - get_function_hessians( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; - template void - FEValuesViews::Scalar:: - get_function_laplacians( - const dealii::IndexSet &, - std::vector::type> &) const; - template void - FEValuesViews::Scalar:: - get_function_third_derivatives( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; - - template void - FEValuesViews::Vector:: - get_function_values( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; - template void - FEValuesViews::Vector:: - get_function_gradients( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; - template void - FEValuesViews::Vector:: - get_function_symmetric_gradients( - const dealii::IndexSet &, - std::vector>::type> &) const; - template void - FEValuesViews::Vector:: - get_function_curls( - const dealii::IndexSet &, - std::vector::type> &) - const; - template void - FEValuesViews::Vector:: - get_function_divergences( - const dealii::IndexSet &, - std::vector::type> &) - const; - template void - FEValuesViews::Vector:: - get_function_hessians( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; - template void - FEValuesViews::Vector:: - get_function_laplacians( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; - template void - FEValuesViews::Vector:: - get_function_third_derivatives( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; - - template void FEValuesViews::SymmetricTensor<2, - deal_II_dimension, - deal_II_space_dimension>:: - get_function_values( - const dealii::IndexSet &, - std::vector>::type> &) const; - template void FEValuesViews:: - SymmetricTensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_divergences( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; - - template void - FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_values( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; - template void - FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_divergences( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; - template void - FEValuesViews::Tensor<2, deal_II_dimension, deal_II_space_dimension>:: - get_function_gradients( - const dealii::IndexSet &, - std::vector< - ProductType>::type> &) - const; -#endif - } - - - -// Instantiations of functions in FEValuesBase and IndexSet=IndexSet - -for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : DIMENSIONS) - { -#if deal_II_dimension <= deal_II_space_dimension - template void FEValuesBase:: - get_function_values(const IndexSet &, - std::vector &) const; - template void FEValuesBase:: - get_function_values( - const IndexSet &, - const ArrayView &, - std::vector &) const; - - template void FEValuesBase:: - get_function_values(const IndexSet &, - std::vector> &) - const; - - template void FEValuesBase:: - get_function_values( - const IndexSet &, - const ArrayView &, - std::vector> &) const; - - template void FEValuesBase:: - get_function_values( - const IndexSet &, - const ArrayView &, - ArrayView>, - bool) const; - - template void FEValuesBase:: - get_function_gradients( - const IndexSet &, - std::vector< - dealii::Tensor<1, deal_II_space_dimension, IndexSet::value_type>> &) - const; - template void FEValuesBase:: - get_function_gradients( - const IndexSet &, - const ArrayView &, - std::vector< - dealii::Tensor<1, deal_II_space_dimension, IndexSet::value_type>> &) - const; - - template void FEValuesBase:: - get_function_gradients( - const IndexSet &, - std::vector>> &) - const; - template void FEValuesBase:: - get_function_gradients( - const IndexSet &, - const ArrayView &, - ArrayView>>, - bool) const; - - template void FEValuesBase:: - get_function_hessians( - const IndexSet &, - std::vector< - dealii::Tensor<2, deal_II_space_dimension, IndexSet::value_type>> &) - const; - template void FEValuesBase:: - get_function_hessians( - const IndexSet &, - const ArrayView &, - std::vector< - dealii::Tensor<2, deal_II_space_dimension, IndexSet::value_type>> &) - const; - - template void FEValuesBase:: - get_function_hessians( - const IndexSet &, - std::vector>> &, - bool) const; - template void FEValuesBase:: - get_function_hessians( - const IndexSet &, - const ArrayView &, - ArrayView>>, - bool) const; - - template void FEValuesBase:: - get_function_laplacians(const IndexSet &, - std::vector &) - const; - template void FEValuesBase:: - get_function_laplacians( - const IndexSet &, - const ArrayView &, - std::vector &) const; - - template void FEValuesBase:: - get_function_laplacians( - const IndexSet &, std::vector> &) const; - - template void FEValuesBase:: - get_function_laplacians( - const IndexSet &, - const ArrayView &, - std::vector> &) const; - - template void FEValuesBase:: - get_function_laplacians( - const IndexSet &, - const ArrayView &, - std::vector> &, - bool) const; - - template void FEValuesBase:: - get_function_third_derivatives( - const IndexSet &, - std::vector< - dealii::Tensor<3, deal_II_space_dimension, IndexSet::value_type>> &) - const; - template void FEValuesBase:: - get_function_third_derivatives( - const IndexSet &, - const ArrayView &, - std::vector< - dealii::Tensor<3, deal_II_space_dimension, IndexSet::value_type>> &) - const; - - template void FEValuesBase:: - get_function_third_derivatives( - const IndexSet &, - std::vector>> &, - bool) const; - template void FEValuesBase:: - get_function_third_derivatives( - const IndexSet &, - const ArrayView &, - ArrayView>>, - bool) const; -#endif - } diff --git a/source/numerics/data_out_dof_data.inst.in b/source/numerics/data_out_dof_data.inst.in index 1d2cf2612df3..ecc15cb3602f 100644 --- a/source/numerics/data_out_dof_data.inst.in +++ b/source/numerics/data_out_dof_data.inst.in @@ -93,82 +93,6 @@ for (VEC : VECTOR_TYPES; DH : DOFHANDLER_TEMPLATES; -for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) - { - template void DataOut_DoFData, - deal_II_dimension, - deal_II_dimension>:: - add_data_vector_internal( - const DH *, - const IndexSet &, - const std::vector &, - const DataVectorType, - const std::vector< - DataComponentInterpretation::DataComponentInterpretation> &, - const bool); - - template void DataOut_DoFData, - deal_II_dimension, - deal_II_dimension>:: - add_data_vector( - const DH &, - const IndexSet &, - const DataPostprocessor< - DH::space_dimension> &); - - - - // stuff needed for face data - - template void DataOut_DoFData, - deal_II_dimension - 1, - deal_II_dimension>:: - add_data_vector_internal( - const DH *, - const IndexSet &, - const std::vector &, - const DataVectorType, - const std::vector< - DataComponentInterpretation::DataComponentInterpretation> &, - const bool); - - template void DataOut_DoFData, - deal_II_dimension - 1, - deal_II_dimension>:: - add_data_vector( - const DH &, - const IndexSet &, - const DataPostprocessor< - DH::space_dimension> &); - - // things for DataOutRotation - -#if deal_II_dimension < 3 - template void DataOut_DoFData, - deal_II_dimension + 1, - deal_II_dimension + 1>:: - add_data_vector_internal( - const DH *, - const IndexSet &, - const std::vector &, - const DataVectorType, - const std::vector< - DataComponentInterpretation::DataComponentInterpretation> &, - const bool); - - template void DataOut_DoFData, - deal_II_dimension + 1, - deal_II_dimension + 1>:: - add_data_vector( - const DH &, - const IndexSet &, - const DataPostprocessor< - DH::space_dimension> &); -#endif - } - - - for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) { template class DataOut_DoFData, deal_II_dimension>; diff --git a/source/numerics/data_out_dof_data_codim.inst.in b/source/numerics/data_out_dof_data_codim.inst.in index f5ae7d5b7cc2..005f78bccd76 100644 --- a/source/numerics/data_out_dof_data_codim.inst.in +++ b/source/numerics/data_out_dof_data_codim.inst.in @@ -55,36 +55,6 @@ for (VEC : REAL_VECTOR_TYPES; DH : DOFHANDLER_TEMPLATES; -for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS; - deal_II_space_dimension : DIMENSIONS) - { -#if deal_II_dimension < deal_II_space_dimension - template void - DataOut_DoFData, - deal_II_dimension, - deal_II_space_dimension>:: - add_data_vector_internal( - const DH *, - const IndexSet &, - const std::vector &, - const DataVectorType, - const std::vector< - DataComponentInterpretation::DataComponentInterpretation> &, - const bool); - - template void - DataOut_DoFData, - deal_II_dimension, - deal_II_space_dimension>:: - add_data_vector( - const IndexSet &, - const DataPostprocessor< - DH::space_dimension> &); -#endif - } - - - for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) { #if deal_II_dimension < 3 From d46c79d79a16b70f725800b47998e124171e8858 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 20 Mar 2019 17:01:28 +0100 Subject: [PATCH 294/507] Fix data_out_13 in case there is no ZLIB support --- .../data_out/data_out_13.with_zlib=off.output | 111 ++++++++++++++++++ ...output => data_out_13.with_zlib=on.output} | 0 2 files changed, 111 insertions(+) create mode 100644 tests/data_out/data_out_13.with_zlib=off.output rename tests/data_out/{data_out_13.output => data_out_13.with_zlib=on.output} (100%) diff --git a/tests/data_out/data_out_13.with_zlib=off.output b/tests/data_out/data_out_13.with_zlib=off.output new file mode 100644 index 000000000000..df62af4878fb --- /dev/null +++ b/tests/data_out/data_out_13.with_zlib=off.output @@ -0,0 +1,111 @@ + + + + + + + + +0.00000 0.00000 0 +1.00000 0.00000 0 +0.00000 1.00000 0 +1.00000 1.00000 0 + + + + + +0 1 3 2 + + +4 + + +9 + + + + +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 1.00000 1.00000 0.00000 1.00000 1.00000 0.00000 + +1.00000 0.00000 0.00000 0.00000 1.00000 0.00000 0.00000 0.00000 0.00000 3.00000 0.00000 0.00000 0.00000 1.00000 0.00000 0.00000 0.00000 0.00000 1.00000 0.00000 0.00000 0.00000 3.00000 0.00000 0.00000 0.00000 0.00000 3.00000 1.00000 0.00000 1.00000 2.00000 0.00000 0.00000 0.00000 0.00000 + + + + + + + + + + + + + + + + + + + + + + + + + +0.00000 0.00000 0.00000 +1.00000 0.00000 0.00000 +0.00000 1.00000 0.00000 +1.00000 1.00000 0.00000 +0.00000 0.00000 1.00000 +1.00000 0.00000 1.00000 +0.00000 1.00000 1.00000 +1.00000 1.00000 1.00000 + + + + + +0 1 3 2 4 5 7 6 + + +8 + + +12 + + + + +1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 1.00000 1.00000 0.00000 1.00000 1.00000 0.00000 1.00000 0.00000 0.00000 1.00000 0.00000 0.00000 1.00000 1.00000 0.00000 1.00000 1.00000 0.00000 + +1.00000 0.00000 0.00000 0.00000 1.00000 0.00000 0.00000 0.00000 1.00000 -2.00000 0.00000 0.00000 0.00000 -2.00000 0.00000 0.00000 0.00000 3.00000 1.00000 0.00000 0.00000 0.00000 1.00000 0.00000 0.00000 0.00000 0.00100000 2.00000 1.00000 1.00000 1.00000 2.00000 1.00000 1.00000 1.00000 3.00000 0.247186 0.490995 0.131325 0.490995 -0.371056 0.719072 0.131325 0.719072 -0.156008 0.280588 0.467439 0.934953 0.467439 0.0600321 -0.211376 0.934953 -0.211376 0.962976 0.0628610 -0.0117908 -0.667617 -0.0117908 -0.390601 -0.957805 -0.667617 -0.957805 -0.193320 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 + + + + + + + + + + + + + + + + + + diff --git a/tests/data_out/data_out_13.output b/tests/data_out/data_out_13.with_zlib=on.output similarity index 100% rename from tests/data_out/data_out_13.output rename to tests/data_out/data_out_13.with_zlib=on.output From a78b01abb2d162943fd830df1401aa85ef639a8c Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Wed, 20 Mar 2019 22:19:55 +0100 Subject: [PATCH 295/507] further cleanup of distribute_sparsity_pattern() --- source/lac/sparsity_tools.cc | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/source/lac/sparsity_tools.cc b/source/lac/sparsity_tools.cc index 2ec2422ad64f..1a18621296bc 100644 --- a/source/lac/sparsity_tools.cc +++ b/source/lac/sparsity_tools.cc @@ -954,15 +954,13 @@ namespace SparsityTools continue; // save entries - auto &dst = send_data[dest_cpu]; - - dst.push_back(rlen); // number of entries - dst.push_back(row); // row index + send_data[dest_cpu].push_back(row); // row index + send_data[dest_cpu].push_back(rlen); // number of entries for (DynamicSparsityPattern::size_type c = 0; c < rlen; ++c) { // columns const auto column = dsp.column_number(row, c); - dst.push_back(column); + send_data[dest_cpu].push_back(column); } } } @@ -977,13 +975,13 @@ namespace SparsityTools const auto end = recv_buf.end(); while (ptr != end) { - const DynamicSparsityPattern::size_type num = *(ptr++); + const auto row = *(ptr++); Assert(ptr != end, ExcInternalError()); - const DynamicSparsityPattern::size_type row = *(ptr++); + const auto n_entries = *(ptr++); - Assert(ptr + (num - 1) != end, ExcInternalError()); - dsp.add_entries(row, ptr, ptr + num, true); - ptr += num; + Assert(ptr + (n_entries - 1) != end, ExcInternalError()); + dsp.add_entries(row, ptr, ptr + n_entries, true); + ptr += n_entries; } Assert(ptr == end, ExcInternalError()); } From 5213023ca165bfbd420423551c184a3e31886223 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Wed, 27 Feb 2019 22:04:58 +0100 Subject: [PATCH 296/507] split SparsityPattern into a base class and derived class with a special treatment for diagonal matrices --- include/deal.II/lac/sparsity_pattern.h | 1041 +++++++++++-------- source/lac/sparsity_pattern.cc | 94 +- tests/serialization/sparsity_pattern.output | 4 +- tests/sparsity/sparsity_pattern_13.cc | 171 +++ tests/sparsity/sparsity_pattern_13.output | 7 + 5 files changed, 843 insertions(+), 474 deletions(-) create mode 100644 tests/sparsity/sparsity_pattern_13.cc create mode 100644 tests/sparsity/sparsity_pattern_13.output diff --git a/include/deal.II/lac/sparsity_pattern.h b/include/deal.II/lac/sparsity_pattern.h index 573c6c29475b..e87ca818e207 100644 --- a/include/deal.II/lac/sparsity_pattern.h +++ b/include/deal.II/lac/sparsity_pattern.h @@ -42,6 +42,7 @@ DEAL_II_NAMESPACE_OPEN class SparsityPattern; +class SparsityPatternBase; class DynamicSparsityPattern; class ChunkSparsityPattern; template @@ -139,12 +140,12 @@ namespace SparsityPatternIterators /** * Constructor. */ - Accessor(const SparsityPattern *matrix, const std::size_t linear_index); + Accessor(const SparsityPatternBase *matrix, const std::size_t linear_index); /** * Constructor. Construct the end accessor for the given sparsity pattern. */ - Accessor(const SparsityPattern *matrix); + Accessor(const SparsityPatternBase *matrix); /** * Default constructor creating a dummy accessor. This constructor is here @@ -225,7 +226,7 @@ namespace SparsityPatternIterators /** * The sparsity pattern we operate on accessed. */ - const SparsityPattern *container; + const SparsityPatternBase *container; /** * Index in global sparsity pattern. This index represents the location @@ -267,7 +268,7 @@ namespace SparsityPatternIterators * SparsityPattern class for more information. * * @note This class operates directly on the internal data structures of the - * SparsityPattern class. As a consequence, some operations are cheap and + * SparsityPatternBase class. As a consequence, some operations are cheap and * some are not. In particular, it is cheap to access the column index of * the sparsity pattern entry pointed to. On the other hand, it is expensive * to access the row index (this requires $O(\log(N))$ operations for a @@ -290,14 +291,14 @@ namespace SparsityPatternIterators /** * Type of the stored pointer. */ - using container_pointer_type = SparsityPattern *; + using container_pointer_type = SparsityPatternBase *; /** * Constructor. Create an iterator into the sparsity pattern @p sp for the * given global index (i.e., the index of the given element counting from * the zeroth row). */ - Iterator(const SparsityPattern *sp, const std::size_t linear_index); + Iterator(const SparsityPatternBase *sp, const std::size_t linear_index); /** * Constructor. Create an iterator into the sparsity pattern @p sp for @@ -318,6 +319,516 @@ namespace SparsityPatternIterators * It uses the compressed row storage * (CSR) format to store data, and is used as the basis for the + * derived SparsityPattern class and SparseMatrix class. + * + * The elements of a SparsityPatternBase, corresponding to the places where + * SparseMatrix objects can store nonzero entries, are stored row-by-row. + * The ordering of non-zero elements within each row (i.e. increasing + * column index order) depends on the derived classes. + * + * @author Wolfgang Bangerth, Guido Kanschat and others + */ +class SparsityPatternBase : public Subscriptor +{ +public: + /** + * Declare type for container size. + */ + using size_type = types::global_dof_index; + + /** + * Typedef an iterator class that allows to walk over all nonzero elements + * of a sparsity pattern. + */ + using const_iterator = SparsityPatternIterators::Iterator; + + /** + * Typedef an iterator class that allows to walk over all nonzero elements + * of a sparsity pattern. + * + * Since the iterator does not allow to modify the sparsity pattern, this + * type is the same as that for @p const_iterator. + */ + using iterator = SparsityPatternIterators::Iterator; + + /** + * Define a value which is used to indicate that a certain value in the + * #colnums array is unused, i.e. does not represent a certain column number + * index. + * + * Indices with this invalid value are used to insert new entries to the + * sparsity pattern using the add() member function, and are removed when + * calling compress(). + * + * You should not assume that the variable declared here has a certain + * value. The initialization is given here only to enable the compiler to + * perform some optimizations, but the actual value of the variable may + * change over time. + */ + static const size_type invalid_entry = numbers::invalid_size_type; + + /** + * @name Construction and setup Constructors, destructor; functions + * initializing, copying and filling an object. + */ + // @{ + /** + * Initialize the matrix empty, that is with no memory allocated. This is + * useful if you want such objects as member variables in other classes. You + * can make the structure usable by calling the reinit() function. + */ + SparsityPatternBase(); + + /** + * Destructor. + */ + ~SparsityPatternBase() override = default; + + /** + * Reallocate memory and set up data structures for a new matrix with @p m + * rows and @p n columns, with at most @p max_per_row + * nonzero entries per row. + * + * This function simply maps its operations to the other reinit() + * function. + */ + void + reinit(const size_type m, const size_type n, const unsigned int max_per_row); + + /** + * Reallocate memory for a matrix of size @p m times @p n. The number of + * entries for each row is taken from the array @p row_lengths which + * has to give this number of each row $i=1\ldots m$. + * + * If m*n==0 all memory is freed, resulting in a total + * reinitialization of the object. If it is nonzero, new memory is only + * allocated if the new size extends the old one. This is done to save time + * and to avoid fragmentation of the heap. + */ + void + reinit(const size_type m, + const size_type n, + const std::vector &row_lengths); + + /** + * Same as above, but with an ArrayView argument instead. + * + * The derived classes are responsible for implementation of this function. + */ + virtual void + reinit(const size_type m, + const size_type n, + const ArrayView &row_lengths) = 0; + + /** + * Make the sparsity pattern symmetric by adding the sparsity pattern of the + * transpose object. + * + * This function throws an exception if the sparsity pattern does not + * represent a quadratic matrix. + */ + void + symmetrize(); + + /** + * Add a nonzero entry to the matrix. This function may only be called for + * non-compressed sparsity patterns. + * + * If the entry already exists, nothing bad happens. + */ + void + add(const size_type i, const size_type j); + + // @} + + /** + * @name Iterators + */ + // @{ + + /** + * Iterator starting at the first entry of the matrix. The resulting + * iterator can be used to walk over all nonzero entries of the sparsity + * pattern. + * + * The order in which elements are accessed depends on the storage scheme + * implemented by derived classes. + */ + iterator + begin() const; + + /** + * Final iterator. + */ + iterator + end() const; + + /** + * Iterator starting at the first entry of row r. + * + * Note that if the given row is empty, i.e. does not contain any nonzero + * entries, then the iterator returned by this function equals + * end(r). Note also that the iterator may not be dereferenceable in + * that case. + * + * The order in which elements are accessed depends on the storage scheme + * implemented by derived classes. + */ + iterator + begin(const size_type r) const; + + /** + * Final iterator of row r. It points to the first element past the + * end of line @p r, or past the end of the entire sparsity pattern. + * + * Note that the end iterator is not necessarily dereferenceable. This is in + * particular the case if it is the end iterator for the last row of a + * matrix. + */ + iterator + end(const size_type r) const; + + + // @} + + /** + * @name Querying information + */ + // @{ + + /** + * Test for equality of two SparsityPatterns. + */ + bool + operator==(const SparsityPatternBase &) const; + + /** + * Return whether the object is empty. It is empty if no memory is + * allocated, which is the same as that both dimensions are zero. + */ + bool + empty() const; + + /** + * Check if a value at a certain position may be non-zero. + */ + bool + exists(const size_type i, const size_type j) const; + + /** + * Return the maximum number of entries per row. Before compression, this + * equals the number given to the constructor, while after compression, it + * equals the maximum number of entries actually allocated by the user. + */ + size_type + max_entries_per_row() const; + + /** + * Compute the bandwidth of the matrix represented by this structure. The + * bandwidth is the maximum of $|i-j|$ for which the index pair $(i,j)$ + * represents a nonzero entry of the matrix. Consequently, the maximum + * bandwidth a $n\times m$ matrix can have is $\max\{n-1,m-1\}$, a diagonal + * matrix has bandwidth 0, and there are at most $2*q+1$ entries per row if + * the bandwidth is $q$. The returned quantity is sometimes called "half + * bandwidth" in the literature. + */ + size_type + bandwidth() const; + + /** + * Return the number of nonzero elements of this matrix. Actually, it + * returns the number of entries in the sparsity pattern; if any of the + * entries should happen to be zero, it is counted anyway. + * + * This function may only be called if the matrix struct is compressed. It + * does not make too much sense otherwise anyway. + */ + std::size_t + n_nonzero_elements() const; + + /** + * Return whether the structure is compressed or not. + */ + bool + is_compressed() const; + + /** + * Return number of rows of this matrix, which equals the dimension of the + * image space. + */ + size_type + n_rows() const; + + /** + * Return number of columns of this matrix, which equals the dimension of + * the range space. + */ + size_type + n_cols() const; + + /** + * Number of entries in a specific row. + */ + unsigned int + row_length(const size_type row) const; + + /** + * Determine an estimate for the memory consumption (in bytes) of this + * object. See MemoryConsumption. + */ + std::size_t + memory_consumption() const; + + // @} + + /** + * @name Accessing entries + */ + // @{ + + /** + * Access to column number field. Return the column number of the + * indexth entry in row. Note that if diagonal elements + * are optimized, the first element in each row is the diagonal element, + * i.e. column_number(row,0)==row. + * + * If the sparsity pattern is already compressed, then (except for the + * diagonal element), the entries are sorted by columns, i.e. + * column_number(row,i) < column_number(row,i+1). + */ + size_type + column_number(const size_type row, const unsigned int index) const; + + /** + * The index of a global matrix entry in its row. + * + * This function is analogous to operator(), but it computes the index not + * with respect to the total field, but only with respect to the row + * j. + */ + size_type + row_position(const size_type i, const size_type j) const; + + /** + * This is the inverse operation to operator()(): given a global index, find + * out row and column of the matrix entry to which it belongs. The returned + * value is the pair composed of row and column index. + * + * This function may only be called if the sparsity pattern is closed. The + * global index must then be between zero and n_nonzero_elements(). + * + * If N is the number of rows of this matrix, then the complexity + * of this function is log(N). + */ + std::pair + matrix_position(const std::size_t global_index) const; + + // @} + + /** + * @name Input/Output + */ + // @{ + + /** + * Print the sparsity of the matrix. The output consists of one line per row + * of the format [i,j1,j2,j3,...]. i is the row number and + * jn are the allocated columns in this row. + */ + void + print(std::ostream &out) const; + + /** + * Print the sparsity of the matrix in a format that gnuplot + * understands and which can be used to plot the sparsity pattern in a + * graphical way. The format consists of pairs i j of nonzero + * elements, each representing one entry of this matrix, one per line of the + * output file. Indices are counted from zero on, as usual. Since sparsity + * patterns are printed in the same way as matrices are displayed, we print + * the negative of the column index, which means that the (0,0) + * element is in the top left rather than in the bottom left corner. + * + * Print the sparsity pattern in gnuplot by setting the data style to dots + * or points and use the plot command. + */ + void + print_gnuplot(std::ostream &out) const; + + /** + * Prints the sparsity of the matrix in a .svg file which can be opened in a + * web browser. The .svg file contains squares which correspond to the + * entries in the matrix. An entry in the matrix which contains a non-zero + * value corresponds with a red square while a zero-valued entry in the + * matrix correspond with a white square. + */ + void + print_svg(std::ostream &out) const; + + /** + * Write the data of this object to a stream for the purpose of + * serialization + */ + template + void + save(Archive &ar, const unsigned int version) const; + + /** + * Read the data of this object from a stream for the purpose of + * serialization + */ + template + void + load(Archive &ar, const unsigned int version); + + BOOST_SERIALIZATION_SPLIT_MEMBER() + + // @} + + /** + * @addtogroup Exceptions + * @{ + */ + + /** + * The operation is only allowed after the SparsityPattern has been set up + * and compress() was called. + */ + DeclExceptionMsg( + ExcNotCompressed, + "The operation you attempted is only allowed after the SparsityPattern " + "has been set up and compress() was called."); + + /** + * You tried to add an element to a row, but there was no space left. + */ + DeclException2(ExcNotEnoughSpace, + int, + int, + << "Upon entering a new entry to row " << arg1 + << ": there was no free entry any more. " << std::endl + << "(Maximum number of entries for this row: " << arg2 + << "; maybe the matrix is already compressed?)"); + + /** + * This operation changes the structure of the SparsityPattern and is not + * possible after compress() has been called. + */ + DeclExceptionMsg( + ExcMatrixIsCompressed, + "The operation you attempted changes the structure of the SparsityPattern " + "and is not possible after compress() has been called."); + + // @} + + +protected: + /** + * Maximum number of rows that can be stored in the #rowstart array. Since + * reallocation of that array only happens if the present one is too small, + * but never when the size of this matrix structure shrinks, #max_dim might + * be larger than #rows and in this case #rowstart has more elements than + * are used. + */ + size_type max_dim; + + /** + * Number of rows that this sparsity structure shall represent. + */ + size_type rows; + + /** + * Number of columns that this sparsity structure shall represent. + */ + size_type cols; + + /** + * Size of the actually allocated array #colnums. Here, the same applies as + * for the #rowstart array, i.e. it may be larger than the actually used + * part of the array. + */ + std::size_t max_vec_len; + + /** + * Maximum number of elements per row. This is set to the value given to the + * reinit() function (or to the constructor), or to the maximum row length + * computed from the vectors in case the more flexible constructors or + * reinit versions are called. Its value is more or less meaningless after + * compress() has been called. + */ + unsigned int max_row_length; + + /** + * Array which hold for each row which is the first element in #colnums + * belonging to that row. Note that the size of the array is one larger than + * the number of rows, because the last element is used for + * row=#rows, i.e. the row past the last used one. The value of + * #rowstart[#rows]} equals the index of the element past the end in + * #colnums; this way, we are able to write loops like for + * (i=rowstart[k]; i also for the last row. + * + * Note that the actual size of the allocated memory may be larger than the + * region that is used. The actual number of elements that was allocated is + * stored in #max_dim. + */ + std::unique_ptr rowstart; + + /** + * Array of column numbers. In this array, we store for each non-zero + * element its column number. The column numbers for the elements in row + * r are stored within the index range + * #rowstart[r]...#rowstart[r+1]. Therefore to find out + * whether a given element (r,c) exists, we have to check whether the + * column number c exists in the above-mentioned range within this + * array. If it exists, say at position p within this array, the + * value of the respective element in the sparse matrix will also be at + * position p of the values array of that class. + * + * At the beginning, all elements of this array are set to @p -1 indicating + * invalid (unused) column numbers (diagonal elements are preset if + * optimized storage is requested, though). Now, if nonzero elements are + * added, one column number in the row's respective range after the other is + * set to the column number of the added element. When compress is called, + * unused elements (indicated by column numbers @p -1) are eliminated by + * copying the column number of subsequent rows and the column numbers + * within each row (with possible exception of the diagonal element) are + * sorted, such that finding whether an element exists and determining its + * position can be done by a binary search. + */ + std::unique_ptr colnums; + + /** + * Store whether the compress() function was called for this object. + */ + bool compressed; + + /** + * Make all sparse matrices friends of this class. + */ + template + friend class SparseMatrix; + template + friend class SparseLUDecomposition; + template + friend class SparseILU; + template + friend class ChunkSparseMatrix; + + friend class ChunkSparsityPattern; + friend class DynamicSparsityPattern; + + /** + * Also give access to internal details to the iterator/accessor classes. + */ + friend class SparsityPatternIterators::Iterator; + friend class SparsityPatternIterators::Accessor; + friend class ChunkSparsityPatternIterators::Accessor; +}; + +/** + * This class stores a sparsity pattern in + * the compressed row storage + * (CSR) format to store data, and is used as the basis for the * SparseMatrix class. * * The elements of a SparsityPattern, corresponding to the places where @@ -343,19 +854,19 @@ namespace SparsityPatternIterators * * @author Wolfgang Bangerth, Guido Kanschat and others */ -class SparsityPattern : public Subscriptor +class SparsityPattern : public SparsityPatternBase { public: /** * Declare type for container size. */ - using size_type = types::global_dof_index; + using size_type = SparsityPatternBase::size_type; /** * Typedef an iterator class that allows to walk over all nonzero elements * of a sparsity pattern. */ - using const_iterator = SparsityPatternIterators::Iterator; + using const_iterator = SparsityPatternBase::const_iterator; /** * Typedef an iterator class that allows to walk over all nonzero elements @@ -364,8 +875,14 @@ class SparsityPattern : public Subscriptor * Since the iterator does not allow to modify the sparsity pattern, this * type is the same as that for @p const_iterator. */ - using iterator = SparsityPatternIterators::Iterator; + using iterator = SparsityPatternBase::iterator; + /** + * Since this class has to implement only one reinit() function, we need to + * bring all base reinit() functions into the scope so that the compiler can + * find them. + */ + using SparsityPatternBase::reinit; /** * Define a value which is used to indicate that a certain value in the @@ -381,7 +898,7 @@ class SparsityPattern : public Subscriptor * perform some optimizations, but the actual value of the variable may * change over time. */ - static const size_type invalid_entry = numbers::invalid_size_type; + static const size_type invalid_entry = SparsityPatternBase::invalid_entry; /** * @name Construction and setup Constructors, destructor; functions @@ -495,45 +1012,15 @@ class SparsityPattern : public Subscriptor SparsityPattern & operator=(const SparsityPattern &); - /** - * Reallocate memory and set up data structures for a new matrix with @p m - * rows and @p n columns, with at most @p max_per_row - * nonzero entries per row. - * - * This function simply maps its operations to the other reinit() - * function. - */ - void - reinit(const size_type m, const size_type n, const unsigned int max_per_row); - - /** * Reallocate memory for a matrix of size @p m times @p n. The number of - * entries for each row is taken from the array @p row_lengths which - * has to give this number of each row $i=1\ldots m$. - * - * If m*n==0 all memory is freed, resulting in a total - * reinitialization of the object. If it is nonzero, new memory is only - * allocated if the new size extends the old one. This is done to save time - * and to avoid fragmentation of the heap. - * - * If the number of rows equals the number of columns and the last parameter - * is true, diagonal elements are stored first in each row to allow - * optimized access in relaxation methods of SparseMatrix. - */ - void - reinit(const size_type m, - const size_type n, - const std::vector &row_lengths); - - - /** - * Same as above, but with an ArrayView argument instead. + * entries for each row is taken from the ArrayView @p row_lengths which + * has to give this number of each row $i=0\ldots m-1$. */ - void + virtual void reinit(const size_type m, const size_type n, - const ArrayView &row_lengths); + const ArrayView &row_lengths) override; /** * This function compresses the sparsity structure that this object @@ -649,174 +1136,41 @@ class SparsityPattern : public Subscriptor copy_from(const SparsityPattern &sp); /** - * Take a full matrix and use its nonzero entries to generate a sparse - * matrix entry pattern for this object. - * - * Previous content of this object is lost, and the sparsity pattern is in - * compressed mode afterwards. - */ - template - void - copy_from(const FullMatrix &matrix); - - /** - * Make the sparsity pattern symmetric by adding the sparsity pattern of the - * transpose object. - * - * This function throws an exception if the sparsity pattern does not - * represent a quadratic matrix. - */ - void - symmetrize(); - - /** - * Add a nonzero entry to the matrix. This function may only be called for - * non-compressed sparsity patterns. - * - * If the entry already exists, nothing bad happens. - */ - void - add(const size_type i, const size_type j); - - /** - * Add several nonzero entries to the specified matrix row. This function - * may only be called for non-compressed sparsity patterns. - * - * If some of the entries already exist, nothing bad happens. - */ - template - void - add_entries(const size_type row, - ForwardIterator begin, - ForwardIterator end, - const bool indices_are_sorted = false); - - // @} - - - - /** - * @name Iterators - */ - // @{ - - /** - * Iterator starting at the first entry of the matrix. The resulting - * iterator can be used to walk over all nonzero entries of the sparsity - * pattern. - * - * Note the discussion in the general documentation of this class about the - * order in which elements are accessed. - */ - iterator - begin() const; - - /** - * Final iterator. - */ - iterator - end() const; - - /** - * Iterator starting at the first entry of row r. - * - * Note that if the given row is empty, i.e. does not contain any nonzero - * entries, then the iterator returned by this function equals - * end(r). Note also that the iterator may not be dereferenceable in - * that case. - * - * Note also the discussion in the general documentation of this class about - * the order in which elements are accessed. - */ - iterator - begin(const size_type r) const; - - /** - * Final iterator of row r. It points to the first element past the - * end of line @p r, or past the end of the entire sparsity pattern. - * - * Note that the end iterator is not necessarily dereferenceable. This is in - * particular the case if it is the end iterator for the last row of a - * matrix. - */ - iterator - end(const size_type r) const; - - - // @} - /** - * @name Querying information - */ - // @{ - /** - * Test for equality of two SparsityPatterns. - */ - bool - operator==(const SparsityPattern &) const; - - /** - * Return whether the object is empty. It is empty if no memory is - * allocated, which is the same as that both dimensions are zero. - */ - bool - empty() const; - - /** - * Return the maximum number of entries per row. Before compression, this - * equals the number given to the constructor, while after compression, it - * equals the maximum number of entries actually allocated by the user. - */ - size_type - max_entries_per_row() const; - - /** - * Compute the bandwidth of the matrix represented by this structure. The - * bandwidth is the maximum of $|i-j|$ for which the index pair $(i,j)$ - * represents a nonzero entry of the matrix. Consequently, the maximum - * bandwidth a $n\times m$ matrix can have is $\max\{n-1,m-1\}$, a diagonal - * matrix has bandwidth 0, and there are at most $2*q+1$ entries per row if - * the bandwidth is $q$. The returned quantity is sometimes called "half - * bandwidth" in the literature. - */ - size_type - bandwidth() const; - - /** - * Return the number of nonzero elements of this matrix. Actually, it - * returns the number of entries in the sparsity pattern; if any of the - * entries should happen to be zero, it is counted anyway. - * - * This function may only be called if the matrix struct is compressed. It - * does not make too much sense otherwise anyway. - */ - std::size_t - n_nonzero_elements() const; - - /** - * Return whether the structure is compressed or not. + * Take a full matrix and use its nonzero entries to generate a sparse + * matrix entry pattern for this object. + * + * Previous content of this object is lost, and the sparsity pattern is in + * compressed mode afterwards. */ - bool - is_compressed() const; + template + void + copy_from(const FullMatrix &matrix); /** - * Return number of rows of this matrix, which equals the dimension of the - * image space. + * Add several nonzero entries to the specified matrix row. This function + * may only be called for non-compressed sparsity patterns. + * + * If some of the entries already exist, nothing bad happens. */ - size_type - n_rows() const; + template + void + add_entries(const size_type row, + ForwardIterator begin, + ForwardIterator end, + const bool indices_are_sorted = false); + + // @} + /** - * Return number of columns of this matrix, which equals the dimension of - * the range space. + * @name Querying information */ - size_type - n_cols() const; - + // @{ /** - * Number of entries in a specific row. + * Test for equality of two SparsityPatterns. */ - unsigned int - row_length(const size_type row) const; + bool + operator==(const SparsityPattern &) const; /** * Return whether this object stores only those entries that have been added @@ -870,55 +1224,12 @@ class SparsityPattern : public Subscriptor size_type operator()(const size_type i, const size_type j) const; - /** - * This is the inverse operation to operator()(): given a global index, find - * out row and column of the matrix entry to which it belongs. The returned - * value is the pair composed of row and column index. - * - * This function may only be called if the sparsity pattern is closed. The - * global index must then be between zero and n_nonzero_elements(). - * - * If N is the number of rows of this matrix, then the complexity - * of this function is log(N). - */ - std::pair - matrix_position(const std::size_t global_index) const; - - /** - * Check if a value at a certain position may be non-zero. - */ - bool - exists(const size_type i, const size_type j) const; - - /** - * The index of a global matrix entry in its row. - * - * This function is analogous to operator(), but it computes the index not - * with respect to the total field, but only with respect to the row - * j. - */ - size_type - row_position(const size_type i, const size_type j) const; - - /** - * Access to column number field. Return the column number of the - * indexth entry in row. Note that if diagonal elements - * are optimized, the first element in each row is the diagonal element, - * i.e. column_number(row,0)==row. - * - * If the sparsity pattern is already compressed, then (except for the - * diagonal element), the entries are sorted by columns, i.e. - * column_number(row,i) < column_number(row,i+1). - */ - size_type - column_number(const size_type row, const unsigned int index) const; - - // @} /** * @name Input/Output */ // @{ + /** * Write the data of this object en bloc to a file. This is done in a binary * mode, so the output is neither readable by humans nor (probably) by other @@ -948,41 +1259,6 @@ class SparsityPattern : public Subscriptor void block_read(std::istream &in); - /** - * Print the sparsity of the matrix. The output consists of one line per row - * of the format [i,j1,j2,j3,...]. i is the row number and - * jn are the allocated columns in this row. - */ - void - print(std::ostream &out) const; - - /** - * Print the sparsity of the matrix in a format that gnuplot - * understands and which can be used to plot the sparsity pattern in a - * graphical way. The format consists of pairs i j of nonzero - * elements, each representing one entry of this matrix, one per line of the - * output file. Indices are counted from zero on, as usual. Since sparsity - * patterns are printed in the same way as matrices are displayed, we print - * the negative of the column index, which means that the (0,0) - * element is in the top left rather than in the bottom left corner. - * - * Print the sparsity pattern in gnuplot by setting the data style to dots - * or points and use the plot command. - */ - void - print_gnuplot(std::ostream &out) const; - - /** - * Prints the sparsity of the matrix in a .svg file which can be opened in a - * web browser. The .svg file contains squares which correspond to the - * entries in the matrix. An entry in the matrix which contains a non-zero - * value corresponds with a red square while a zero-valued entry in the - * matrix correspond with a white square. - */ - void - print_svg(std::ostream &out) const; - - /** * Write the data of this object to a stream for the purpose of * serialization @@ -1007,32 +1283,6 @@ class SparsityPattern : public Subscriptor * @addtogroup Exceptions * @{ */ - /** - * You tried to add an element to a row, but there was no space left. - */ - DeclException2(ExcNotEnoughSpace, - int, - int, - << "Upon entering a new entry to row " << arg1 - << ": there was no free entry any more. " << std::endl - << "(Maximum number of entries for this row: " << arg2 - << "; maybe the matrix is already compressed?)"); - /** - * The operation is only allowed after the SparsityPattern has been set up - * and compress() was called. - */ - DeclExceptionMsg( - ExcNotCompressed, - "The operation you attempted is only allowed after the SparsityPattern " - "has been set up and compress() was called."); - /** - * This operation changes the structure of the SparsityPattern and is not - * possible after compress() has been called. - */ - DeclExceptionMsg( - ExcMatrixIsCompressed, - "The operation you attempted changes the structure of the SparsityPattern " - "and is not possible after compress() has been called."); /** * Exception */ @@ -1050,85 +1300,6 @@ class SparsityPattern : public Subscriptor << ", but must be greater than zero."); //@} private: - /** - * Maximum number of rows that can be stored in the #rowstart array. Since - * reallocation of that array only happens if the present one is too small, - * but never when the size of this matrix structure shrinks, #max_dim might - * be larger than #rows and in this case #rowstart has more elements than - * are used. - */ - size_type max_dim; - - /** - * Number of rows that this sparsity structure shall represent. - */ - size_type rows; - - /** - * Number of columns that this sparsity structure shall represent. - */ - size_type cols; - - /** - * Size of the actually allocated array #colnums. Here, the same applies as - * for the #rowstart array, i.e. it may be larger than the actually used - * part of the array. - */ - std::size_t max_vec_len; - - /** - * Maximum number of elements per row. This is set to the value given to the - * reinit() function (or to the constructor), or to the maximum row length - * computed from the vectors in case the more flexible constructors or - * reinit versions are called. Its value is more or less meaningless after - * compress() has been called. - */ - unsigned int max_row_length; - - /** - * Array which hold for each row which is the first element in #colnums - * belonging to that row. Note that the size of the array is one larger than - * the number of rows, because the last element is used for - * row=#rows, i.e. the row past the last used one. The value of - * #rowstart[#rows]} equals the index of the element past the end in - * #colnums; this way, we are able to write loops like for - * (i=rowstart[k]; i also for the last row. - * - * Note that the actual size of the allocated memory may be larger than the - * region that is used. The actual number of elements that was allocated is - * stored in #max_dim. - */ - std::unique_ptr rowstart; - - /** - * Array of column numbers. In this array, we store for each non-zero - * element its column number. The column numbers for the elements in row - * r are stored within the index range - * #rowstart[r]...#rowstart[r+1]. Therefore to find out - * whether a given element (r,c) exists, we have to check whether the - * column number c exists in the above-mentioned range within this - * array. If it exists, say at position p within this array, the - * value of the respective element in the sparse matrix will also be at - * position p of the values array of that class. - * - * At the beginning, all elements of this array are set to @p -1 indicating - * invalid (unused) column numbers (diagonal elements are preset if - * optimized storage is requested, though). Now, if nonzero elements are - * added, one column number in the row's respective range after the other is - * set to the column number of the added element. When compress is called, - * unused elements (indicated by column numbers @p -1) are eliminated by - * copying the column number of subsequent rows and the column numbers - * within each row (with possible exception of the diagonal element) are - * sorted, such that finding whether an element exists and determining its - * position can be done by a binary search. - */ - std::unique_ptr colnums; - - /** - * Store whether the compress() function was called for this object. - */ - bool compressed; - /** * Is special treatment of diagonals enabled? */ @@ -1166,15 +1337,15 @@ class SparsityPattern : public Subscriptor namespace SparsityPatternIterators { - inline Accessor::Accessor(const SparsityPattern *sparsity_pattern, - const std::size_t i) + inline Accessor::Accessor(const SparsityPatternBase *sparsity_pattern, + const std::size_t i) : container(sparsity_pattern) , linear_index(i) {} - inline Accessor::Accessor(const SparsityPattern *sparsity_pattern) + inline Accessor::Accessor(const SparsityPatternBase *sparsity_pattern) : container(sparsity_pattern) , linear_index(container->rowstart[container->rows]) {} @@ -1274,8 +1445,8 @@ namespace SparsityPatternIterators } - inline Iterator::Iterator(const SparsityPattern *sp, - const std::size_t linear_index) + inline Iterator::Iterator(const SparsityPatternBase *sp, + const std::size_t linear_index) : LinearIndexIterator(Accessor(sp, linear_index)) {} @@ -1289,8 +1460,8 @@ namespace SparsityPatternIterators -inline SparsityPattern::iterator -SparsityPattern::begin() const +inline SparsityPatternBase::iterator +SparsityPatternBase::begin() const { if (n_rows() > 0) return {this, rowstart[0]}; @@ -1300,8 +1471,8 @@ SparsityPattern::begin() const -inline SparsityPattern::iterator -SparsityPattern::end() const +inline SparsityPatternBase::iterator +SparsityPatternBase::end() const { if (n_rows() > 0) return {this, rowstart[rows]}; @@ -1311,8 +1482,8 @@ SparsityPattern::end() const -inline SparsityPattern::iterator -SparsityPattern::begin(const size_type r) const +inline SparsityPatternBase::iterator +SparsityPatternBase::begin(const size_type r) const { Assert(r < n_rows(), ExcIndexRangeType(r, 0, n_rows())); @@ -1321,8 +1492,8 @@ SparsityPattern::begin(const size_type r) const -inline SparsityPattern::iterator -SparsityPattern::end(const size_type r) const +inline SparsityPatternBase::iterator +SparsityPatternBase::end(const size_type r) const { Assert(r < n_rows(), ExcIndexRangeType(r, 0, n_rows())); @@ -1331,16 +1502,16 @@ SparsityPattern::end(const size_type r) const -inline SparsityPattern::size_type -SparsityPattern::n_rows() const +inline SparsityPatternBase::size_type +SparsityPatternBase::n_rows() const { return rows; } -inline SparsityPattern::size_type -SparsityPattern::n_cols() const +inline SparsityPatternBase::size_type +SparsityPatternBase::n_cols() const { return cols; } @@ -1348,7 +1519,7 @@ SparsityPattern::n_cols() const inline bool -SparsityPattern::is_compressed() const +SparsityPatternBase::is_compressed() const { return compressed; } @@ -1364,7 +1535,7 @@ SparsityPattern::stores_only_added_elements() const inline unsigned int -SparsityPattern::row_length(const size_type row) const +SparsityPatternBase::row_length(const size_type row) const { Assert(row < rows, ExcIndexRangeType(row, 0, rows)); return rowstart[row + 1] - rowstart[row]; @@ -1373,8 +1544,8 @@ SparsityPattern::row_length(const size_type row) const inline SparsityPattern::size_type -SparsityPattern::column_number(const size_type row, - const unsigned int index) const +SparsityPatternBase::column_number(const size_type row, + const unsigned int index) const { Assert(row < rows, ExcIndexRangeType(row, 0, rows)); Assert(index < row_length(row), ExcIndexRange(index, 0, row_length(row))); @@ -1385,7 +1556,7 @@ SparsityPattern::column_number(const size_type row, inline std::size_t -SparsityPattern::n_nonzero_elements() const +SparsityPatternBase::n_nonzero_elements() const { Assert(compressed, ExcNotCompressed()); @@ -1400,13 +1571,12 @@ SparsityPattern::n_nonzero_elements() const template inline void -SparsityPattern::save(Archive &ar, const unsigned int) const +SparsityPatternBase::save(Archive &ar, const unsigned int) const { // forward to serialization function in the base class. - ar &static_cast(*this); + ar &boost::serialization::base_object(*this); - ar &max_dim &rows &cols &max_vec_len &max_row_length &compressed - &store_diagonal_first_in_row; + ar &max_dim &rows &cols &max_vec_len &max_row_length &compressed; ar &boost::serialization::make_array(rowstart.get(), max_dim + 1); ar &boost::serialization::make_array(colnums.get(), max_vec_len); @@ -1416,13 +1586,12 @@ SparsityPattern::save(Archive &ar, const unsigned int) const template inline void -SparsityPattern::load(Archive &ar, const unsigned int) +SparsityPatternBase::load(Archive &ar, const unsigned int) { // forward to serialization function in the base class. - ar &static_cast(*this); + ar &boost::serialization::base_object(*this); - ar &max_dim &rows &cols &max_vec_len &max_row_length &compressed - &store_diagonal_first_in_row; + ar &max_dim &rows &cols &max_vec_len &max_row_length &compressed; rowstart = std_cxx14::make_unique(max_dim + 1); colnums = std_cxx14::make_unique(max_vec_len); @@ -1433,15 +1602,36 @@ SparsityPattern::load(Archive &ar, const unsigned int) +template +inline void +SparsityPattern::save(Archive &ar, const unsigned int) const +{ + // forward to serialization function in the base class. + ar &boost::serialization::base_object(*this); + ar &store_diagonal_first_in_row; +} + + + +template +inline void +SparsityPattern::load(Archive &ar, const unsigned int) +{ + // forward to serialization function in the base class. + ar &boost::serialization::base_object(*this); + ar &store_diagonal_first_in_row; +} + + + inline bool -SparsityPattern::operator==(const SparsityPattern &sp2) const +SparsityPatternBase::operator==(const SparsityPatternBase &sp2) const { // it isn't quite necessary to compare *all* member variables. by only // comparing the essential ones, we can say that two sparsity patterns are // equal even if one is compressed and the other is not (in which case some // of the member variables are not yet set correctly) - if (rows != sp2.rows || cols != sp2.cols || compressed != sp2.compressed || - store_diagonal_first_in_row != sp2.store_diagonal_first_in_row) + if (rows != sp2.rows || cols != sp2.cols || compressed != sp2.compressed) return false; for (size_type i = 0; i < rows + 1; ++i) @@ -1457,6 +1647,15 @@ SparsityPattern::operator==(const SparsityPattern &sp2) const +inline bool +SparsityPattern::operator==(const SparsityPattern &sp2) const +{ + return (static_cast(*this) == sp2) && + (store_diagonal_first_in_row == sp2.store_diagonal_first_in_row); +} + + + namespace internal { namespace SparsityPatternTools diff --git a/source/lac/sparsity_pattern.cc b/source/lac/sparsity_pattern.cc index 2eb565a4542d..ee331f9ead27 100644 --- a/source/lac/sparsity_pattern.cc +++ b/source/lac/sparsity_pattern.cc @@ -36,15 +36,21 @@ DEAL_II_NAMESPACE_OPEN __declspec(selectany) // Weak extern binding due to multiple link error #endif const SparsityPattern::size_type SparsityPattern::invalid_entry; +const SparsityPatternBase::size_type SparsityPatternBase::invalid_entry; - -SparsityPattern::SparsityPattern() +SparsityPatternBase::SparsityPatternBase() : max_dim(0) , max_vec_len(0) , rowstart(nullptr) , colnums(nullptr) , compressed(false) +{} + + + +SparsityPattern::SparsityPattern() + : SparsityPatternBase() , store_diagonal_first_in_row(false) { reinit(0, 0, 0); @@ -53,12 +59,7 @@ SparsityPattern::SparsityPattern() SparsityPattern::SparsityPattern(const SparsityPattern &s) - : Subscriptor() - , max_dim(0) - , max_vec_len(0) - , rowstart(nullptr) - , colnums(nullptr) - , compressed(false) + : SparsityPatternBase() , store_diagonal_first_in_row(false) { (void)s; @@ -76,11 +77,7 @@ SparsityPattern::SparsityPattern(const SparsityPattern &s) SparsityPattern::SparsityPattern(const size_type m, const size_type n, const unsigned int max_per_row) - : max_dim(0) - , max_vec_len(0) - , rowstart(nullptr) - , colnums(nullptr) - , compressed(false) + : SparsityPatternBase() , store_diagonal_first_in_row(m == n) { reinit(m, n, max_per_row); @@ -91,10 +88,7 @@ SparsityPattern::SparsityPattern(const size_type m, SparsityPattern::SparsityPattern(const size_type m, const size_type n, const std::vector &row_lengths) - : max_dim(0) - , max_vec_len(0) - , rowstart(nullptr) - , colnums(nullptr) + : SparsityPatternBase() , store_diagonal_first_in_row(m == n) { reinit(m, n, row_lengths); @@ -104,10 +98,7 @@ SparsityPattern::SparsityPattern(const size_type m, SparsityPattern::SparsityPattern(const size_type m, const unsigned int max_per_row) - : max_dim(0) - , max_vec_len(0) - , rowstart(nullptr) - , colnums(nullptr) + : SparsityPatternBase() { reinit(m, m, max_per_row); } @@ -116,10 +107,7 @@ SparsityPattern::SparsityPattern(const size_type m, SparsityPattern::SparsityPattern(const size_type m, const std::vector &row_lengths) - : max_dim(0) - , max_vec_len(0) - , rowstart(nullptr) - , colnums(nullptr) + : SparsityPatternBase() { reinit(m, m, row_lengths); } @@ -129,10 +117,7 @@ SparsityPattern::SparsityPattern(const size_type m, SparsityPattern::SparsityPattern(const SparsityPattern &original, const unsigned int max_per_row, const size_type extra_off_diagonals) - : max_dim(0) - , max_vec_len(0) - , rowstart(nullptr) - , colnums(nullptr) + : SparsityPattern() { Assert(original.rows == original.cols, ExcNotQuadratic()); Assert(original.is_compressed(), ExcNotCompressed()); @@ -228,9 +213,9 @@ SparsityPattern::operator=(const SparsityPattern &s) void -SparsityPattern::reinit(const size_type m, - const size_type n, - const unsigned int max_per_row) +SparsityPatternBase::reinit(const size_type m, + const size_type n, + const unsigned int max_per_row) { // simply map this function to the other @p{reinit} function const std::vector row_lengths(m, max_per_row); @@ -601,9 +586,9 @@ SparsityPattern::copy_from(const FullMatrix &matrix) void -SparsityPattern::reinit(const size_type m, - const size_type n, - const std::vector &row_lengths) +SparsityPatternBase::reinit(const size_type m, + const size_type n, + const std::vector &row_lengths) { reinit(m, n, make_slice(row_lengths)); } @@ -611,7 +596,7 @@ SparsityPattern::reinit(const size_type m, bool -SparsityPattern::empty() const +SparsityPatternBase::empty() const { // let's try to be on the safe side of life by using multiple possibilities // in the check for emptiness... (sorry for this kludge -- emptying matrices @@ -633,8 +618,8 @@ SparsityPattern::empty() const -SparsityPattern::size_type -SparsityPattern::max_entries_per_row() const +SparsityPatternBase::size_type +SparsityPatternBase::max_entries_per_row() const { // if compress() has not yet been called, we can get the maximum number of // elements per row using the stored value @@ -691,7 +676,7 @@ SparsityPattern::operator()(const size_type i, const size_type j) const void -SparsityPattern::add(const size_type i, const size_type j) +SparsityPatternBase::add(const size_type i, const size_type j) { Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject()); Assert(i < rows, ExcIndexRange(i, 0, rows)); @@ -768,7 +753,7 @@ SparsityPattern::add_entries(const size_type row, bool -SparsityPattern::exists(const size_type i, const size_type j) const +SparsityPatternBase::exists(const size_type i, const size_type j) const { Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject()); Assert(i < rows, ExcIndexRange(i, 0, rows)); @@ -785,8 +770,8 @@ SparsityPattern::exists(const size_type i, const size_type j) const -SparsityPattern::size_type -SparsityPattern::row_position(const size_type i, const size_type j) const +SparsityPatternBase::size_type +SparsityPatternBase::row_position(const size_type i, const size_type j) const { Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject()); Assert(i < rows, ExcIndexRange(i, 0, rows)); @@ -803,8 +788,8 @@ SparsityPattern::row_position(const size_type i, const size_type j) const -std::pair -SparsityPattern::matrix_position(const std::size_t global_index) const +std::pair +SparsityPatternBase::matrix_position(const std::size_t global_index) const { Assert(compressed == true, ExcNotCompressed()); Assert(global_index < n_nonzero_elements(), @@ -829,7 +814,7 @@ SparsityPattern::matrix_position(const std::size_t global_index) const void -SparsityPattern::symmetrize() +SparsityPatternBase::symmetrize() { Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject()); Assert(compressed == false, ExcMatrixIsCompressed()); @@ -863,7 +848,7 @@ SparsityPattern::symmetrize() void -SparsityPattern::print(std::ostream &out) const +SparsityPatternBase::print(std::ostream &out) const { Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject()); @@ -884,7 +869,7 @@ SparsityPattern::print(std::ostream &out) const void -SparsityPattern::print_gnuplot(std::ostream &out) const +SparsityPatternBase::print_gnuplot(std::ostream &out) const { Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject()); @@ -902,7 +887,7 @@ SparsityPattern::print_gnuplot(std::ostream &out) const } void -SparsityPattern::print_svg(std::ostream &out) const +SparsityPatternBase::print_svg(std::ostream &out) const { unsigned int m = this->n_rows(); unsigned int n = this->n_cols(); @@ -935,8 +920,8 @@ SparsityPattern::print_svg(std::ostream &out) const -SparsityPattern::size_type -SparsityPattern::bandwidth() const +SparsityPatternBase::size_type +SparsityPatternBase::bandwidth() const { Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject()); size_type b = 0; @@ -1019,13 +1004,20 @@ SparsityPattern::block_read(std::istream &in) std::size_t -SparsityPattern::memory_consumption() const +SparsityPatternBase::memory_consumption() const { return (max_dim * sizeof(size_type) + sizeof(*this) + max_vec_len * sizeof(size_type)); } +std::size_t +SparsityPattern::memory_consumption() const +{ + return sizeof(*this) + SparsityPatternBase::memory_consumption(); +} + + // explicit instantiations template void diff --git a/tests/serialization/sparsity_pattern.output b/tests/serialization/sparsity_pattern.output index cf500822409c..abc3bde154b5 100644 --- a/tests/serialization/sparsity_pattern.output +++ b/tests/serialization/sparsity_pattern.output @@ -1,6 +1,6 @@ -DEAL::0 0 0 0 16 16 16 64 5 1 1 0 3 7 11 14 18 23 28 32 36 41 46 50 53 57 61 64 0 1 4 1 0 2 5 2 1 3 6 3 2 7 4 0 5 8 5 1 4 6 9 6 2 5 7 10 7 3 6 11 8 4 9 12 9 5 8 10 13 10 6 9 11 14 11 7 10 15 12 8 13 13 9 12 14 14 10 13 15 15 11 14 +DEAL::0 0 0 0 0 0 16 16 16 64 5 1 0 3 7 11 14 18 23 28 32 36 41 46 50 53 57 61 64 0 1 4 1 0 2 5 2 1 3 6 3 2 7 4 0 5 8 5 1 4 6 9 6 2 5 7 10 7 3 6 11 8 4 9 12 9 5 8 10 13 10 6 9 11 14 11 7 10 15 12 8 13 13 9 12 14 14 10 13 15 15 11 14 1 -DEAL::0 0 0 0 16 16 16 64 5 1 1 0 3 7 11 14 18 23 28 32 36 41 46 50 53 57 61 64 0 1 4 1 0 2 5 2 1 3 6 3 2 7 4 0 5 8 5 1 4 6 9 6 2 5 7 10 7 3 6 11 8 4 9 12 9 5 8 10 13 10 6 9 11 14 11 7 10 15 12 8 13 13 9 12 14 14 10 13 15 15 11 14 +DEAL::0 0 0 0 0 0 16 16 16 64 5 1 0 3 7 11 14 18 23 28 32 36 41 46 50 53 57 61 64 0 1 4 1 0 2 5 2 1 3 6 3 2 7 4 0 5 8 5 1 4 6 9 6 2 5 7 10 7 3 6 11 8 4 9 12 9 5 8 10 13 10 6 9 11 14 11 7 10 15 12 8 13 13 9 12 14 14 10 13 15 15 11 14 1 DEAL::OK diff --git a/tests/sparsity/sparsity_pattern_13.cc b/tests/sparsity/sparsity_pattern_13.cc new file mode 100644 index 000000000000..c1b0a8f1ff8b --- /dev/null +++ b/tests/sparsity/sparsity_pattern_13.cc @@ -0,0 +1,171 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + + +// proof of concept for DynamicSparsityPattern-like CSR object without +// special treatment of diagonals + +#include "sparsity_pattern_common.h" + +class SparsityPatternStandard : public SparsityPatternBase +{ +public: + using size_type = SparsityPatternBase::size_type; + + using SparsityPatternBase::reinit; + + SparsityPatternStandard() + : SparsityPatternBase() + { + reinit(0, 0, 0); + }; + + virtual void + reinit(const size_type m, + const size_type n, + const ArrayView &row_lengths) override + { + AssertDimension(row_lengths.size(), m); + + rows = m; + cols = n; + + // delete empty matrices + if ((m == 0) || (n == 0)) + { + rowstart.reset(); + colnums.reset(); + + max_vec_len = max_dim = rows = cols = 0; + // if dimension is zero: ignore max_per_row + max_row_length = 0; + compressed = false; + + return; + } + + // find out how many entries we need in the @p{colnums} array. if this + // number is larger than @p{max_vec_len}, then we will need to reallocate + // memory + // + // note that the number of elements per row is bounded by the number of + // columns + // + std::size_t vec_len = 0; + for (size_type i = 0; i < m; ++i) + vec_len += std::min(static_cast(row_lengths[i]), n); + + // sometimes, no entries are requested in the matrix (this most often + // happens when blocks in a block matrix are simply zero). in that case, + // allocate exactly one element, to have a valid pointer to some memory + if (vec_len == 0) + { + vec_len = 1; + max_vec_len = vec_len; + colnums = std_cxx14::make_unique(max_vec_len); + } + + max_row_length = + (row_lengths.size() == 0 ? + 0 : + std::min(static_cast( + *std::max_element(row_lengths.begin(), row_lengths.end())), + n)); + + // allocate memory for the rowstart values, if necessary. even though we + // re-set the pointers again immediately after deleting their old content, + // set them to zero in between because the allocation might fail, in which + // case we get an exception and the destructor of this object will be called + // -- where we look at the non-nullness of the (now invalid) pointer again + // and try to delete the memory a second time. + if (rows > max_dim) + { + max_dim = rows; + rowstart = std_cxx14::make_unique(max_dim + 1); + } + + // allocate memory for the column numbers if necessary + if (vec_len > max_vec_len) + { + max_vec_len = vec_len; + colnums = std_cxx14::make_unique(max_vec_len); + } + + // set the rowstart array + rowstart[0] = 0; + for (size_type i = 1; i <= rows; ++i) + rowstart[i] = rowstart[i - 1] + + std::min(static_cast(row_lengths[i - 1]), n); + Assert((rowstart[rows] == vec_len) || + ((vec_len == 1) && (rowstart[rows] == 0)), + ExcInternalError()); + + // preset the column numbers by a value indicating it is not in use + std::fill_n(colnums.get(), vec_len, invalid_entry); + + compressed = false; + }; + + void + copy_from(const DynamicSparsityPattern &dsp) + { + std::vector row_lengths(dsp.n_rows()); + for (size_type i = 0; i < dsp.n_rows(); ++i) + row_lengths[i] = dsp.row_length(i); + + reinit(dsp.n_rows(), dsp.n_cols(), row_lengths); + + if (n_rows() != 0 && n_cols() != 0) + for (size_type row = 0; row < dsp.n_rows(); ++row) + { + size_type * cols = &colnums[rowstart[row]]; + const unsigned int row_length = dsp.row_length(row); + for (unsigned int index = 0; index < row_length; ++index) + { + const size_type col = dsp.column_number(row, index); + *cols++ = col; + } + } + + compressed = true; + }; +}; + + + +int +main() +{ + std::ofstream logfile("output"); + logfile.setf(std::ios::fixed); + deallog << std::setprecision(3); + deallog.attach(logfile); + + DynamicSparsityPattern dsp(2); + dsp.add(0, 1); + dsp.add(1, 0); + + SparsityPattern sp_usual; + sp_usual.copy_from(dsp); + deallog << "SparsityPattern:" << std::endl; + sp_usual.print(deallog.get_file_stream()); + + SparsityPatternStandard sp; + sp.copy_from(dsp); + + deallog << "SparsityPatternStandard:" << std::endl; + sp.print(deallog.get_file_stream()); +} diff --git a/tests/sparsity/sparsity_pattern_13.output b/tests/sparsity/sparsity_pattern_13.output new file mode 100644 index 000000000000..0da0dd68e139 --- /dev/null +++ b/tests/sparsity/sparsity_pattern_13.output @@ -0,0 +1,7 @@ + +DEAL::SparsityPattern: +[0,0,1] +[1,1,0] +DEAL::SparsityPatternStandard: +[0,1] +[1,0] From 1519aa2d431372e63dd66a62b059244b935a5679 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Wed, 20 Mar 2019 18:22:43 -0600 Subject: [PATCH 297/507] use 64 bit tbb range --- include/deal.II/lac/la_vector.templates.h | 6 +++--- .../deal.II/lac/vector_operations_internal.h | 20 +++++++++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/include/deal.II/lac/la_vector.templates.h b/include/deal.II/lac/la_vector.templates.h index 7eaa6b3eea41..94309bde36db 100644 --- a/include/deal.II/lac/la_vector.templates.h +++ b/include/deal.II/lac/la_vector.templates.h @@ -92,7 +92,7 @@ namespace LinearAlgebra dealii::internal::VectorOperations::Vector_copy copier( in_vector.values.get(), this->values.get()); internal::VectorOperations::parallel_for(copier, - 0, + static_cast(0), this->size(), this->thread_loop_partitioner); @@ -113,7 +113,7 @@ namespace LinearAlgebra dealii::internal::VectorOperations::Vector_copy copier( in_vector.values.get(), this->values.get()); internal::VectorOperations::parallel_for(copier, - 0, + static_cast(0), this->size(), this->thread_loop_partitioner); @@ -151,7 +151,7 @@ namespace LinearAlgebra internal::VectorOperations::Vectorization_multiply_factor vector_multiply(this->values.get(), factor); internal::VectorOperations::parallel_for(vector_multiply, - 0, + static_cast(0), this->size(), this->thread_loop_partitioner); diff --git a/include/deal.II/lac/vector_operations_internal.h b/include/deal.II/lac/vector_operations_internal.h index 95ea6bc18cae..542c31499fa1 100644 --- a/include/deal.II/lac/vector_operations_internal.h +++ b/include/deal.II/lac/vector_operations_internal.h @@ -149,7 +149,7 @@ namespace internal } void - operator()(const tbb::blocked_range &range) const + operator()(const tbb::blocked_range &range) const { const size_type r_begin = start + range.begin() * chunk_size; const size_type r_end = std::min(start + range.end() * chunk_size, end); @@ -188,8 +188,12 @@ namespace internal partitioner->acquire_one_partitioner(); TBBForFunctor generic_functor(functor, start, end); - parallel::internal::parallel_for( - 0U, generic_functor.n_chunks, generic_functor, 1, tbb_partitioner); + parallel::internal::parallel_for(static_cast(0), + static_cast( + generic_functor.n_chunks), + generic_functor, + 1, + tbb_partitioner); partitioner->release_one_partitioner(tbb_partitioner); } else if (vec_size > 0) @@ -1317,7 +1321,7 @@ namespace internal * [range.begin(), range.end()). */ void - operator()(const tbb::blocked_range &range) const + operator()(const tbb::blocked_range &range) const { for (size_type i = range.begin(); i < range.end(); ++i) accumulate_recursive(op, @@ -1387,8 +1391,12 @@ namespace internal TBBReduceFunctor generic_functor(op, start, end); - parallel::internal::parallel_for( - 0U, generic_functor.n_chunks, generic_functor, 1, tbb_partitioner); + parallel::internal::parallel_for(static_cast(0), + static_cast( + generic_functor.n_chunks), + generic_functor, + 1, + tbb_partitioner); partitioner->release_one_partitioner(tbb_partitioner); result = generic_functor.do_sum(); } From 2281d7765122c2e399dcdb726189043324a9436c Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 21 Mar 2019 15:24:10 +0100 Subject: [PATCH 298/507] Improve documentation of ADHelperScalarFunction --- .../deal.II/differentiation/ad/ad_helpers.h | 59 +++++++++++++++++-- source/differentiation/ad/ad_helpers.cc | 8 +-- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index bc00902024cc..685032fd369e 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -2964,7 +2964,7 @@ namespace Differentiation * // Define the helper that we will use in the AD computations for our * // scalar energy function. Note that we expect it to return values of * // type double. - * ADHelperScalarFunction ad_helper (n_independent_variables); + * ADHelperScalarFunction ad_helper (n_independent_variables); * using ADNumberType = typename ADHelper::ad_type; * * // Compute the fields that provide the independent values. @@ -3006,7 +3006,7 @@ namespace Differentiation * // introduce them. So this means we have to do it by logical order * // of the extractors that we've created. * const SymmetricTensor<2,dim,ADNumberType> C_AD = - * ad_helper.get_sensitive_variables(C_dofs); const + * ad_helper.get_sensitive_variables(C_dofs); * const Tensor<1,dim,ADNumberType> H_AD = * ad_helper.get_sensitive_variables(H_dofs); * @@ -3055,7 +3055,7 @@ namespace Differentiation * // and extract the desired values from these intermediate outputs. * Vector Dpsi (ad_helper.n_dependent_variables()); * FullMatrix D2psi (ad_helper.n_dependent_variables(), - * ad_helper.n_dependent_variables()); + * ad_helper.n_independent_variables()); * const double psi = ad_helper.compute_value(); * ad_helper.compute_gradient(Dpsi); * ad_helper.compute_hessian(D2psi); @@ -3175,7 +3175,8 @@ namespace Differentiation * * @param[out] gradient A Vector with the values for the scalar field * gradient (first derivatives) evaluated at the point defined by the - * independent variable values. + * independent variable values. The output @p gradient vector has a length + * corresponding to @p n_independent_variables. */ void compute_gradient(Vector &gradient) const; @@ -3190,7 +3191,9 @@ namespace Differentiation * * @param[out] hessian A FullMatrix with the values for the scalar field * Hessian (second derivatives) evaluated at the point defined by the - * independent variable values. + * independent variable values. The output @p hessian matrix has + * dimensions corresponding to + * n_independent_variables$\times$n_independent_variables. */ void compute_hessian(FullMatrix &hessian) const; @@ -3207,6 +3210,27 @@ namespace Differentiation * @param[in] extractor_row An extractor associated with the input field * variables. This effectively defines which components of the global set * of independent variables this field is associated with. + * + * @return A Tensor or SymmetricTensor with its rank and symmetries + * determined by the @p extractor_row. + * This corresponds to subsetting a whole set of rows of the + * gradient vector, scaling those entries to take account of tensor + * symmetries, and then reshaping the (sub-)vector so obtained into a + * tensor, the final result. + * For example, if + * @p extractor_row is a FEValuesExtractors::Vector and + * @p extractor_col is a FEValuesExtractors::Tensor, + * then the returned object is a Tensor of rank 3, with its first + * index associated with the field corresponding to the row extractor and + * the second and third indices associated with the field corresponding to + * the column extractor. + * Similarly, if + * @p extractor_row is a FEValuesExtractors::SymmetricTensor and + * @p extractor_col is a FEValuesExtractors::SymmetricTensor, + * then the returned object is a SymmetricTensor of rank 4, with its first + * two indices associated with the field corresponding to the row + * extractor and the last two indices associated with the field + * corresponding to the column extractor. */ template typename internal::ScalarFieldGradient typename internal::ScalarFieldHessian extract_hessian_component( diff --git a/source/differentiation/ad/ad_helpers.cc b/source/differentiation/ad/ad_helpers.cc index a1e0809b5bfd..2317f763ded1 100644 --- a/source/differentiation/ad/ad_helpers.cc +++ b/source/differentiation/ad/ad_helpers.cc @@ -1617,10 +1617,10 @@ namespace Differentiation const FEValuesExtractors::SymmetricTensor<2> &extractor_col) const { // NOTE: The order of components must be consistently defined throughout - // this class. NOTE: We require a specialisation for rank-4 symmetric - // tensors because they - // do not define their rank, and setting data using TableIndices is - // somewhat specialised as well. + // this class. + // NOTE: We require a specialisation for rank-4 symmetric tensors because + // they do not define their rank, and setting data using TableIndices is + // somewhat specialised as well. SymmetricTensor<4, dim, scalar_type> out; // Get indexsets for the subblocks from which we wish to extract the From 461bf46c07f747b64c60379431ada73dd3cb1a3d Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 21 Mar 2019 15:25:24 +0100 Subject: [PATCH 299/507] Mark some member functions of ADHelperScalarFunction as static --- .../deal.II/differentiation/ad/ad_helpers.h | 33 +++++++++---------- source/differentiation/ad/ad_helpers.cc | 9 +++-- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index 685032fd369e..828ad50c9326 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -3233,11 +3233,10 @@ namespace Differentiation * corresponding to the column extractor. */ template - typename internal::ScalarFieldGradient::type - extract_gradient_component(const Vector &gradient, - const ExtractorType_Row &extractor_row) const; + static typename internal:: + ScalarFieldGradient::type + extract_gradient_component(const Vector &gradient, + const ExtractorType_Row & extractor_row); /** * Extract the function Hessian for a subset of independent variables @@ -3278,13 +3277,13 @@ namespace Differentiation * corresponding to the column extractor. */ template - typename internal::ScalarFieldHessian::type + static typename internal::ScalarFieldHessian::type extract_hessian_component(const FullMatrix &hessian, const ExtractorType_Row & extractor_row, - const ExtractorType_Col &extractor_col) const; + const ExtractorType_Col & extractor_col); /** * Extract the function Hessian for a subset of independent variables @@ -3299,11 +3298,11 @@ namespace Differentiation * Hessian matrix because both extractors imply selection of just a * single row or column of the matrix. */ - Tensor<0, dim, scalar_type> + static Tensor<0, dim, scalar_type> extract_hessian_component( const FullMatrix & hessian, const FEValuesExtractors::Scalar &extractor_row, - const FEValuesExtractors::Scalar &extractor_col) const; + const FEValuesExtractors::Scalar &extractor_col); /** * Extract the function Hessian for a subset of independent variables @@ -3314,13 +3313,13 @@ namespace Differentiation * @f] * * This function is a specialization of the above for rank-4 symmetric - * tensors + * tensors. */ - SymmetricTensor<4, dim, scalar_type> + static SymmetricTensor<4, dim, scalar_type> extract_hessian_component( const FullMatrix & hessian, const FEValuesExtractors::SymmetricTensor<2> &extractor_row, - const FEValuesExtractors::SymmetricTensor<2> &extractor_col) const; + const FEValuesExtractors::SymmetricTensor<2> &extractor_col); //@} @@ -3508,7 +3507,7 @@ namespace Differentiation ExtractorType_Row>::type ADHelperScalarFunction:: extract_gradient_component(const Vector &gradient, - const ExtractorType_Row & extractor_row) const + const ExtractorType_Row & extractor_row) { // NOTE: The order of components must be consistently defined throughout // this class. @@ -3542,7 +3541,7 @@ namespace Differentiation ADHelperScalarFunction:: extract_hessian_component(const FullMatrix &hessian, const ExtractorType_Row & extractor_row, - const ExtractorType_Col &extractor_col) const + const ExtractorType_Col & extractor_col) { using InternalHessian = internal::ScalarFieldHessian:: scalar_type> ADHelperScalarFunction:: - extract_hessian_component( - const FullMatrix & hessian, - const FEValuesExtractors::Scalar &extractor_row, - const FEValuesExtractors::Scalar &extractor_col) const + extract_hessian_component(const FullMatrix & hessian, + const FEValuesExtractors::Scalar &extractor_row, + const FEValuesExtractors::Scalar &extractor_col) { // NOTE: It is necessary to make special provision for the case when the // HessianType is scalar. Unfortunately Tensor<0,dim> does not provide @@ -1614,7 +1613,7 @@ namespace Differentiation extract_hessian_component( const FullMatrix & hessian, const FEValuesExtractors::SymmetricTensor<2> &extractor_row, - const FEValuesExtractors::SymmetricTensor<2> &extractor_col) const + const FEValuesExtractors::SymmetricTensor<2> &extractor_col) { // NOTE: The order of components must be consistently defined throughout // this class. From 6ec19eb45644225e057cf32026256715a8358b50 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 21 Mar 2019 15:26:06 +0100 Subject: [PATCH 300/507] AD Helpers: Add helper for vector functions (QP-level) --- .../deal.II/differentiation/ad/ad_helpers.h | 528 ++++++++++++++++++ source/differentiation/ad/ad_helpers.cc | 243 ++++++++ source/differentiation/ad/ad_helpers.inst1.in | 16 + source/differentiation/ad/ad_helpers.inst2.in | 28 + 4 files changed, 815 insertions(+) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index 828ad50c9326..7619901a82bc 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -3326,6 +3326,409 @@ namespace Differentiation }; // class ADHelperScalarFunction + + /** + * A helper class that facilitates the evaluation of a vector of functions, + * typically one that represents a collection of coupled, multi-dimensional + * fields. This class would typically be used to compute the linearization + * of a set of kinetic field variables defined at the quadrature point + * level. + * + * An example of its usage in the case of linearizing the kinetic variables + * derived from a multi-field constitutive law might be as follows: + * @code + * // Define some extractors that will help us set independent variables + * // and later get the computed values related to the dependent + * // variables. Each of these extractors is related to the gradient of a + * // component of the solution field (in this case, displacement and + * // magnetic scalar potential). Here "C" is the right Cauchy-Green + * // tensor and "H" is the magnetic field. + * const FEValuesExtractors::SymmetricTensor<2> C_dofs (0); + * const FEValuesExtractors::Vector H_dofs + * (dealii::SymmetricTensor<2,dim>::n_independent_components); + * const unsigned int n_independent_variables = + * SymmetricTensor<2,dim>::n_independent_components + + * Tensor<1,dim>::n_independent_components; + * + * // Declare how many dependent variables we expect to compute. + * // In this case, we will be computing a stress field (a symmetric + * // rank-2 tensor) and the magnetic induction (a vector field). + * // At the same time we define some additional extractors associated + * // with these kinetic fields. In general, these need not be of the same + * // layout as the independent variables. + * const FEValuesExtractors::SymmetricTensor<2> S_dofs (0); + * const FEValuesExtractors::Vector B_dofs + * (dealii::SymmetricTensor<2,dim>::n_independent_components); + * const unsigned int n_dependent_variables = + * SymmetricTensor<2,dim>::n_independent_components + + * Tensor<1,dim>::n_independent_components; + * + * // Define the helper that we will use in the AD computations for our + * // scalar energy function. Note that we expect it to return values of + * // type double. + * ADHelperVectorFunction ad_helper (n_independent_variables, + * n_dependent_variables); + * using ADNumberType = typename ADHelper::ad_type; + * + * // Compute the fields that provide the independent values. + * // When the tape is being replayed, these should be set to something + * // meaningful. + * const Tensor<1,dim> H = ...; + * const SymmetricTensor<2,dim> C = ...; + * + * // If using a taped AD number, then at this point we would initiate + * // taping of the expression for the material stored energy function + * // for this particular set of material parameters: + * + * // Select a tape number to record to + * const typename Types::tape_index tape_index = ...; + * + * // Indicate that we are about to start tracing the operations for + * // function evaluation on the tape. If this tape has already been + * // used (i.e. the operations are already recorded) then we + * // (optionally) load the tape and reuse this data. + * const bool is_recording + * = ad_helper.start_recording_operations(tape_index); + * + * // The steps that follow in the recording phase are required for + * // tapeless methods as well. + * if (is_recording == true) + * { + * // This is the "recording" phase of the operations. + * + * // First, we set the values for all fields. + * // These could happily be set to anything, unless the function will + * // be evaluated along a branch not otherwise traversed during later + * // use. For this reason, in this example instead of using some dummy + * // values, we'll actually map out the function at the same point + * // around which we'll later linearize it. + * ad_helper.register_independent_variable(H, H_dofs); + * ad_helper.register_independent_variable(C, C_dofs); + * + * // NOTE: We have to extract the sensitivities in the order we wish to + * // introduce them. So this means we have to do it by logical order + * // of the extractors that we've created. + * const SymmetricTensor<2,dim,ADNumberType> C_AD = + * ad_helper.get_sensitive_variables(C_dofs); + * const Tensor<1,dim,ADNumberType> H_AD = + * ad_helper.get_sensitive_variables(H_dofs); + * + * // Here we define the stress and magnetic induction in terms + * // of the independent values C_AD and H_AD. + * const SymmetricTensor<2, dim, ad_type> S_AD = ...; + * const Tensor<1, dim, ad_type> B_AD = ...; + * + * // Register the definition of the kinetic fields. The second + * // argument to the function provides a non-overlapping ordering + * // of the + * ad_helper.register_dependent_variable(S_AD, S_dofs); + * ad_helper.register_dependent_variable(B_AD, B_dofs); + * + * // Indicate that we have completed tracing the operations onto + * // the tape. + * ad_helper.stop_recording_operations(false); // write_tapes_to_file + * } + * else + * { + * // This is the "tape reuse" phase of the operations. + * // Here we will leverage the already traced operations that reside + * // on a tape, and simply re-evaluate the tape at a different point + * // to get the function values and their derivatives. + * + * // Load the existing tape to be reused + * ad_helper.activate_recorded_tape(tape_index); + * + * // Set the new values of the independent variables where the + * // recorded dependent functions are to be evaluated (and + * // differentiated around). + * ad_helper.set_independent_variable(C, C_dofs); + * ad_helper.set_independent_variable(H, H_dofs); + * } + * + * // Play the tape and store the output function value, its gradient and + * // linearization. These are expensive to compute, so we'll do this once + * // and extract the desired values from these intermediate outputs. + * Vector values (ad_helper.n_dependent_variables()); + * FullMatrix jacobian (ad_helper.n_dependent_variables(), + * ad_helper.n_independent_variables()); + * ad_helper.compute_values(values); + * ad_helper.compute_jacobian(jacobian); + * + * // Extract the desired components of the value vector and its Jacobian + * // matrix. In this example, we use them to compute the Piola-Kirchhoff + * // stress tensor S and its associated tangent, defined + * // as HH = 2*dS/dC... + * const SymmetricTensor<2,dim> S = + * ad_helper.extract_value_component(values,S_dofs); + * const SymmetricTensor<4,dim> HH = + * 2.0*ad_helper.extract_jacobian_component(jacobian,S_dofs,C_dofs); + * + * // ... the magnetic induction B and its associated tangent defined + * // as BB = dB/dH... + * const Tensor<1,dim> B = + * ad_helper.extract_value_component(values,H_dofs); + * const SymmetricTensor<2,dim> BB = + * symmetrize(ad_helper.extract_jacobian_component(jacobian,B_dofs,H_dofs)); + * + * // ... and finally the magnetoelastic coupling tangent, defined + * // as PP = -dS/dH. Here the order of the extractor arguments is + * // especially important, as it dictates the field that is being + * // differentiated, and which the directional derivatives are being + * // computed. + * const Tensor<3,dim,double> PP = + * -ad_helper.extract_jacobian_component(jacobian,S_dofs,H_dofs) + * @endcode + * + * @warning ADOL-C does not support the standard threading models used by + * deal.II, so this class should @b not be embedded within a multithreaded + * function when using ADOL-C number types. It is, however, suitable for use + * in both serial and MPI routines. + * + * @author Jean-Paul Pelteret, 2016, 2017, 2018 + */ + template + class ADHelperVectorFunction + : public ADHelperPointLevelFunctionsBase + { + public: + /** + * Type definition for the floating point number type that is used in, + * and results from, all computations. + */ + using scalar_type = + typename ADHelperBase::scalar_type; + + /** + * Type definition for the auto-differentiation number type that is used + * in all computations. + */ + using ad_type = + typename ADHelperBase::ad_type; + + /** + * @name Constructor / destructor + */ + //@{ + + /** + * The constructor for the class. + * + * @param[in] n_independent_variables The number of independent variables + * that will be used in the definition of the functions that it is + * desired to compute the sensitivities of. In the computation of + * $\mathbf{f}(\mathbf{X})$, this will be the number of inputs + * $\mathbf{X}$, i.e., the dimension of the domain space. + * @param[in] n_dependent_variables The number of scalar functions to be + * defined that will have a sensitivity to the given independent + * variables. In the computation of $\mathbf{f}(\mathbf{X})$, this will + * be the number of outputs $\mathbf{f}$, i.e., the dimension of the + * image space. + */ + ADHelperVectorFunction(const unsigned int n_independent_variables, + const unsigned int n_dependent_variables); + + /** + * Destructor. + */ + virtual ~ADHelperVectorFunction() = default; + + //@} + + /** + * @name Dependent variables + */ + //@{ + + /** + * Register the definition of the vector field + * $\boldsymbol{\Psi}(\mathbf{X})$. + * + * @param[in] funcs A vector of recorded functions that defines the + * dependent variables. + * + * @note For this class that expects only vector field of dependent + * variables, this function must only be called once per tape. + * + * @note For taped AD numbers, this operation is only valid in recording mode. + */ + void + register_dependent_variables(const std::vector &funcs); + + /** + * Register the definition of the vector field + * $\hat{\mathbf{g}}(\mathbf{X}) \subset \boldsymbol{\Psi}(\mathbf{X})$ + * that may represent a subset of the dependent variables. + * + * @param[in] funcs The recorded functions that define a set of dependent + * variables. + * @param[in] extractor An extractor associated with the input field + * variables. This effectively defines which components of the global set + * of dependent variables this field is associated with. + * + * @note The input extractor must correspond to the input @p ValueType. + * So, for example, if a value is a rank-1 tensor + * (i.e. of type Tensor<1,dim,scalar_type>), then the extractor must + * be an FEValuesExtractors::Vector or FEValuesExtractors::Tensor<1>. + * + * @note For taped AD numbers, this operation is only valid in recording mode. + */ + template + void + register_dependent_variable(const ValueType & funcs, + const ExtractorType &extractor); + + /** + * Compute the value of the vector field $\boldsymbol{\Psi}(\mathbf{X})$. + * + * @param[out] values A Vector object with the value for each component + * of the vector field evaluated at the point defined by the independent + * variable values. The output @p values vector has a length + * corresponding to @p n_dependent_variables. + */ + void + compute_values(Vector &values) const; + + /** + * Compute the Jacobian (first derivative) of the vector field with + * respect to all independent variables, i.e. + * @f[ + * \mathbf{J}(\boldsymbol{\Psi}) + * = \frac{\partial\boldsymbol{\Psi}(\mathbf{X})}{\partial\mathbf{X}} + * @f] + * + * @param[out] jacobian A FullMatrix with the gradient of each component + * of the vector field evaluated at the point defined by the independent + * variable values. The output @p jacobian matrix has + * dimensions corresponding to + * n_dependent_variables$\times$n_independent_variables. + */ + void + compute_jacobian(FullMatrix &jacobian) const; + + + /** + * Extract the set of functions' values for a subset of dependent + * variables + * $\mathbf{g} \subset \boldsymbol{\Psi}(\mathbf{X})$. + * + * @param[in] values A Vector object with the value for each component of + * the vector field evaluated at the point defined by the independent + * variable values. + * @param[in] extractor_row An extractor associated with the input field + * variables. This effectively defines which components of the global set + * of dependent variables this field is associated with. + */ + template + static typename internal:: + VectorFieldValue::type + extract_value_component(const Vector &values, + const ExtractorType_Row & extractor_row); + + /** + * Extract the Jacobian of the subset of dependent functions + * $\mathbf{g} \subset \boldsymbol{\Psi}(\mathbf{X})$ + * for a subset of independent variables + * $\mathbf{A} \subset \mathbf{X}$, i.e. + * @f[ + * \mathbf{J}(\mathbf{g}) + * = \frac{\partial\mathbf{g}(\mathbf{X})}{\partial\mathbf{A}} + * @f] + * The first index of the Jacobian matrix $\mathbf{J}(\mathbf{g})$ + * relates to the dependent variables, while the second index relates + * to the independent variables. + * + * @param[in] jacobian The Jacobian of the vector function with respect to + * all independent variables, i.e., that returned by compute_jacobian(). + * @param[in] extractor_row An extractor associated with the input field + * variables for which the first index of the Jacobian is extracted. + * This effectively defines the correspondence between components of the + * global set of dependent variables and the field (representing a + * subset of dependent functions) associated with the extractor. + * @param[in] extractor_col An extractor associated with the input field + * variables for which the second index of the Jacobian is extracted. + * This effectively defines the correspondence between components of the + * global set of independent variables and the field (representing a + * subset of independent variables) associated with the extractor. + * + * @return A Tensor or SymmetricTensor with its rank and symmetries + * determined by the @p extractor_row and @p extractor_col . + * This corresponds to subsetting a whole set of rows and columns of the + * Jacobian matrix, scaling those entries to take account of tensor + * symmetries, and then reshaping the (sub-)matrix so obtained into a + * tensor, the final result. + * For example, if + * @p extractor_row is a FEValuesExtractors::Vector and + * @p extractor_col is a FEValuesExtractors::Tensor, + * then the returned object is a Tensor of rank 3, with its first + * index associated with the field corresponding to the row extractor and + * the second and third indices associated with the field corresponding to + * the column extractor. + * Similarly, if + * @p extractor_row is a FEValuesExtractors::SymmetricTensor and + * @p extractor_col is a FEValuesExtractors::SymmetricTensor, + * then the returned object is a SymmetricTensor of rank 4, with its first + * two indices associated with the field corresponding to the row + * extractor and the last two indices associated with the field + * corresponding to the column extractor. + */ + template + static typename internal::VectorFieldJacobian::type + extract_jacobian_component(const FullMatrix &jacobian, + const ExtractorType_Row & extractor_row, + const ExtractorType_Col & extractor_col); + + /** + * Extract the Jacobian of the subset of dependent functions + * $\mathbf{g} \subset \boldsymbol{\Psi}(\mathbf{X})$ + * for a subset of independent variables + * $\mathbf{A} \subset \mathbf{X}$, i.e. + * @f[ + * \mathbf{J}(\mathbf{g}) + * = \frac{\partial\mathbf{g}(\mathbf{X})}{\partial\mathbf{A}} + * @f] + * + * This function is a specialization of the above for rank-0 tensors + * (scalars). This corresponds to extracting a single entry of the + * Jacobian matrix because both extractors imply selection of just a + * single row or column of the matrix. + */ + static Tensor<0, dim, scalar_type> + extract_jacobian_component( + const FullMatrix & jacobian, + const FEValuesExtractors::Scalar &extractor_row, + const FEValuesExtractors::Scalar &extractor_col); + + /** + * Extract the Jacobian of the subset of dependent functions + * $\mathbf{g} \subset \boldsymbol{\Psi}(\mathbf{X})$ + * for a subset of independent variables + * $\mathbf{A} \subset \mathbf{X}$, i.e. + * @f[ + * \mathbf{J}(\mathbf{g}) + * = \frac{\partial\mathbf{g}(\mathbf{X})}{\partial\mathbf{A}} + * @f] + * + * This function is a specialization of the above for rank-4 symmetric + * tensors. + */ + static SymmetricTensor<4, dim, scalar_type> + extract_jacobian_component( + const FullMatrix & jacobian, + const FEValuesExtractors::SymmetricTensor<2> &extractor_row, + const FEValuesExtractors::SymmetricTensor<2> &extractor_col); + + //@} + + }; // class ADHelperVectorFunction + + } // namespace AD } // namespace Differentiation @@ -3592,6 +3995,131 @@ namespace Differentiation } + + /* ----------------- ADHelperVectorFunction ----------------- */ + + + + template + template + void + ADHelperVectorFunction:: + register_dependent_variable(const ValueType & funcs, + const ExtractorType &extractor) + { + const std::vector index_set( + internal::extract_field_component_indices(extractor)); + for (unsigned int i = 0; i < index_set.size(); ++i) + { + Assert(this->registered_marked_dependent_variables[index_set[i]] == + false, + ExcMessage("Overlapping indices for dependent variables.")); + ADHelperBase:: + register_dependent_variable(index_set[i], + internal::get_tensor_entry(funcs, i)); + } + } + + + + template + template + typename internal::VectorFieldValue< + dim, + typename ADHelperVectorFunction:: + scalar_type, + ExtractorType_Row>::type + ADHelperVectorFunction:: + extract_value_component(const Vector &values, + const ExtractorType_Row & extractor_row) + { + // NOTE: The order of components must be consistently defined throughout + // this class. + typename internal::VectorFieldValue:: + type out; + + // Get indexsets for the subblock from which we wish to extract the + // gradient values + const std::vector row_index_set( + internal::extract_field_component_indices(extractor_row)); + Assert(out.n_independent_components == row_index_set.size(), + ExcMessage("Not all tensor components have been extracted!")); + for (unsigned int r = 0; r < row_index_set.size(); ++r) + internal::set_tensor_entry(out, r, values[row_index_set[r]]); + + return out; + } + + + + template + template + typename internal::VectorFieldJacobian< + dim, + typename ADHelperVectorFunction:: + scalar_type, + ExtractorType_Row, + ExtractorType_Col>::type + ADHelperVectorFunction:: + extract_jacobian_component(const FullMatrix &jacobian, + const ExtractorType_Row & extractor_row, + const ExtractorType_Col & extractor_col) + { + using InternalJacobian = internal::VectorFieldJacobian; + using InternalExtractorRow = internal::Extractor; + using InternalExtractorCol = internal::Extractor; + using JacobianType = typename InternalJacobian::type; + + // NOTE: The order of components must be consistently defined throughout + // this class. + JacobianType out; + + // Get indexsets for the subblocks from which we wish to extract the + // Hessian values. + // NOTE: Here we have to do some clever accounting when the + // one extractor is a symmetric Tensor and the other is not, e.g. + // . In this scenario the return type is a + // non-symmetric Tensor<3,dim> but we have to fetch information from a + // SymmTensor row/column that has too few entries to fill the output + // tensor. So we must duplicate the relevant entries in the row/column + // indexset to fetch off-diagonal components that are Otherwise + // non-existent in a SymmTensor. + const std::vector row_index_set( + internal::extract_field_component_indices( + extractor_row, false /*ignore_symmetries*/)); + const std::vector col_index_set( + internal::extract_field_component_indices( + extractor_col, false /*ignore_symmetries*/)); + + for (unsigned int index = 0; + index < JacobianType::n_independent_components; + ++index) + { + const TableIndices ti_out = + JacobianType::unrolled_to_component_indices(index); + const unsigned int r = + InternalExtractorRow::local_component(ti_out, 0); + const unsigned int c = + InternalExtractorCol::local_component(ti_out, + InternalExtractorRow::rank); + + internal::set_tensor_entry( + out, index, jacobian[row_index_set[r]][col_index_set[c]]); + } + + return out; + } + + } // namespace AD } // namespace Differentiation diff --git a/source/differentiation/ad/ad_helpers.cc b/source/differentiation/ad/ad_helpers.cc index 1722791301b5..4d67b34ad7f9 100644 --- a/source/differentiation/ad/ad_helpers.cc +++ b/source/differentiation/ad/ad_helpers.cc @@ -1640,6 +1640,249 @@ namespace Differentiation } + + /* -------------------- ADHelperVectorFunction -------------------- */ + + + + template + ADHelperVectorFunction:: + ADHelperVectorFunction(const unsigned int n_independent_variables, + const unsigned int n_dependent_variables) + : ADHelperPointLevelFunctionsBase( + n_independent_variables, + n_dependent_variables) + {} + + + + template + void + ADHelperVectorFunction:: + register_dependent_variables(const std::vector &funcs) + { + Assert(funcs.size() == this->n_dependent_variables(), + ExcMessage( + "Vector size does not match number of dependent variables")); + for (unsigned int i = 0; i < this->n_dependent_variables(); ++i) + ADHelperBase::register_dependent_variable( + i, funcs[i]); + } + + + + template + void + ADHelperVectorFunction::compute_values( + Vector &values) const + { + if ((ADNumberTraits::is_taped == true && + this->taped_driver.keep_independent_values() == false) || + ADNumberTraits::is_tapeless == true) + { + Assert( + this->n_registered_independent_variables() == + this->n_independent_variables(), + ExcMessage( + "Not all values of sensitivities have been registered or subsequently set!")); + } + Assert(this->n_registered_dependent_variables() == + this->n_dependent_variables(), + ExcMessage("Not all dependent variables have been registered.")); + + // We can neglect correctly initializing the entries as + // we'll be overwriting them immediately in the succeeding call to + // Drivers::values(). + if (values.size() != this->n_dependent_variables()) + values.reinit(this->n_dependent_variables(), + true /*omit_zeroing_entries*/); + + if (ADNumberTraits::is_taped == true) + { + Assert(this->active_tape_index() != + Numbers::invalid_tape_index, + ExcMessage("Invalid tape index")); + Assert(this->is_recording() == false, + ExcMessage( + "Cannot compute values while tape is being recorded.")); + Assert(this->independent_variable_values.size() == + this->n_independent_variables(), + ExcDimensionMismatch(this->independent_variable_values.size(), + this->n_independent_variables())); + + this->taped_driver.values(this->active_tape_index(), + this->n_dependent_variables(), + this->independent_variable_values, + values); + } + else + { + Assert(ADNumberTraits::is_tapeless == true, + ExcInternalError()); + this->tapeless_driver.values(this->dependent_variables, values); + } + } + + + + template + void + ADHelperVectorFunction::compute_jacobian( + FullMatrix &jacobian) const + { + if ((ADNumberTraits::is_taped == true && + this->taped_driver.keep_independent_values() == false) || + ADNumberTraits::is_tapeless == true) + { + Assert( + this->n_registered_independent_variables() == + this->n_independent_variables(), + ExcMessage( + "Not all values of sensitivities have been registered or subsequently set!")); + } + Assert(this->n_registered_dependent_variables() == + this->n_dependent_variables(), + ExcMessage("Not all dependent variables have been registered.")); + + // We can neglect correctly initializing the entries as + // we'll be overwriting them immediately in the succeeding call to + // Drivers::jacobian(). + if (jacobian.m() != this->n_dependent_variables() || + jacobian.n() != this->n_independent_variables()) + jacobian.reinit({this->n_dependent_variables(), + this->n_independent_variables()}, + true /*omit_default_initialization*/); + + if (ADNumberTraits::is_taped == true) + { + Assert(this->active_tape_index() != + Numbers::invalid_tape_index, + ExcMessage("Invalid tape index")); + Assert(this->is_recording() == false, + ExcMessage( + "Cannot compute Jacobian while tape is being recorded.")); + Assert(this->independent_variable_values.size() == + this->n_independent_variables(), + ExcDimensionMismatch(this->independent_variable_values.size(), + this->n_independent_variables())); + + this->taped_driver.jacobian(this->active_tape_index(), + this->n_dependent_variables(), + this->independent_variable_values, + jacobian); + } + else + { + Assert(ADNumberTraits::is_tapeless == true, + ExcInternalError()); + Assert(this->independent_variables.size() == + this->n_independent_variables(), + ExcDimensionMismatch(this->independent_variables.size(), + this->n_independent_variables())); + + this->tapeless_driver.jacobian(this->independent_variables, + this->dependent_variables, + jacobian); + } + + for (unsigned int j = 0; j < this->n_independent_variables(); j++) + { + // Because we perform just a single differentiation + // operation with respect to the "column" variables, + // we only need to consider them for symmetry conditions. + if (this->is_symmetric_independent_variable(j) == true) + for (unsigned int i = 0; i < this->n_dependent_variables(); i++) + jacobian[i][j] *= 0.5; + } + } + + + + template + Tensor<0, + dim, + typename ADHelperVectorFunction:: + scalar_type> + ADHelperVectorFunction:: + extract_jacobian_component( + const FullMatrix & jacobian, + const FEValuesExtractors::Scalar &extractor_row, + const FEValuesExtractors::Scalar &extractor_col) + { + // NOTE: It is necessary to make special provision for the case when the + // HessianType is scalar. Unfortunately Tensor<0,dim> does not provide + // the function unrolled_to_component_indices! + // NOTE: The order of components must be consistently defined throughout + // this class. + Tensor<0, dim, scalar_type> out; + + // Get indexsets for the subblocks from which we wish to extract the + // matrix values + const std::vector row_index_set( + internal::extract_field_component_indices(extractor_row)); + const std::vector col_index_set( + internal::extract_field_component_indices(extractor_col)); + Assert(row_index_set.size() == 1, ExcInternalError()); + Assert(col_index_set.size() == 1, ExcInternalError()); + + internal::set_tensor_entry(out, + 0, + jacobian[row_index_set[0]][col_index_set[0]]); + + return out; + } + + + + template + SymmetricTensor<4, + dim, + typename ADHelperVectorFunction::scalar_type> + ADHelperVectorFunction:: + extract_jacobian_component( + const FullMatrix & jacobian, + const FEValuesExtractors::SymmetricTensor<2> &extractor_row, + const FEValuesExtractors::SymmetricTensor<2> &extractor_col) + { + // NOTE: The order of components must be consistently defined throughout + // this class. + // NOTE: We require a specialisation for rank-4 symmetric tensors because + // they do not define their rank, and setting data using TableIndices is + // somewhat specialised as well. + SymmetricTensor<4, dim, scalar_type> out; + + // Get indexsets for the subblocks from which we wish to extract the + // matrix values + const std::vector row_index_set( + internal::extract_field_component_indices(extractor_row)); + const std::vector col_index_set( + internal::extract_field_component_indices(extractor_col)); + + for (unsigned int r = 0; r < row_index_set.size(); ++r) + for (unsigned int c = 0; c < col_index_set.size(); ++c) + { + internal::set_tensor_entry( + out, r, c, jacobian[row_index_set[r]][col_index_set[c]]); + } + + return out; + } + + } // namespace AD } // namespace Differentiation diff --git a/source/differentiation/ad/ad_helpers.inst1.in b/source/differentiation/ad/ad_helpers.inst1.in index a5c9b87da3bf..1c1ff5a534b8 100644 --- a/source/differentiation/ad/ad_helpers.inst1.in +++ b/source/differentiation/ad/ad_helpers.inst1.in @@ -125,6 +125,14 @@ for (deal_II_dimension : DIMENSIONS ; number : REAL_SCALARS) template class ADHelperScalarFunction; + // -------------------------- ADHelperVectorFunction ---------------------- + + template + class ADHelperVectorFunction; + + template + class ADHelperVectorFunction; + \} \} } @@ -153,6 +161,14 @@ for (deal_II_dimension : DIMENSIONS) template class ADHelperScalarFunction::ad_type>; + // -------------------------- ADHelperVectorFunction ---------------------- + + template + class ADHelperVectorFunction::ad_type>; + + template + class ADHelperVectorFunction::ad_type>; + \} \} } diff --git a/source/differentiation/ad/ad_helpers.inst2.in b/source/differentiation/ad/ad_helpers.inst2.in index e886a8575ad0..800b697f99ae 100644 --- a/source/differentiation/ad/ad_helpers.inst2.in +++ b/source/differentiation/ad/ad_helpers.inst2.in @@ -186,6 +186,20 @@ for (deal_II_dimension : DIMENSIONS ; number : REAL_SCALARS) template class ADHelperScalarFunction; + // -------------------------- ADHelperVectorFunction ---------------------- + + template + class ADHelperVectorFunction; + + template + class ADHelperVectorFunction; + + template + class ADHelperVectorFunction; + + template + class ADHelperVectorFunction; + \} \} } @@ -225,6 +239,20 @@ for (deal_II_dimension : DIMENSIONS) template class ADHelperScalarFunction::ad_type>; + + // -------------------------- ADHelperVectorFunction ---------------------- + + template + class ADHelperVectorFunction::ad_type>; + + template + class ADHelperVectorFunction::ad_type>; + + template + class ADHelperVectorFunction::ad_type>; + + template + class ADHelperVectorFunction::ad_type>; \} \} From 6a59dba257e2ef0170b164b5784ceef19b72ccdf Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 21 Mar 2019 15:29:51 +0100 Subject: [PATCH 301/507] Add a changelog entry for ADHelperVectorFunction --- doc/news/changes/major/20190321Jean-PaulPelteret | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 doc/news/changes/major/20190321Jean-PaulPelteret diff --git a/doc/news/changes/major/20190321Jean-PaulPelteret b/doc/news/changes/major/20190321Jean-PaulPelteret new file mode 100644 index 000000000000..54b796a6d6b7 --- /dev/null +++ b/doc/news/changes/major/20190321Jean-PaulPelteret @@ -0,0 +1,9 @@ +New: A new class Differentiation::AD::ADHelperVectorFunction 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) From e400be3332a7f6d4eb6c5e17226b411820589895 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Thu, 21 Mar 2019 09:59:22 -0600 Subject: [PATCH 302/507] Revamp the layout of the main 'index.html' file. --- doc/CMakeLists.txt | 11 ------ doc/documentation.html | 75 ----------------------------------- doc/index.html | 90 ++++++++++++++++++++++++++++++++++++------ doc/navbar.html | 51 ------------------------ doc/title.html.in | 17 -------- 5 files changed, 77 insertions(+), 167 deletions(-) delete mode 100644 doc/documentation.html delete mode 100644 doc/navbar.html delete mode 100644 doc/title.html.in 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 9977691eb5fc..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/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/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

    -
    - - - - From d566a2d10af46abcc9fa4ea7dd8a1fd4f6610d83 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 21 Mar 2019 20:35:02 +0100 Subject: [PATCH 303/507] Also link with LAPACK libraries --- cmake/configure/configure_scalapack.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/configure/configure_scalapack.cmake b/cmake/configure/configure_scalapack.cmake index a91457f379c2..08820ceecbbd 100644 --- a/cmake/configure/configure_scalapack.cmake +++ b/cmake/configure/configure_scalapack.cmake @@ -28,7 +28,7 @@ MACRO(FEATURE_SCALAPACK_FIND_EXTERNAL var) CHECK_MPI_INTERFACE(SCALAPACK ${var}) IF (${var}) - SET(CMAKE_REQUIRED_LIBRARIES ${SCALAPACK_LIBRARIES}) + SET(CMAKE_REQUIRED_LIBRARIES ${SCALAPACK_LIBRARIES} ${LAPACK_LIBRARIES}) CHECK_C_SOURCE_COMPILES(" void pdsyevr_(); void pssyevr_(); From 5fdaaaf6c1ee8ff5152dff86bb7fec3a7ea6ce72 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 19 Mar 2019 19:32:08 +0100 Subject: [PATCH 304/507] Added get_names to Extractors, and moved implementation to cc file. --- doc/news/changes/minor/20190319LucaHeltai | 4 ++ include/deal.II/fe/fe_values_extractors.h | 24 ++++++++ source/fe/CMakeLists.txt | 1 + source/fe/fe_values_extractors.cc | 67 +++++++++++++++++++++++ tests/fe/fe_values_extractor_02.cc | 40 ++++++++++++++ tests/fe/fe_values_extractor_02.output | 5 ++ 6 files changed, 141 insertions(+) create mode 100644 doc/news/changes/minor/20190319LucaHeltai create mode 100644 source/fe/fe_values_extractors.cc create mode 100644 tests/fe/fe_values_extractor_02.cc create mode 100644 tests/fe/fe_values_extractor_02.output 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/include/deal.II/fe/fe_values_extractors.h b/include/deal.II/fe/fe_values_extractors.h index db3729129af0..a7e1944bd3b1 100644 --- a/include/deal.II/fe/fe_values_extractors.h +++ b/include/deal.II/fe/fe_values_extractors.h @@ -112,6 +112,12 @@ namespace FEValuesExtractors * Constructor. Take the selected vector component as argument. */ Scalar(const unsigned int component); + + /** + * Return a string that uniquely identifies this finite element extractor. + */ + std::string + get_name() const; }; @@ -162,6 +168,12 @@ namespace FEValuesExtractors * FEValues object as argument. */ Vector(const unsigned int first_vector_component); + + /** + * Return a string that uniquely identifies this finite element extractor. + */ + std::string + get_name() const; }; @@ -205,6 +217,12 @@ namespace FEValuesExtractors * FEValues object as argument. */ SymmetricTensor(const unsigned int first_tensor_component); + + /** + * Return a string that uniquely identifies this finite element extractor. + */ + std::string + get_name() const; }; @@ -248,6 +266,12 @@ namespace FEValuesExtractors * FEValues object as argument. */ Tensor(const unsigned int first_tensor_component); + + /** + * Return a string that uniquely identifies this finite element extractor. + */ + std::string + get_name() const; }; } // namespace FEValuesExtractors diff --git a/source/fe/CMakeLists.txt b/source/fe/CMakeLists.txt index 79a5bb8466f3..fbc00aeafc05 100644 --- a/source/fe/CMakeLists.txt +++ b/source/fe/CMakeLists.txt @@ -63,6 +63,7 @@ SET(_unity_include_src SET(_separate_src fe_values.cc + fe_values_extractors.cc fe_values_inst2.cc fe_values_inst3.cc fe_values_inst4.cc diff --git a/source/fe/fe_values_extractors.cc b/source/fe/fe_values_extractors.cc new file mode 100644 index 000000000000..8d0c417f6eb5 --- /dev/null +++ b/source/fe/fe_values_extractors.cc @@ -0,0 +1,67 @@ +// --------------------------------------------------------------------- +// +// 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 + +#include + +DEAL_II_NAMESPACE_OPEN + +namespace FEValuesExtractors +{ + std::string + Scalar::get_name() const + { + return "Scalar(" + Utilities::int_to_string(component) + ")"; + } + + + std::string + Vector::get_name() const + { + return "Vector(" + Utilities::int_to_string(first_vector_component) + ")"; + } + + + template + std::string + Tensor::get_name() const + { + return "Tensor<" + Utilities::int_to_string(rank) + ">(" + + Utilities::int_to_string(first_tensor_component) + ")"; + } + + + template + std::string + SymmetricTensor::get_name() const + { + return "SymmetricTensor<" + Utilities::int_to_string(rank) + ">(" + + Utilities::int_to_string(first_tensor_component) + ")"; + } + + // Explicit instantiations + template struct Tensor<1>; + template struct Tensor<2>; + template struct Tensor<3>; + template struct Tensor<4>; + template struct SymmetricTensor<2>; + template struct SymmetricTensor<4>; + +} // namespace FEValuesExtractors + + + +DEAL_II_NAMESPACE_CLOSE \ No newline at end of file diff --git a/tests/fe/fe_values_extractor_02.cc b/tests/fe/fe_values_extractor_02.cc new file mode 100644 index 000000000000..c48a224ced99 --- /dev/null +++ b/tests/fe/fe_values_extractor_02.cc @@ -0,0 +1,40 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + + +// test that the FEValuesExtractors::get_name() work as expected + +#include +#include + +#include "../tests.h" + +int +main() +{ + initlog(); + + FEValuesExtractors::Scalar scalar(0); + FEValuesExtractors::Vector vector(1); + FEValuesExtractors::Tensor<2> tensor(3); + FEValuesExtractors::SymmetricTensor<2> symmetric_tensor(4); + + + deallog << scalar.get_name() << std::endl + << vector.get_name() << std::endl + << tensor.get_name() << std::endl + << symmetric_tensor.get_name() << std::endl; +} diff --git a/tests/fe/fe_values_extractor_02.output b/tests/fe/fe_values_extractor_02.output new file mode 100644 index 000000000000..1b5a9144063b --- /dev/null +++ b/tests/fe/fe_values_extractor_02.output @@ -0,0 +1,5 @@ + +DEAL::Scalar(0) +DEAL::Vector(1) +DEAL::Tensor<2>(3) +DEAL::SymmetricTensor<2>(4) From 6fbe952eae8a71ef19066af2b1b1a6fb7a25a9fc Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Thu, 21 Mar 2019 22:04:00 +0100 Subject: [PATCH 305/507] make MPILogInitAll work without MPI --- tests/tests.h | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/tests.h b/tests/tests.h index f585da1fc761..ee46c716d0a7 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -527,6 +527,9 @@ struct MPILogInitAll { #ifdef DEAL_II_WITH_MPI const unsigned int myid = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); +#else + constexpr unsigned int myid = 0; +#endif if (myid == 0) { if (!deallog.has_file()) @@ -545,22 +548,17 @@ struct MPILogInitAll deallog.depth_console(console ? 10 : 0); deallog.push(Utilities::int_to_string(myid)); -#else - (void)console; - // can't use this function if not using MPI - Assert(false, ExcInternalError()); -#endif } ~MPILogInitAll() { + // pop the prefix for the MPI rank of the current process + deallog.pop(); + #ifdef DEAL_II_WITH_MPI const unsigned int myid = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); const unsigned int nproc = Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD); - // pop the prefix for the MPI rank of the current process - deallog.pop(); - if (myid != 0) { deallog.detach(); @@ -583,10 +581,6 @@ struct MPILogInitAll } } MPI_Barrier(MPI_COMM_WORLD); - -#else - // can't use this function if not using MPI - Assert(false, ExcInternalError()); #endif } }; From d3c741494c5f62b4856bd6dd80c1f02344d7bc22 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Tue, 19 Mar 2019 20:39:35 +0100 Subject: [PATCH 306/507] add Utilities::MPI::create_ascending_partitioning() --- doc/news/changes/minor/20190319DenisDavydov | 4 + include/deal.II/base/mpi.h | 13 +++ source/base/mpi.cc | 33 ++++++++ tests/base/mpi_create_partitioning_01.cc | 80 +++++++++++++++++++ ...mpi_create_partitioning_01.mpirun=2.output | 13 +++ ...mpi_create_partitioning_01.mpirun=4.output | 43 ++++++++++ tests/base/mpi_create_partitioning_01.output | 4 + 7 files changed, 190 insertions(+) create mode 100644 doc/news/changes/minor/20190319DenisDavydov create mode 100644 tests/base/mpi_create_partitioning_01.cc create mode 100644 tests/base/mpi_create_partitioning_01.mpirun=2.output create mode 100644 tests/base/mpi_create_partitioning_01.mpirun=4.output create mode 100644 tests/base/mpi_create_partitioning_01.output 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/include/deal.II/base/mpi.h b/include/deal.II/base/mpi.h index 4688b3c17fd4..74bef20899e6 100644 --- a/include/deal.II/base/mpi.h +++ b/include/deal.II/base/mpi.h @@ -90,6 +90,7 @@ template class SymmetricTensor; template class SparseMatrix; +class IndexSet; namespace Utilities { @@ -225,6 +226,18 @@ namespace Utilities MPI_Comm * new_comm); #endif + /** + * Given the number of locally owned elements @p local_size, + * create a 1:1 partitioning of the of elements across the MPI communicator @p comm. + * The total size of elements is the sum of @p local_size across the MPI communicator. + * Each process will store contiguous subset of indices, and the index set + * on process p+1 starts at the index one larger than the last one stored on + * process p. + */ + std::vector + create_ascending_partitioning(const MPI_Comm & comm, + const IndexSet::size_type &local_size); + /** * Return the sum over all processors of the value @p t. This function is * collective over all processors given in the diff --git a/source/base/mpi.cc b/source/base/mpi.cc index b8cd45e7c26a..35928aa9cc19 100644 --- a/source/base/mpi.cc +++ b/source/base/mpi.cc @@ -15,6 +15,7 @@ #include +#include #include #include #include @@ -181,6 +182,30 @@ namespace Utilities + std::vector + create_ascending_partitioning(const MPI_Comm & comm, + const IndexSet::size_type &local_size) + { + const unsigned int n_proc = n_mpi_processes(comm); + const std::vector sizes = + all_gather(comm, local_size); + const auto total_size = + std::accumulate(sizes.begin(), sizes.end(), IndexSet::size_type(0)); + + std::vector res(n_proc, IndexSet(total_size)); + + IndexSet::size_type begin = 0; + for (unsigned int i = 0; i < n_proc; ++i) + { + res[i].add_range(begin, begin + sizes[i]); + begin = begin + sizes[i]; + } + + return res; + } + + + std::vector compute_point_to_point_communication_pattern( const MPI_Comm & mpi_comm, @@ -484,6 +509,14 @@ namespace Utilities } + std::vector + create_ascending_partitioning(const MPI_Comm & /*comm*/, + const IndexSet::size_type &local_size) + { + return std::vector(1, complete_index_set(local_size)); + } + + MPI_Comm duplicate_communicator(const MPI_Comm &mpi_communicator) { diff --git a/tests/base/mpi_create_partitioning_01.cc b/tests/base/mpi_create_partitioning_01.cc new file mode 100644 index 000000000000..6ca9f6de4437 --- /dev/null +++ b/tests/base/mpi_create_partitioning_01.cc @@ -0,0 +1,80 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2017 - 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. +// +// --------------------------------------------------------------------- + +// Test Utilities::MPI::create_ascending_partitioning() + +#include +#include + +#include + +#include "../tests.h" + +void +test() +{ + MPI_Comm comm(MPI_COMM_WORLD); + const auto my_proc = Utilities::MPI::this_mpi_process(comm); + const auto n_proc = Utilities::MPI::n_mpi_processes(comm); + + const auto my_size = (my_proc == 2 ? 0 : my_proc * 2 + 5); + const auto vec = Utilities::MPI::create_ascending_partitioning(comm, my_size); + + // correct number: + AssertThrow(vec.size() == n_proc, ExcInternalError()); + + // ascending one-to-one + AssertThrow(vec[my_proc].is_ascending_and_one_to_one(comm), + ExcInternalError()); + + // same size: + const auto size = vec[0].size(); + for (unsigned int i = 1; i < vec.size(); ++i) + AssertThrow(size == vec[i].size(), ExcInternalError()); + + // 1:1 + for (unsigned int i = 0; i < vec.size(); ++i) + for (unsigned int j = i + 1; j < vec.size(); ++j) + { + const IndexSet intersection = vec[i] & vec[j]; + AssertThrow(intersection.is_empty(), ExcInternalError()); + } + + // union of all + IndexSet all(size); + for (unsigned int i = 0; i < vec.size(); ++i) + all.add_indices(vec[i]); + + AssertThrow(all == complete_index_set(size), ExcInternalError()); + + // finally print: + deallog << "Total size=" << size << std::endl; + for (unsigned int p = 0; p < vec.size(); ++p) + { + deallog << "p=" << p << ":" << std::endl; + vec[p].print(deallog.get_file_stream()); + } +} + +int +main(int argc, char *argv[]) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + MPILogInitAll log; + + test(); + return 0; +} diff --git a/tests/base/mpi_create_partitioning_01.mpirun=2.output b/tests/base/mpi_create_partitioning_01.mpirun=2.output new file mode 100644 index 000000000000..9075cba86e4a --- /dev/null +++ b/tests/base/mpi_create_partitioning_01.mpirun=2.output @@ -0,0 +1,13 @@ + +DEAL:0::Total size=12 +DEAL:0::p=0: +{[0,4]} +DEAL:0::p=1: +{[5,11]} + +DEAL:1::Total size=12 +DEAL:1::p=0: +{[0,4]} +DEAL:1::p=1: +{[5,11]} + diff --git a/tests/base/mpi_create_partitioning_01.mpirun=4.output b/tests/base/mpi_create_partitioning_01.mpirun=4.output new file mode 100644 index 000000000000..7ac455243e9d --- /dev/null +++ b/tests/base/mpi_create_partitioning_01.mpirun=4.output @@ -0,0 +1,43 @@ + +DEAL:0::Total size=23 +DEAL:0::p=0: +{[0,4]} +DEAL:0::p=1: +{[5,11]} +DEAL:0::p=2: +{} +DEAL:0::p=3: +{[12,22]} + +DEAL:1::Total size=23 +DEAL:1::p=0: +{[0,4]} +DEAL:1::p=1: +{[5,11]} +DEAL:1::p=2: +{} +DEAL:1::p=3: +{[12,22]} + + +DEAL:2::Total size=23 +DEAL:2::p=0: +{[0,4]} +DEAL:2::p=1: +{[5,11]} +DEAL:2::p=2: +{} +DEAL:2::p=3: +{[12,22]} + + +DEAL:3::Total size=23 +DEAL:3::p=0: +{[0,4]} +DEAL:3::p=1: +{[5,11]} +DEAL:3::p=2: +{} +DEAL:3::p=3: +{[12,22]} + diff --git a/tests/base/mpi_create_partitioning_01.output b/tests/base/mpi_create_partitioning_01.output new file mode 100644 index 000000000000..4d10ab83b3fa --- /dev/null +++ b/tests/base/mpi_create_partitioning_01.output @@ -0,0 +1,4 @@ + +DEAL:0::Total size=5 +DEAL:0::p=0: +{[0,4]} From f519cfaa2451e4248be759c08cdac60064d2b3ec Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Fri, 22 Mar 2019 09:35:20 +0100 Subject: [PATCH 307/507] Rename the helper classes in the Differentiation::AD namespace --- .../changes/major/20180827Jean-PaulPelteret | 2 +- .../changes/major/20180930Jean-PaulPelteret | 2 +- .../changes/major/20190220Jean-PaulPelteret | 2 +- .../changes/major/20190321Jean-PaulPelteret | 2 +- .../deal.II/differentiation/ad/ad_helpers.h | 198 ++++++------ source/differentiation/ad/ad_helpers.cc | 281 +++++++++--------- source/differentiation/ad/ad_helpers.inst1.in | 84 +++--- source/differentiation/ad/ad_helpers.inst2.in | 140 ++++----- .../step-44-helper_res_lin_01.h | 4 +- .../step-44-helper_var_form_01.h | 4 +- 10 files changed, 348 insertions(+), 371 deletions(-) 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/20190220Jean-PaulPelteret b/doc/news/changes/major/20190220Jean-PaulPelteret index c9df4e7cb7ca..3a0e37fe0de4 100644 --- a/doc/news/changes/major/20190220Jean-PaulPelteret +++ b/doc/news/changes/major/20190220Jean-PaulPelteret @@ -1,4 +1,4 @@ -New: A new class Differentiation::AD::ADHelperScalarFunction has been +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 diff --git a/doc/news/changes/major/20190321Jean-PaulPelteret b/doc/news/changes/major/20190321Jean-PaulPelteret index 54b796a6d6b7..80e70e9e662a 100644 --- a/doc/news/changes/major/20190321Jean-PaulPelteret +++ b/doc/news/changes/major/20190321Jean-PaulPelteret @@ -1,4 +1,4 @@ -New: A new class Differentiation::AD::ADHelperVectorFunction has been +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 diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index 7619901a82bc..507803a0dcf0 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -169,7 +169,7 @@ namespace Differentiation */ template - class ADHelperBase + class HelperBase { public: /** @@ -205,13 +205,13 @@ namespace Differentiation * be the number of outputs $\mathbf{f}$, i.e., the dimension of the * image space. */ - ADHelperBase(const unsigned int n_independent_variables, - const unsigned int n_dependent_variables); + HelperBase(const unsigned int n_independent_variables, + const unsigned int n_dependent_variables); /** * Destructor */ - virtual ~ADHelperBase() = default; + virtual ~HelperBase() = default; //@} @@ -279,7 +279,7 @@ namespace Differentiation * Pre-specify the number of @p independent_variables to be used in * tapeless mode. * - * Although this function is called internally in the ADHelperBase + * Although this function is called internally in the HelperBase * constructor, there may be occasions when ADOL-C tapeless numbers * (adtl::adoubles) are created before an instance of this class * is created. This function therefore allows one to declare at the @@ -307,7 +307,7 @@ namespace Differentiation /** * Reset the state of the helper class. * - * When an instance of an ADHelperBase is stored as a class member object + * When an instance of an HelperBase is stored as a class member object * with the intention to reuse its instance, it may be necessary to reset * the state of the object before use. This is because, internally, there * is error checking performed to ensure that the correct @@ -788,7 +788,7 @@ namespace Differentiation //@} - }; // class ADHelperBase + }; // class HelperBase @@ -824,8 +824,8 @@ namespace Differentiation * @endcode * Note that the quotation marks are mandatory. * An alternative approach that allows for run-time decision making is to - * use the ADHelperBase::set_tape_buffer_sizes() function before starting - * taping (as done via the ADHelperBase::start_recording_operations() + * use the HelperBase::set_tape_buffer_sizes() function before starting + * taping (as done via the HelperBase::start_recording_operations() * function). * * @warning ADOL-C does not support the standard threading models used by @@ -837,8 +837,7 @@ namespace Differentiation */ template - class ADHelperCellLevelBase - : public ADHelperBase + class CellLevelBase : public HelperBase { public: /** @@ -846,14 +845,14 @@ namespace Differentiation * and results from, all computations. */ using scalar_type = - typename ADHelperBase::scalar_type; + typename HelperBase::scalar_type; /** * Type definition for the auto-differentiation number type that is used * in all computations. */ using ad_type = - typename ADHelperBase::ad_type; + typename HelperBase::ad_type; /** * @name Constructor / destructor @@ -874,13 +873,13 @@ namespace Differentiation * be the number of outputs $\mathbf{f}$, i.e., the dimension of the * image space. */ - ADHelperCellLevelBase(const unsigned int n_independent_variables, - const unsigned int n_dependent_variables); + CellLevelBase(const unsigned int n_independent_variables, + const unsigned int n_dependent_variables); /** * Destructor */ - virtual ~ADHelperCellLevelBase() = default; + virtual ~CellLevelBase() = default; //@} @@ -976,7 +975,7 @@ namespace Differentiation * correspond with the @p ScalarType prescribed as a template argument. * * @note If the @p keep_independent_values flag has been set when - * ADHelperBase::start_recording_operations() is called then the tape is + * HelperBase::start_recording_operations() is called then the tape is * immediately usable after creation, and the values of the independent * variables set by register_dof_values() are those at which the function * is to be evaluated. In this case, a separate call to this function is @@ -996,7 +995,7 @@ namespace Differentiation * typically obtained by calling cell->get_dof_indices(). * * @note If the @p keep_independent_values flag has been set when - * ADHelperBase::start_recording_operations() is called then the tape is + * HelperBase::start_recording_operations() is called then the tape is * immediately usable after creation, and the values of the independent * variables set by register_dof_values() are those at which the function * is to be evaluated. In this case, a separate call to this function is @@ -1054,7 +1053,7 @@ namespace Differentiation //@} - }; // class ADHelperCellLevelBase + }; // class CellLevelBase @@ -1091,7 +1090,7 @@ namespace Differentiation * // Create some aliases for the AD helper. * // In the example, the AD_typecode used for the template argument can * // be refer to either a taped or tapeless type. - * using ADHelper = AD::ADHelperEnergyFunctional<...>; + * using ADHelper = AD::EnergyFunctional<...>; * using ADNumberType = typename ADHelper::ad_type; * * // Create and initialize an instance of the helper class. @@ -1222,8 +1221,7 @@ namespace Differentiation */ template - class ADHelperEnergyFunctional - : public ADHelperCellLevelBase + class EnergyFunctional : public CellLevelBase { public: /** @@ -1231,14 +1229,14 @@ namespace Differentiation * and results from, all computations. */ using scalar_type = - typename ADHelperBase::scalar_type; + typename HelperBase::scalar_type; /** * Type definition for the auto-differentiation number type that is used * in all computations. */ using ad_type = - typename ADHelperBase::ad_type; + typename HelperBase::ad_type; /** * @name Constructor / destructor @@ -1260,12 +1258,12 @@ namespace Differentiation * is computed from the first and second derivatives of a scalar * function $\Psi(\mathbf{X})$. */ - ADHelperEnergyFunctional(const unsigned int n_independent_variables); + EnergyFunctional(const unsigned int n_independent_variables); /** * Destructor */ - virtual ~ADHelperEnergyFunctional() = default; + virtual ~EnergyFunctional() = default; //@} @@ -1298,7 +1296,7 @@ namespace Differentiation * @f] * * The values at the evaluation point $\mathbf{X}$ are obtained by calling - * ADHelperCellLevelBase::set_dof_values(). + * CellLevelBase::set_dof_values(). * * @return The value of the energy functional at the evaluation point * corresponding to a chosen set of local degree of freedom values. @@ -1318,7 +1316,7 @@ namespace Differentiation * @f] * * The values at the evaluation point $\mathbf{X}$ are obtained by calling - * ADHelperCellLevelBase::set_dof_values(). + * CellLevelBase::set_dof_values(). * * @param[out] residual A Vector object, for which the value for each * entry represents the residual value for the corresponding local @@ -1341,7 +1339,7 @@ namespace Differentiation * @f] * * The values at the evaluation point $\mathbf{X}$ are obtained by calling - * ADHelperCellLevelBase::set_dof_values(). + * CellLevelBase::set_dof_values(). * * @param[out] linearization A FullMatrix representing the linearization * of the residual vector. The output @p linearization matrix has @@ -1354,7 +1352,7 @@ namespace Differentiation //@} - }; // class ADHelperEnergyFunctional + }; // class EnergyFunctional @@ -1398,9 +1396,9 @@ namespace Differentiation * // In this example, we strictly assume that we're using tapeless * // AD types, and so the AD_typecode used in the template argument * // must refer to one of these types. See the example for the - * // ADHelperEnergyFunctional for details on how to extend + * // EnergyFunctional for details on how to extend * // support to taped AD numbers. - * using ADHelper = AD::ADHelperResidualLinearization<...>; + * using ADHelper = AD::ResidualLinearization<...>; * using ADNumberType = typename ADHelper::ad_type; * * // Create and initialize an instance of the helper class. @@ -1538,8 +1536,8 @@ namespace Differentiation */ template - class ADHelperResidualLinearization - : public ADHelperCellLevelBase + class ResidualLinearization + : public CellLevelBase { public: /** @@ -1547,14 +1545,14 @@ namespace Differentiation * and results from, all computations. */ using scalar_type = - typename ADHelperBase::scalar_type; + typename HelperBase::scalar_type; /** * Type definition for the auto-differentiation number type that is used * in all computations. */ using ad_type = - typename ADHelperBase::ad_type; + typename HelperBase::ad_type; /** * @name Constructor / destructor @@ -1575,13 +1573,13 @@ namespace Differentiation * be the number of outputs $\mathbf{r}$, i.e., the dimension of the * image space. */ - ADHelperResidualLinearization(const unsigned int n_independent_variables, - const unsigned int n_dependent_variables); + ResidualLinearization(const unsigned int n_independent_variables, + const unsigned int n_dependent_variables); /** * Destructor */ - virtual ~ADHelperResidualLinearization() = default; + virtual ~ResidualLinearization() = default; //@} @@ -1615,7 +1613,7 @@ namespace Differentiation * @f] * * The values at the evaluation point $\mathbf{X}$ are obtained by calling - * ADHelperCellLevelBase::set_dof_values(). + * CellLevelBase::set_dof_values(). * * @param[out] residual A Vector object, for which the value for each * entry represents the residual value for the corresponding local @@ -1635,7 +1633,7 @@ namespace Differentiation * @f] * * The values at the evaluation point $\mathbf{X}$ are obtained by calling - * ADHelperCellLevelBase::set_dof_values(). + * CellLevelBase::set_dof_values(). * * @param[out] linearization A FullMatrix representing the linearization * of the residual vector. The output @p linearization matrix has @@ -1648,7 +1646,7 @@ namespace Differentiation //@} - }; // class ADHelperResidualLinearization + }; // class ResidualLinearization @@ -2623,7 +2621,7 @@ namespace Differentiation /** * A base helper class that facilitates the evaluation of point-wise defined * functions. This is the point-wise counterpart of the - * ADHelperCellLevelBase class, and was conceived for computations at a + * CellLevelBase class, and was conceived for computations at a * continuum point, or quadrature point, rather than for finite-element * level calculations. That being said, the interface to this and the * derived classes are sufficiently generic that the dependent function(s) @@ -2646,8 +2644,8 @@ namespace Differentiation template - class ADHelperPointLevelFunctionsBase - : public ADHelperBase + class PointLevelFunctionsBase + : public HelperBase { public: /** @@ -2661,14 +2659,14 @@ namespace Differentiation * and results from, all computations. */ using scalar_type = - typename ADHelperBase::scalar_type; + typename HelperBase::scalar_type; /** * Type definition for the auto-differentiation number type that is used * in all computations. */ using ad_type = - typename ADHelperBase::ad_type; + typename HelperBase::ad_type; /** * @name Constructor / destructor @@ -2689,14 +2687,13 @@ namespace Differentiation * be the number of outputs $\mathbf{f}$, i.e., the dimension of the * image space. */ - ADHelperPointLevelFunctionsBase( - const unsigned int n_independent_variables, - const unsigned int n_dependent_variables); + PointLevelFunctionsBase(const unsigned int n_independent_variables, + const unsigned int n_dependent_variables); /** * Destructor */ - virtual ~ADHelperPointLevelFunctionsBase() = default; + virtual ~PointLevelFunctionsBase() = default; //@} @@ -2706,7 +2703,7 @@ namespace Differentiation //@{ /** - * @copydoc ADHelperBase::reset() + * @copydoc HelperBase::reset() */ virtual void reset(const unsigned int n_independent_variables = @@ -2837,7 +2834,7 @@ namespace Differentiation * correspond with the @p ScalarType prescribed as a template argument. * * @note If the @p keep_independent_values flag has been set when - * ADHelperBase::start_recording_operations() is called then the tape is + * HelperBase::start_recording_operations() is called then the tape is * immediately usable after creation, and the values of the independent * variables set by register_independent_variables() are those at which * the function is to be evaluated. In this case, a separate call to this @@ -2866,7 +2863,7 @@ namespace Differentiation * be an FEValuesExtractors::Vector or FEValuesExtractors::Tensor<1>. * * @note If the @p keep_independent_values flag has been set when - * ADHelperBase::start_recording_operations() is called then the tape is + * HelperBase::start_recording_operations() is called then the tape is * immediately usable after creation, and the values of the independent * variables set by register_independent_variable() are those at which the * function is to be evaluated. In this case, a separate call to this @@ -2931,7 +2928,7 @@ namespace Differentiation //@} - }; // class ADHelperPointLevelFunctionsBase + }; // class PointLevelFunctionsBase @@ -2964,7 +2961,7 @@ namespace Differentiation * // Define the helper that we will use in the AD computations for our * // scalar energy function. Note that we expect it to return values of * // type double. - * ADHelperScalarFunction ad_helper (n_independent_variables); + * ScalarFunction ad_helper (n_independent_variables); * using ADNumberType = typename ADHelper::ad_type; * * // Compute the fields that provide the independent values. @@ -3094,10 +3091,8 @@ namespace Differentiation template - class ADHelperScalarFunction - : public ADHelperPointLevelFunctionsBase + class ScalarFunction + : public PointLevelFunctionsBase { public: /** @@ -3105,14 +3100,14 @@ namespace Differentiation * and results from, all computations. */ using scalar_type = - typename ADHelperBase::scalar_type; + typename HelperBase::scalar_type; /** * Type definition for the auto-differentiation number type that is used * in all computations. */ using ad_type = - typename ADHelperBase::ad_type; + typename HelperBase::ad_type; /** * @name Constructor / destructor @@ -3128,12 +3123,12 @@ namespace Differentiation * $\mathbf{f}(\mathbf{X})$, this will be the number of inputs * $\mathbf{X}$, i.e., the dimension of the domain space. */ - ADHelperScalarFunction(const unsigned int n_independent_variables); + ScalarFunction(const unsigned int n_independent_variables); /** * Destructor. */ - virtual ~ADHelperScalarFunction() = default; + virtual ~ScalarFunction() = default; //@} @@ -3323,7 +3318,7 @@ namespace Differentiation //@} - }; // class ADHelperScalarFunction + }; // class ScalarFunction @@ -3366,7 +3361,7 @@ namespace Differentiation * // Define the helper that we will use in the AD computations for our * // scalar energy function. Note that we expect it to return values of * // type double. - * ADHelperVectorFunction ad_helper (n_independent_variables, + * VectorFunction ad_helper (n_independent_variables, * n_dependent_variables); * using ADNumberType = typename ADHelper::ad_type; * @@ -3489,10 +3484,8 @@ namespace Differentiation template - class ADHelperVectorFunction - : public ADHelperPointLevelFunctionsBase + class VectorFunction + : public PointLevelFunctionsBase { public: /** @@ -3500,14 +3493,14 @@ namespace Differentiation * and results from, all computations. */ using scalar_type = - typename ADHelperBase::scalar_type; + typename HelperBase::scalar_type; /** * Type definition for the auto-differentiation number type that is used * in all computations. */ using ad_type = - typename ADHelperBase::ad_type; + typename HelperBase::ad_type; /** * @name Constructor / destructor @@ -3528,13 +3521,13 @@ namespace Differentiation * be the number of outputs $\mathbf{f}$, i.e., the dimension of the * image space. */ - ADHelperVectorFunction(const unsigned int n_independent_variables, - const unsigned int n_dependent_variables); + VectorFunction(const unsigned int n_independent_variables, + const unsigned int n_dependent_variables); /** * Destructor. */ - virtual ~ADHelperVectorFunction() = default; + virtual ~VectorFunction() = default; //@} @@ -3726,7 +3719,7 @@ namespace Differentiation //@} - }; // class ADHelperVectorFunction + }; // class VectorFunction } // namespace AD @@ -3742,14 +3735,14 @@ namespace Differentiation { namespace AD { - /* ----------------- ADHelperCellLevelBase ----------------- */ + /* ----------------- CellLevelBase ----------------- */ template template void - ADHelperCellLevelBase::register_dof_values( + CellLevelBase::register_dof_values( const VectorType & values, const std::vector &local_dof_indices) { @@ -3774,7 +3767,7 @@ namespace Differentiation template template void - ADHelperCellLevelBase::set_dof_values( + CellLevelBase::set_dof_values( const VectorType & values, const std::vector &local_dof_indices) { @@ -3782,13 +3775,13 @@ namespace Differentiation ExcMessage( "Vector size does not match number of independent variables")); for (unsigned int i = 0; i < this->n_independent_variables(); ++i) - ADHelperBase::set_sensitivity_value( + HelperBase::set_sensitivity_value( i, values[local_dof_indices[i]]); } - /* ----------------- ADHelperPointLevelFunctionsBase ----------------- */ + /* ----------------- PointLevelFunctionsBase ----------------- */ @@ -3797,7 +3790,7 @@ namespace Differentiation typename ScalarType> template void - ADHelperPointLevelFunctionsBase:: + PointLevelFunctionsBase:: register_independent_variable(const ValueType & value, const ExtractorType &extractor) { @@ -3833,7 +3826,7 @@ namespace Differentiation typename ScalarType> template void - ADHelperPointLevelFunctionsBase:: + PointLevelFunctionsBase:: set_independent_variable(const ValueType & value, const ExtractorType &extractor) { @@ -3855,8 +3848,8 @@ namespace Differentiation typename ScalarType> template typename internal::Extractor::template tensor_type< - typename ADHelperBase::ad_type> - ADHelperPointLevelFunctionsBase:: + typename HelperBase::ad_type> + PointLevelFunctionsBase:: get_sensitive_variables(const ExtractorType &extractor) const { if (ADNumberTraits::is_taped == true) @@ -3895,7 +3888,7 @@ namespace Differentiation - /* ----------------- ADHelperScalarFunction ----------------- */ + /* ----------------- ScalarFunction ----------------- */ @@ -3905,10 +3898,9 @@ namespace Differentiation template typename internal::ScalarFieldGradient< dim, - typename ADHelperScalarFunction:: - scalar_type, + typename ScalarFunction::scalar_type, ExtractorType_Row>::type - ADHelperScalarFunction:: + ScalarFunction:: extract_gradient_component(const Vector &gradient, const ExtractorType_Row & extractor_row) { @@ -3937,11 +3929,10 @@ namespace Differentiation template typename internal::ScalarFieldHessian< dim, - typename ADHelperScalarFunction:: - scalar_type, + typename ScalarFunction::scalar_type, ExtractorType_Row, ExtractorType_Col>::type - ADHelperScalarFunction:: + ScalarFunction:: extract_hessian_component(const FullMatrix &hessian, const ExtractorType_Row & extractor_row, const ExtractorType_Col & extractor_col) @@ -3996,7 +3987,7 @@ namespace Differentiation - /* ----------------- ADHelperVectorFunction ----------------- */ + /* ----------------- VectorFunction ----------------- */ @@ -4005,7 +3996,7 @@ namespace Differentiation typename ScalarType> template void - ADHelperVectorFunction:: + VectorFunction:: register_dependent_variable(const ValueType & funcs, const ExtractorType &extractor) { @@ -4016,9 +4007,8 @@ namespace Differentiation Assert(this->registered_marked_dependent_variables[index_set[i]] == false, ExcMessage("Overlapping indices for dependent variables.")); - ADHelperBase:: - register_dependent_variable(index_set[i], - internal::get_tensor_entry(funcs, i)); + HelperBase::register_dependent_variable( + index_set[i], internal::get_tensor_entry(funcs, i)); } } @@ -4030,12 +4020,11 @@ namespace Differentiation template typename internal::VectorFieldValue< dim, - typename ADHelperVectorFunction:: - scalar_type, + typename VectorFunction::scalar_type, ExtractorType_Row>::type - ADHelperVectorFunction:: - extract_value_component(const Vector &values, - const ExtractorType_Row & extractor_row) + VectorFunction::extract_value_component( + const Vector &values, + const ExtractorType_Row & extractor_row) { // NOTE: The order of components must be consistently defined throughout // this class. @@ -4062,11 +4051,10 @@ namespace Differentiation template typename internal::VectorFieldJacobian< dim, - typename ADHelperVectorFunction:: - scalar_type, + typename VectorFunction::scalar_type, ExtractorType_Row, ExtractorType_Col>::type - ADHelperVectorFunction:: + VectorFunction:: extract_jacobian_component(const FullMatrix &jacobian, const ExtractorType_Row & extractor_row, const ExtractorType_Col & extractor_col) diff --git a/source/differentiation/ad/ad_helpers.cc b/source/differentiation/ad/ad_helpers.cc index 4d67b34ad7f9..fac44b98a5bd 100644 --- a/source/differentiation/ad/ad_helpers.cc +++ b/source/differentiation/ad/ad_helpers.cc @@ -30,12 +30,12 @@ namespace Differentiation { namespace AD { - /* -------------------------- ADHelperBase -------------------------- */ + /* -------------------------- HelperBase -------------------------- */ template - ADHelperBase::ADHelperBase( + HelperBase::HelperBase( const unsigned int n_independent_variables, const unsigned int n_dependent_variables) : independent_variable_values( @@ -65,8 +65,8 @@ namespace Differentiation template void - ADHelperBase::reset_registered_independent_variables() + HelperBase::reset_registered_independent_variables() { for (typename std::vector::iterator it = registered_independent_variable_values.begin(); @@ -79,7 +79,7 @@ namespace Differentiation template void - ADHelperBase:: + HelperBase:: reset_registered_dependent_variables(const bool flag) { for (typename std::vector::iterator it = @@ -93,7 +93,7 @@ namespace Differentiation template void - ADHelperBase::set_sensitivity_value( + HelperBase::set_sensitivity_value( const unsigned int index, const scalar_type &value) { @@ -130,7 +130,7 @@ namespace Differentiation template void - ADHelperBase::mark_independent_variable( + HelperBase::mark_independent_variable( const unsigned int index, ad_type & out) const { @@ -168,8 +168,8 @@ namespace Differentiation template void - ADHelperBase::finalize_sensitive_independent_variables() const + HelperBase::finalize_sensitive_independent_variables() const { // Double check that we've actually registered all DoFs Assert(n_registered_independent_variables() == n_independent_variables(), @@ -192,7 +192,7 @@ namespace Differentiation template void - ADHelperBase:: + HelperBase:: initialize_non_sensitive_independent_variable(const unsigned int index, ad_type &out) const { @@ -217,8 +217,8 @@ namespace Differentiation template unsigned int - ADHelperBase::n_registered_independent_variables() const + HelperBase::n_registered_independent_variables() const { return std::count(registered_independent_variable_values.begin(), registered_independent_variable_values.end(), @@ -229,7 +229,7 @@ namespace Differentiation template std::size_t - ADHelperBase::n_independent_variables() const + HelperBase::n_independent_variables() const { return independent_variable_values.size(); } @@ -238,8 +238,8 @@ namespace Differentiation template unsigned int - ADHelperBase::n_registered_dependent_variables() const + HelperBase::n_registered_dependent_variables() + const { return std::count(registered_marked_dependent_variables.begin(), registered_marked_dependent_variables.end(), @@ -250,7 +250,7 @@ namespace Differentiation template std::size_t - ADHelperBase::n_dependent_variables() const + HelperBase::n_dependent_variables() const { return dependent_variables.size(); } @@ -259,7 +259,7 @@ namespace Differentiation template bool - ADHelperBase::is_recording() const + HelperBase::is_recording() const { if (AD::is_taped_ad_number::value) return taped_driver.is_recording(); @@ -271,8 +271,8 @@ namespace Differentiation template typename Types< - typename ADHelperBase::ad_type>::tape_index - ADHelperBase::active_tape_index() const + typename HelperBase::ad_type>::tape_index + HelperBase::active_tape_index() const { if (AD::is_taped_ad_number::value) return taped_driver.active_tape_index(); @@ -284,7 +284,7 @@ namespace Differentiation template bool - ADHelperBase::is_registered_tape( + HelperBase::is_registered_tape( const typename Types::tape_index tape_index) const { if (AD::is_taped_ad_number::value) @@ -297,8 +297,7 @@ namespace Differentiation template void - ADHelperBase::print( - std::ostream &stream) const + HelperBase::print(std::ostream &stream) const { // Store stream flags const std::ios_base::fmtflags stream_flags(stream.flags()); @@ -353,7 +352,7 @@ namespace Differentiation template void - ADHelperBase::print_values( + HelperBase::print_values( std::ostream &stream) const { for (unsigned int i = 0; i < n_independent_variables(); i++) @@ -367,7 +366,7 @@ namespace Differentiation template void - ADHelperBase::print_tape_stats( + HelperBase::print_tape_stats( const typename Types::tape_index tape_index, std::ostream & stream) const { @@ -384,7 +383,7 @@ namespace Differentiation template void - ADHelperBase::reset( + HelperBase::reset( const unsigned int n_independent_variables, const unsigned int n_dependent_variables, const bool clear_registered_tapes) @@ -442,7 +441,7 @@ namespace Differentiation template void - ADHelperBase::configure_tapeless_mode( + HelperBase::configure_tapeless_mode( const unsigned int n_independent_variables, const bool ensure_persistent_setting) { @@ -467,7 +466,7 @@ namespace Differentiation template void - ADHelperBase::activate_recorded_tape( + HelperBase::activate_recorded_tape( const typename Types::tape_index tape_index) { activate_tape(tape_index, true /*read_mode*/); @@ -477,7 +476,7 @@ namespace Differentiation template bool - ADHelperBase::recorded_tape_requires_retaping( + HelperBase::recorded_tape_requires_retaping( const typename Types::tape_index tape_index) const { if (ADNumberTraits::is_tapeless == true) @@ -490,7 +489,7 @@ namespace Differentiation template bool - ADHelperBase::active_tape_requires_retaping() + HelperBase::active_tape_requires_retaping() const { if (ADNumberTraits::is_tapeless == true) @@ -503,7 +502,7 @@ namespace Differentiation template void - ADHelperBase::clear_active_tape() + HelperBase::clear_active_tape() { if (ADNumberTraits::is_tapeless == true) return; @@ -515,7 +514,7 @@ namespace Differentiation template void - ADHelperBase::activate_tape( + HelperBase::activate_tape( const typename Types::tape_index tape_index, const bool read_mode) { @@ -552,7 +551,7 @@ namespace Differentiation template void - ADHelperBase::set_tape_buffer_sizes( + HelperBase::set_tape_buffer_sizes( const typename Types::tape_buffer_sizes obufsize, const typename Types::tape_buffer_sizes lbufsize, const typename Types::tape_buffer_sizes vbufsize, @@ -571,7 +570,7 @@ namespace Differentiation template bool - ADHelperBase::start_recording_operations( + HelperBase::start_recording_operations( const typename Types::tape_index tape_index, const bool overwrite_tape, const bool keep_independent_values) @@ -636,7 +635,7 @@ namespace Differentiation template void - ADHelperBase::stop_recording_operations( + HelperBase::stop_recording_operations( const bool write_tapes_to_file) { Assert(is_recording() == true, ExcMessage("Not currently recording...")); @@ -672,7 +671,7 @@ namespace Differentiation template void - ADHelperBase::register_dependent_variable( + HelperBase::register_dependent_variable( const unsigned int index, const ad_type & func) { @@ -698,23 +697,23 @@ namespace Differentiation - /* -------------------- ADHelperCellLevelBase -------------------- */ + /* -------------------- CellLevelBase -------------------- */ template - ADHelperCellLevelBase::ADHelperCellLevelBase( + CellLevelBase::CellLevelBase( const unsigned int n_independent_variables, const unsigned int n_dependent_variables) - : ADHelperBase(n_independent_variables, - n_dependent_variables) + : HelperBase(n_independent_variables, + n_dependent_variables) {} template void - ADHelperCellLevelBase::register_dof_values( + CellLevelBase::register_dof_values( const std::vector &dof_values) { // This is actually the same thing the set_independent_variable function, @@ -736,9 +735,9 @@ namespace Differentiation template const std::vector< - typename ADHelperCellLevelBase::ad_type> & - ADHelperCellLevelBase::get_sensitive_dof_values() const + typename CellLevelBase::ad_type> & + CellLevelBase::get_sensitive_dof_values() + const { if (ADNumberTraits::is_taped == true) { @@ -762,7 +761,7 @@ namespace Differentiation template void - ADHelperCellLevelBase::set_dof_values( + CellLevelBase::set_dof_values( const std::vector &values) { if (ADNumberTraits::is_taped == true) @@ -775,42 +774,39 @@ namespace Differentiation ExcMessage( "Vector size does not match number of independent variables")); for (unsigned int i = 0; i < this->n_independent_variables(); ++i) - ADHelperBase::set_sensitivity_value( + HelperBase::set_sensitivity_value( i, values[i]); } - /* ------------------ ADHelperEnergyFunctional ------------------ */ + /* ------------------ EnergyFunctional ------------------ */ template - ADHelperEnergyFunctional:: - ADHelperEnergyFunctional(const unsigned int n_independent_variables) - : ADHelperCellLevelBase( - n_independent_variables, - 1) + EnergyFunctional::EnergyFunctional( + const unsigned int n_independent_variables) + : CellLevelBase(n_independent_variables, 1) {} template void - ADHelperEnergyFunctional:: - register_energy_functional(const ad_type &energy) + EnergyFunctional::register_energy_functional( + const ad_type &energy) { Assert(this->n_dependent_variables() == 1, ExcInternalError()); - ADHelperBase::register_dependent_variable( + HelperBase::register_dependent_variable( 0, energy); } template - typename ADHelperEnergyFunctional::scalar_type - ADHelperEnergyFunctional::compute_energy() - const + typename EnergyFunctional::scalar_type + EnergyFunctional::compute_energy() const { if ((ADNumberTraits::is_taped == true && this->taped_driver.keep_independent_values() == false) || @@ -829,7 +825,7 @@ namespace Differentiation Assert( this->n_dependent_variables() == 1, ExcMessage( - "The ADHelperEnergyFunctional class expects there to be only one dependent variable.")); + "The EnergyFunctional class expects there to be only one dependent variable.")); if (ADNumberTraits::is_taped == true) { @@ -864,7 +860,7 @@ namespace Differentiation template void - ADHelperEnergyFunctional::compute_residual( + EnergyFunctional::compute_residual( Vector &gradient) const { if ((ADNumberTraits::is_taped == true && @@ -884,7 +880,7 @@ namespace Differentiation Assert( this->n_dependent_variables() == 1, ExcMessage( - "The ADHelperEnergyFunctional class expects there to be only one dependent variable.")); + "The EnergyFunctional class expects there to be only one dependent variable.")); // We can neglect correctly initializing the entries as // we'll be overwriting them immediately in the succeeding call to @@ -929,8 +925,8 @@ namespace Differentiation template void - ADHelperEnergyFunctional:: - compute_linearization(FullMatrix &hessian) const + EnergyFunctional::compute_linearization( + FullMatrix &hessian) const { Assert(AD::ADNumberTraits::n_supported_derivative_levels >= 2, ExcMessage( @@ -953,7 +949,7 @@ namespace Differentiation Assert( this->n_dependent_variables() == 1, ExcMessage( - "The ADHelperEnergyFunctional class expects there to be only one dependent variable.")); + "The EnergyFunctional class expects there to be only one dependent variable.")); // We can neglect correctly initializing the entries as // we'll be overwriting them immediately in the succeeding call to @@ -997,31 +993,30 @@ namespace Differentiation } - /* ------------------- ADHelperResidualLinearization ------------------- */ + /* ------------------- ResidualLinearization ------------------- */ template - ADHelperResidualLinearization:: - ADHelperResidualLinearization(const unsigned int n_independent_variables, - const unsigned int n_dependent_variables) - : ADHelperCellLevelBase( - n_independent_variables, - n_dependent_variables) + ResidualLinearization::ResidualLinearization( + const unsigned int n_independent_variables, + const unsigned int n_dependent_variables) + : CellLevelBase(n_independent_variables, + n_dependent_variables) {} template void - ADHelperResidualLinearization:: + ResidualLinearization:: register_residual_vector(const std::vector &residual) { Assert(residual.size() == this->n_dependent_variables(), ExcMessage( "Vector size does not match number of dependent variables")); for (unsigned int i = 0; i < this->n_dependent_variables(); ++i) - ADHelperBase::register_dependent_variable( + HelperBase::register_dependent_variable( i, residual[i]); } @@ -1029,8 +1024,8 @@ namespace Differentiation template void - ADHelperResidualLinearization:: - compute_residual(Vector &values) const + ResidualLinearization::compute_residual( + Vector &values) const { if ((ADNumberTraits::is_taped == true && this->taped_driver.keep_independent_values() == false) || @@ -1083,8 +1078,8 @@ namespace Differentiation template void - ADHelperResidualLinearization:: - compute_linearization(FullMatrix &jacobian) const + ResidualLinearization::compute_linearization( + FullMatrix &jacobian) const { if ((ADNumberTraits::is_taped == true && this->taped_driver.keep_independent_values() == false) || @@ -1144,19 +1139,18 @@ namespace Differentiation - /* ----------------- ADHelperPointLevelFunctionsBase ----------------- */ + /* ----------------- PointLevelFunctionsBase ----------------- */ template - ADHelperPointLevelFunctionsBase:: - ADHelperPointLevelFunctionsBase( - const unsigned int n_independent_variables, - const unsigned int n_dependent_variables) - : ADHelperBase(n_independent_variables, - n_dependent_variables) + PointLevelFunctionsBase:: + PointLevelFunctionsBase(const unsigned int n_independent_variables, + const unsigned int n_dependent_variables) + : HelperBase(n_independent_variables, + n_dependent_variables) , symmetric_independent_variables(n_independent_variables, false) {} @@ -1166,14 +1160,14 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> void - ADHelperPointLevelFunctionsBase::reset( + PointLevelFunctionsBase::reset( const unsigned int n_independent_variables, const unsigned int n_dependent_variables, const bool clear_registered_tapes) { - ADHelperBase::reset(n_independent_variables, - n_dependent_variables, - clear_registered_tapes); + HelperBase::reset(n_independent_variables, + n_dependent_variables, + clear_registered_tapes); const unsigned int new_n_independent_variables = (n_independent_variables != dealii::numbers::invalid_unsigned_int ? @@ -1189,7 +1183,7 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> bool - ADHelperPointLevelFunctionsBase:: + PointLevelFunctionsBase:: is_symmetric_independent_variable(const unsigned int index) const { Assert(index < symmetric_independent_variables.size(), @@ -1203,7 +1197,7 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> unsigned int - ADHelperPointLevelFunctionsBase:: + PointLevelFunctionsBase:: n_symmetric_independent_variables() const { return std::count(symmetric_independent_variables.begin(), @@ -1217,7 +1211,7 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> void - ADHelperPointLevelFunctionsBase:: + PointLevelFunctionsBase:: register_independent_variables(const std::vector &values) { // This is actually the same thing the set_independent_variable function, @@ -1240,11 +1234,10 @@ namespace Differentiation template - const std::vector< - typename ADHelperPointLevelFunctionsBase::ad_type> & - ADHelperPointLevelFunctionsBase:: + const std::vector::ad_type> & + PointLevelFunctionsBase:: get_sensitive_variables() const { if (ADNumberTraits::is_taped == true) @@ -1272,13 +1265,13 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> void - ADHelperPointLevelFunctionsBase:: + PointLevelFunctionsBase:: set_sensitivity_value(const unsigned int index, const bool symmetric_component, const scalar_type &value) { - ADHelperBase::set_sensitivity_value(index, - value); + HelperBase::set_sensitivity_value(index, + value); Assert( index < this->n_independent_variables(), ExcMessage( @@ -1294,7 +1287,7 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> void - ADHelperPointLevelFunctionsBase:: + PointLevelFunctionsBase:: set_independent_variables(const std::vector &values) { if (ADNumberTraits::is_taped == true) @@ -1307,22 +1300,22 @@ namespace Differentiation ExcMessage( "Vector size does not match number of independent variables")); for (unsigned int i = 0; i < this->n_independent_variables(); ++i) - ADHelperBase::set_sensitivity_value( + HelperBase::set_sensitivity_value( i, values[i]); } - /* -------------------- ADHelperScalarFunction -------------------- */ + /* -------------------- ScalarFunction -------------------- */ template - ADHelperScalarFunction:: - ADHelperScalarFunction(const unsigned int n_independent_variables) - : ADHelperPointLevelFunctionsBase( + ScalarFunction::ScalarFunction( + const unsigned int n_independent_variables) + : PointLevelFunctionsBase( n_independent_variables, 1) {} @@ -1333,11 +1326,11 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> void - ADHelperScalarFunction:: + ScalarFunction:: register_dependent_variable(const ad_type &func) { Assert(this->n_dependent_variables() == 1, ExcInternalError()); - ADHelperBase::register_dependent_variable( + HelperBase::register_dependent_variable( 0, func); } @@ -1346,10 +1339,8 @@ namespace Differentiation template - typename ADHelperScalarFunction:: - scalar_type - ADHelperScalarFunction::compute_value() - const + typename ScalarFunction::scalar_type + ScalarFunction::compute_value() const { if ((ADNumberTraits::is_taped == true && this->taped_driver.keep_independent_values() == false) || @@ -1368,7 +1359,7 @@ namespace Differentiation Assert( this->n_dependent_variables() == 1, ExcMessage( - "The ADHelperScalarFunction class expects there to be only one dependent variable.")); + "The ScalarFunction class expects there to be only one dependent variable.")); if (ADNumberTraits::is_taped == true) { @@ -1399,7 +1390,7 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> void - ADHelperScalarFunction::compute_gradient( + ScalarFunction::compute_gradient( Vector &gradient) const { if ((ADNumberTraits::is_taped == true && @@ -1419,7 +1410,7 @@ namespace Differentiation Assert( this->n_dependent_variables() == 1, ExcMessage( - "The ADHelperScalarFunction class expects there to be only one dependent variable.")); + "The ScalarFunction class expects there to be only one dependent variable.")); // We can neglect correctly initializing the entries as // we'll be overwriting them immediately in the succeeding call to @@ -1473,7 +1464,7 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> void - ADHelperScalarFunction::compute_hessian( + ScalarFunction::compute_hessian( FullMatrix &hessian) const { Assert(AD::ADNumberTraits::n_supported_derivative_levels >= 2, @@ -1497,7 +1488,7 @@ namespace Differentiation Assert( this->n_dependent_variables() == 1, ExcMessage( - "The ADHelperScalarFunction class expects there to be only one dependent variable.")); + "The ScalarFunction class expects there to be only one dependent variable.")); // We can neglect correctly initializing the entries as // we'll be overwriting them immediately in the succeeding call to @@ -1567,11 +1558,11 @@ namespace Differentiation template - Tensor<0, - dim, - typename ADHelperScalarFunction:: - scalar_type> - ADHelperScalarFunction:: + Tensor< + 0, + dim, + typename ScalarFunction::scalar_type> + ScalarFunction:: extract_hessian_component(const FullMatrix & hessian, const FEValuesExtractors::Scalar &extractor_row, const FEValuesExtractors::Scalar &extractor_col) @@ -1604,12 +1595,11 @@ namespace Differentiation template - SymmetricTensor<4, - dim, - typename ADHelperScalarFunction::scalar_type> - ADHelperScalarFunction:: + SymmetricTensor< + 4, + dim, + typename ScalarFunction::scalar_type> + ScalarFunction:: extract_hessian_component( const FullMatrix & hessian, const FEValuesExtractors::SymmetricTensor<2> &extractor_row, @@ -1641,17 +1631,17 @@ namespace Differentiation - /* -------------------- ADHelperVectorFunction -------------------- */ + /* -------------------- VectorFunction -------------------- */ template - ADHelperVectorFunction:: - ADHelperVectorFunction(const unsigned int n_independent_variables, - const unsigned int n_dependent_variables) - : ADHelperPointLevelFunctionsBase( + VectorFunction::VectorFunction( + const unsigned int n_independent_variables, + const unsigned int n_dependent_variables) + : PointLevelFunctionsBase( n_independent_variables, n_dependent_variables) {} @@ -1662,14 +1652,14 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> void - ADHelperVectorFunction:: + VectorFunction:: register_dependent_variables(const std::vector &funcs) { Assert(funcs.size() == this->n_dependent_variables(), ExcMessage( "Vector size does not match number of dependent variables")); for (unsigned int i = 0; i < this->n_dependent_variables(); ++i) - ADHelperBase::register_dependent_variable( + HelperBase::register_dependent_variable( i, funcs[i]); } @@ -1679,7 +1669,7 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> void - ADHelperVectorFunction::compute_values( + VectorFunction::compute_values( Vector &values) const { if ((ADNumberTraits::is_taped == true && @@ -1735,7 +1725,7 @@ namespace Differentiation enum AD::NumberTypes ADNumberTypeCode, typename ScalarType> void - ADHelperVectorFunction::compute_jacobian( + VectorFunction::compute_jacobian( FullMatrix &jacobian) const { if ((ADNumberTraits::is_taped == true && @@ -1809,11 +1799,11 @@ namespace Differentiation template - Tensor<0, - dim, - typename ADHelperVectorFunction:: - scalar_type> - ADHelperVectorFunction:: + Tensor< + 0, + dim, + typename VectorFunction::scalar_type> + VectorFunction:: extract_jacobian_component( const FullMatrix & jacobian, const FEValuesExtractors::Scalar &extractor_row, @@ -1847,12 +1837,11 @@ namespace Differentiation template - SymmetricTensor<4, - dim, - typename ADHelperVectorFunction::scalar_type> - ADHelperVectorFunction:: + SymmetricTensor< + 4, + dim, + typename VectorFunction::scalar_type> + VectorFunction:: extract_jacobian_component( const FullMatrix & jacobian, const FEValuesExtractors::SymmetricTensor<2> &extractor_row, diff --git a/source/differentiation/ad/ad_helpers.inst1.in b/source/differentiation/ad/ad_helpers.inst1.in index 1c1ff5a534b8..87a4356550e5 100644 --- a/source/differentiation/ad/ad_helpers.inst1.in +++ b/source/differentiation/ad/ad_helpers.inst1.in @@ -21,37 +21,37 @@ for (number : REAL_SCALARS) \{ namespace AD \{ - // -------------------------- ADHelperBase ---------------------- + // -------------------------- HelperBase ---------------------- template - class ADHelperBase; + class HelperBase; template - class ADHelperBase; + class HelperBase; - // -------------------------- ADHelperCellLevelBase ---------------------- + // -------------------------- CellLevelBase ---------------------- template - class ADHelperCellLevelBase; + class CellLevelBase; template - class ADHelperCellLevelBase; + class CellLevelBase; - // -------------------------- ADHelperEnergyFunctional ---------------------- + // -------------------------- EnergyFunctional ---------------------- template - class ADHelperEnergyFunctional; + class EnergyFunctional; template - class ADHelperEnergyFunctional; + class EnergyFunctional; - // -------------------------- ADHelperResidualLinearization ---------------------- + // -------------------------- ResidualLinearization ---------------------- template - class ADHelperResidualLinearization; + class ResidualLinearization; template - class ADHelperResidualLinearization; + class ResidualLinearization; \} \} @@ -65,37 +65,37 @@ for () namespace AD \{ - // -------------------------- ADHelperBase ---------------------- + // -------------------------- HelperBase ---------------------- template - class ADHelperBase::ad_type>; + class HelperBase::ad_type>; template - class ADHelperBase::ad_type>; + class HelperBase::ad_type>; - // -------------------------- ADHelperCellLevelBase ---------------------- + // -------------------------- CellLevelBase ---------------------- template - class ADHelperCellLevelBase::ad_type>; + class CellLevelBase::ad_type>; template - class ADHelperCellLevelBase::ad_type>; + class CellLevelBase::ad_type>; - // -------------------------- ADHelperEnergyFunctional ---------------------- + // -------------------------- EnergyFunctional ---------------------- template - class ADHelperEnergyFunctional::ad_type>; + class EnergyFunctional::ad_type>; template - class ADHelperEnergyFunctional::ad_type>; + class EnergyFunctional::ad_type>; - // -------------------------- ADHelperResidualLinearization ---------------------- + // -------------------------- ResidualLinearization ---------------------- template - class ADHelperResidualLinearization::ad_type>; + class ResidualLinearization::ad_type>; template - class ADHelperResidualLinearization::ad_type>; + class ResidualLinearization::ad_type>; \} @@ -109,29 +109,29 @@ for (deal_II_dimension : DIMENSIONS ; number : REAL_SCALARS) \{ namespace AD \{ - // -------------------------- ADHelperPointLevelFunctionsBase ---------------------- + // -------------------------- PointLevelFunctionsBase ---------------------- template - class ADHelperPointLevelFunctionsBase; + class PointLevelFunctionsBase; template - class ADHelperPointLevelFunctionsBase; + class PointLevelFunctionsBase; - // -------------------------- ADHelperScalarFunction ---------------------- + // -------------------------- ScalarFunction ---------------------- template - class ADHelperScalarFunction; + class ScalarFunction; template - class ADHelperScalarFunction; + class ScalarFunction; - // -------------------------- ADHelperVectorFunction ---------------------- + // -------------------------- VectorFunction ---------------------- template - class ADHelperVectorFunction; + class VectorFunction; template - class ADHelperVectorFunction; + class VectorFunction; \} \} @@ -145,29 +145,29 @@ for (deal_II_dimension : DIMENSIONS) namespace AD \{ - // -------------------------- ADHelperPointLevelFunctionsBase ---------------------- + // -------------------------- PointLevelFunctionsBase ---------------------- template - class ADHelperPointLevelFunctionsBase::ad_type>; + class PointLevelFunctionsBase::ad_type>; template - class ADHelperPointLevelFunctionsBase::ad_type>; + class PointLevelFunctionsBase::ad_type>; - // -------------------------- ADHelperScalarFunction ---------------------- + // -------------------------- ScalarFunction ---------------------- template - class ADHelperScalarFunction::ad_type>; + class ScalarFunction::ad_type>; template - class ADHelperScalarFunction::ad_type>; + class ScalarFunction::ad_type>; - // -------------------------- ADHelperVectorFunction ---------------------- + // -------------------------- VectorFunction ---------------------- template - class ADHelperVectorFunction::ad_type>; + class VectorFunction::ad_type>; template - class ADHelperVectorFunction::ad_type>; + class VectorFunction::ad_type>; \} \} diff --git a/source/differentiation/ad/ad_helpers.inst2.in b/source/differentiation/ad/ad_helpers.inst2.in index 800b697f99ae..a39f35029f2d 100644 --- a/source/differentiation/ad/ad_helpers.inst2.in +++ b/source/differentiation/ad/ad_helpers.inst2.in @@ -21,61 +21,61 @@ for (number : REAL_SCALARS) \{ namespace AD \{ - // -------------------------- ADHelperBase ---------------------- + // -------------------------- HelperBase ---------------------- template - class ADHelperBase; + class HelperBase; template - class ADHelperBase; + class HelperBase; template - class ADHelperBase; + class HelperBase; template - class ADHelperBase; + class HelperBase; - // -------------------------- ADHelperCellLevelBase ---------------------- + // -------------------------- CellLevelBase ---------------------- template - class ADHelperCellLevelBase; + class CellLevelBase; template - class ADHelperCellLevelBase; + class CellLevelBase; template - class ADHelperCellLevelBase; + class CellLevelBase; template - class ADHelperCellLevelBase; + class CellLevelBase; - // -------------------------- ADHelperEnergyFunctional ---------------------- + // -------------------------- EnergyFunctional ---------------------- template - class ADHelperEnergyFunctional; + class EnergyFunctional; template - class ADHelperEnergyFunctional; + class EnergyFunctional; template - class ADHelperEnergyFunctional; + class EnergyFunctional; template - class ADHelperEnergyFunctional; + class EnergyFunctional; - // -------------------------- ADHelperResidualLinearization ---------------------- + // -------------------------- ResidualLinearization ---------------------- template - class ADHelperResidualLinearization; + class ResidualLinearization; template - class ADHelperResidualLinearization; + class ResidualLinearization; template - class ADHelperResidualLinearization; + class ResidualLinearization; template - class ADHelperResidualLinearization; + class ResidualLinearization; \} \} @@ -89,61 +89,61 @@ for () namespace AD \{ - // -------------------------- ADHelperBase ---------------------- + // -------------------------- HelperBase ---------------------- template - class ADHelperBase::ad_type>; + class HelperBase::ad_type>; template - class ADHelperBase::ad_type>; + class HelperBase::ad_type>; template - class ADHelperBase::ad_type>; + class HelperBase::ad_type>; template - class ADHelperBase::ad_type>; + class HelperBase::ad_type>; - // -------------------------- ADHelperCellLevelBase ---------------------- + // -------------------------- CellLevelBase ---------------------- template - class ADHelperCellLevelBase::ad_type>; + class CellLevelBase::ad_type>; template - class ADHelperCellLevelBase::ad_type>; + class CellLevelBase::ad_type>; template - class ADHelperCellLevelBase::ad_type>; + class CellLevelBase::ad_type>; template - class ADHelperCellLevelBase::ad_type>; + class CellLevelBase::ad_type>; - // -------------------------- ADHelperEnergyFunctional ---------------------- + // -------------------------- EnergyFunctional ---------------------- template - class ADHelperEnergyFunctional::ad_type>; + class EnergyFunctional::ad_type>; template - class ADHelperEnergyFunctional::ad_type>; + class EnergyFunctional::ad_type>; template - class ADHelperEnergyFunctional::ad_type>; + class EnergyFunctional::ad_type>; template - class ADHelperEnergyFunctional::ad_type>; + class EnergyFunctional::ad_type>; - // -------------------------- ADHelperResidualLinearization ---------------------- + // -------------------------- ResidualLinearization ---------------------- template - class ADHelperResidualLinearization::ad_type>; + class ResidualLinearization::ad_type>; template - class ADHelperResidualLinearization::ad_type>; + class ResidualLinearization::ad_type>; template - class ADHelperResidualLinearization::ad_type>; + class ResidualLinearization::ad_type>; template - class ADHelperResidualLinearization::ad_type>; + class ResidualLinearization::ad_type>; \} @@ -158,47 +158,47 @@ for (deal_II_dimension : DIMENSIONS ; number : REAL_SCALARS) namespace AD \{ - // -------------------------- ADHelperPointLevelFunctionsBase ---------------------- + // -------------------------- PointLevelFunctionsBase ---------------------- template - class ADHelperPointLevelFunctionsBase; + class PointLevelFunctionsBase; template - class ADHelperPointLevelFunctionsBase; + class PointLevelFunctionsBase; template - class ADHelperPointLevelFunctionsBase; + class PointLevelFunctionsBase; template - class ADHelperPointLevelFunctionsBase; + class PointLevelFunctionsBase; - // -------------------------- ADHelperScalarFunction ---------------------- + // -------------------------- ScalarFunction ---------------------- template - class ADHelperScalarFunction; + class ScalarFunction; template - class ADHelperScalarFunction; + class ScalarFunction; template - class ADHelperScalarFunction; + class ScalarFunction; template - class ADHelperScalarFunction; + class ScalarFunction; - // -------------------------- ADHelperVectorFunction ---------------------- + // -------------------------- VectorFunction ---------------------- template - class ADHelperVectorFunction; + class VectorFunction; template - class ADHelperVectorFunction; + class VectorFunction; template - class ADHelperVectorFunction; + class VectorFunction; template - class ADHelperVectorFunction; + class VectorFunction; \} \} @@ -212,47 +212,47 @@ for (deal_II_dimension : DIMENSIONS) namespace AD \{ - // -------------------------- ADHelperPointLevelFunctionsBase ---------------------- + // -------------------------- PointLevelFunctionsBase ---------------------- template - class ADHelperPointLevelFunctionsBase::ad_type>; + class PointLevelFunctionsBase::ad_type>; template - class ADHelperPointLevelFunctionsBase::ad_type>; + class PointLevelFunctionsBase::ad_type>; template - class ADHelperPointLevelFunctionsBase::ad_type>; + class PointLevelFunctionsBase::ad_type>; template - class ADHelperPointLevelFunctionsBase::ad_type>; + class PointLevelFunctionsBase::ad_type>; - // -------------------------- ADHelperScalarFunction ---------------------- + // -------------------------- ScalarFunction ---------------------- template - class ADHelperScalarFunction::ad_type>; + class ScalarFunction::ad_type>; template - class ADHelperScalarFunction::ad_type>; + class ScalarFunction::ad_type>; template - class ADHelperScalarFunction::ad_type>; + class ScalarFunction::ad_type>; template - class ADHelperScalarFunction::ad_type>; + class ScalarFunction::ad_type>; - // -------------------------- ADHelperVectorFunction ---------------------- + // -------------------------- VectorFunction ---------------------- template - class ADHelperVectorFunction::ad_type>; + class VectorFunction::ad_type>; template - class ADHelperVectorFunction::ad_type>; + class VectorFunction::ad_type>; template - class ADHelperVectorFunction::ad_type>; + class VectorFunction::ad_type>; template - class ADHelperVectorFunction::ad_type>; + class VectorFunction::ad_type>; \} \} diff --git a/tests/ad_common_tests/step-44-helper_res_lin_01.h b/tests/ad_common_tests/step-44-helper_res_lin_01.h index 75913c796e42..b0059c1c7c99 100644 --- a/tests/ad_common_tests/step-44-helper_res_lin_01.h +++ b/tests/ad_common_tests/step-44-helper_res_lin_01.h @@ -1202,8 +1202,8 @@ namespace Step44 Assert(n_dependent_variables == n_independent_variables, ExcMessage("Expect square system.")); - typedef AD::ADHelperResidualLinearization ADHelper; - typedef typename ADHelper::ad_type ADNumberType; + typedef AD::ResidualLinearization ADHelper; + typedef typename ADHelper::ad_type ADNumberType; ADHelper ad_helper(n_independent_variables, n_dependent_variables); ad_helper.set_tape_buffer_sizes(); // Increase the buffer size from the // default values diff --git a/tests/ad_common_tests/step-44-helper_var_form_01.h b/tests/ad_common_tests/step-44-helper_var_form_01.h index f8b7f1b030c0..8e2da6205be3 100644 --- a/tests/ad_common_tests/step-44-helper_var_form_01.h +++ b/tests/ad_common_tests/step-44-helper_var_form_01.h @@ -1165,8 +1165,8 @@ namespace Step44 const unsigned int n_independent_variables = data.local_dof_indices.size(); - typedef AD::ADHelperEnergyFunctional ADHelper; - typedef typename ADHelper::ad_type ADNumberType; + typedef AD::EnergyFunctional ADHelper; + typedef typename ADHelper::ad_type ADNumberType; ADHelper ad_helper(n_independent_variables); ad_helper.set_tape_buffer_sizes(); // Increase the buffer size from the // default values From ec2060cc454064cf43f4d387ad9ffec395ba3d77 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Fri, 22 Mar 2019 13:43:21 +0100 Subject: [PATCH 308/507] Add SymEngine to the readme file in the documentation --- doc/readme.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/readme.html b/doc/readme.html index f938801714e6..6c35741edd11 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -604,6 +604,16 @@

    Optional interfaces to other software packages

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

  • 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%0AdWOLt00w}gb!y#fM) zbV?&ql1lf|AT8Z39nziB-QC>?OUK@Qy`Ou3dj5cUzB6;qoSF0cxpFqu-At>JhU%BI zb?^OXY)RoXrDZ^QHj>0XwULqP)SdMWlJEsQ;s63o2Vy`R!8uB41{xYTe6ayISGSJ- zrdDft)`H=BegXPCVU7ymZXejmOPJoqDTrqq?vpe8?UqI`n&LXw=zRF78jW)5oMPys z&W7ZB9Ge(mO*`Yg1j9wLoH1Y+Tqz*`55vETjs%_iEMPy@ zR|xsIbOta-s%>wK6Llkol3e0VMa`{3@3m?FL<%8{RAP@* zL~grEq@Yl*dUDawdE0fa{z&(bnMEe{T&w0br#Fyq^`6B6D=x$i&WJKXtdzm0=9~u4y=HWu-`(%BlD+?{48DX1^Cb0CFdDPWKBAZ_%xh+V%Vi>9;?60 zEdXi}A!USMC6VR`jDTN2Ak9C{kSaIJegg9mj9m?Sg2Bj7yJTRoS6FCo zdX@ZH?KrjFxVckSFY8X?vFdYL-y`78PQiTJ$auP4>>9jomv#N4A<2~MI05BiJaOi+ zJ$WdG2qsIVXFv7xFSl6>5i?YMQ=Ms3$V<>qfsR2!&EAz>m@& zD(qi;#I2Nu8C9GOnegCN$lNiR@Ug3itiOb2qJ*F%zRNB;;D_9G=?rHp}>x=qceoe5f(dbT7RIpUoEgU(7i z{++Ex1h_h%m!bVn93rp$A41=Yd2h_+73VIp$Vcd~(D{O&k}* zyN%=mqgj`!=7^+*yIku97rV^W?%2soH9T)1;dk{R6JY`re?J8e%lCmuuRe_#Bt|;7 zA&Sph5BW7x#un4cBUPm`*+O%&UWX!A#SEYqpiG^2moT|OkeW)91FOkQpVuu%??f-LGL`@ zk+8WII@80*k#8Aw&n-kQ`@(5)%&*QN<;$?;+oFk5=S$r|a4ayflT77&>NBpNJiP2P zgVdp>_B@P*c4evmIJ&&NEcoD3xcQS)3?vc_i8?fYq4!X+WfaG`Za2!Jp5i@Ed$nqa zyczm>5H;yX+WdEBA6_mfNNlv+&$q{P2!v(CxI-8-cdTgh=Q zjLY-QgG;uPKJOkxh5y?m3{34-v9EZ`6eSy7j}8ogkF&C!?+lr8j&oh;m)YjbThL!V zr>y+isM-HkGl)plU{44!Z)e7p{KmWF79=Lm1GRpMMf?b%BZL8P)1PYGWtVQ8tAsK=*E< zZ{sIRo`;dwB@{aK3H2$1ax;;Zt!-A$L~u?wOJ5V4592uPDtTseA^hMfuB7xA=Hlqg z2N=eal^33NxQEfl`uya>^UO|Oj~jhnl-Gb#AkxYpA8GU5C-4Umvy5t=;7#h+-|wn} z+ouP_??tGKmBF@yEC7nXLXLO`1YQ>;av$kl)lm!@5{VsfKc7Iw5f1|mw;6Cg4ElJ^ z|3#qpR|c6yRXj`@Ru%Y2N5a~XWtpDgxV%FCKQLzK@7e7d6a(hKpsOIWb(=F=O)h9^Bne@P2OUiyY4xB`x0=0=8j5#|_M*`^~^r8Yc zM!r>Of_~HC-l=wZv#3%J><3bD8mA=i$v!V5)C%-D6nq@Kg#q`!D)1Z3&a6Q?zulSA zbE^o;q`0$;8XoEukhn4Pn)5HK0&AM=i{PM8K2Lq5`)r@dtwZ;jpsjbO9LX&;{HgXj z_fGTUaGA+f^R5p%c=or4(P^hod=jHX3wojCcfjeJ$7>4^9Vja=`v_ygvj2)+0;e;9U1{q8#= zKt#{-6{N95o-Pe-`mvmH%8;2z7OPZ?YmrrVdNf=S*P6O{o7ify?3o-08sjt(KKT6P ztx$iRu7R^rC)STD zW8$=ER#hCx1N*>#1qjfReIv5Ex1;h@;zZft{FY|A?_(h*xTYn$YxrgjXvrGP@{uil zm>a-A-u|_95Dj4T1S+#SiR226Nw|d8u0PF z{rlKWbT6JP#sP*M3gW234~DPGpR)nFSoiI`zR&OmkK`Y6Q=)$^Tj{v-u}pWEg@Tjh zWMad7uWZ-*aP%p?Sx9rJ%Dv6e@V%6OMP1|lwF^5fk|I`VPJx@WZl3Ai^WclZjJ)8- zcjJ@oNu}1XOXF?o5k_QfmK3P)O%ug^A=Ydh#P8=*6J^+D`Nq`Vp;B6arM$}1tVEh? zosm{Fm!EGV&A6)M$c*;SJG0>PJ4EpA%Q671Dils9q_rwEigkP4>i!>uOEYFWT_7`?jPKZJqdPih#NonXzO z1{QER;o3Jwg?PC}6{eM=_BY2xOOEg}O*9^+W_;dXZoh5?#IW-@W*WFTmN@AbXx4ss zcdW;LuSLDaMPLD6CD=B@TpG2VwzVZ(!wQL;yq!z({&=z>n&E*^Iw4MjQl4)8wUxv4 zFk-C^;T))#i6HVad;*JrA%7-)s8BEipV=}q#%`V>`X+6d#yH$S+Ki`!Nk5*O_Kb8s z$Tr>1@wfFGei~3Hj#^+IRu1>Zg)jhjQBeXJK1n!O44`dFtBry&eu& zGo@JC_?@)#-gW{JPZ!Dl-KV7XhsGYx883kje<75Rb^f`J+(q!7jtq?v!L%gzfemY6OksDI!gtA)Q}3=jc*Ywu|9k!M8$r7DiF+#V>z;GsCCBlXhHgu3IY%>+;(7 ze<$N39v?y_T2gCXLnL-dDdRg}H;~T_HK1Ywn)2aen!oL{LG)O2CcO36P2X$odeA>%~d@#x~|&YoL-v^q9HX*Z1V- zTQ_K@4LxxJ<@2=7B&nQ((;Vo2xG6n*?}2?YQN>H_Aopmxc(TLY`SGLmo$7<-&0wV- z!q1qQFZkT`=__!`axCv&ZHavlZCo5qz`LHJ!~1&)n3DP_*Ow>9SOf+~Rvf7ka@J8# zAM$k;!G4eRM>;q!yXc;%YCAk&zI&|V_uQBomh|mS6b_-(Gv_2*XRrbBcrB|!f7&&@ zlaVrwxufFqyS}O5!vXJj&b&4=e$0O26S{z@ZI}Pk0sugqeAa(IK*hfwfP^M23i#IY z5nQ>+d}w|&KLE^%^coz;98~YE9KeuOQ^Xo7qO4|zEaG( zKC{sN8AK&JWXIh1vnJN(dzSLb|i~S?ZPTXPIvH!#8S%6Af^q_xz$~&4@!y~Bgq26@i$y+> zV)49gPY>BGZ|-5$_B?YpnyL9qUuI&?vF1L0o6tENCDvdw-&LhK_5Sfxr~}fQdOuub zB-$rVKssZspID^v`WLDMbEcsCeSrefPXHe8DOrTJGG3Q2d(WUZ7pw2u&cvTD?Acyc zc?;2ig+!7Xp5Av@d2OY0uP!Y@2URb{-L>WPL=hX%n$`S*U>CbbqPhF+B zNfDq8BA|on7V$;@%h*_-EJf@Kd@kqI3cJ}ilKY0KulE1zwp1of?!d-{2@pb*gO3lnknmZbJZ3k%0B<{jTYtyy_ z2=(@OnX`)MhX^k1@n``F72c9k+@~Uh=b)F@FU^e{5qdu%h3Gb>$YsplJbjhoIbS3J zt%03Os9C<249hcxKi25(nr?j_EerkH&wki><$HWqmE3qKcp_r*+9X=P6Gw|+Za_X# zz3a3lE<`%L#Sjp^5G7FwaqMnoB;nWHX&?jWKFh4$9$&%TqKm>qLVdgN#lg{Pd8qQ} z*(%lc+c7hUrn)!9WpI$`VR}M8(3^dcJ@Uy=1hRz+6SiNr1uT@!9@J82P?UK%+9^BI zuIhDQ%Na6(qTtPBX^WIg&C^wuZsU8VLi3d*SlLT*aAhoh!O zJUs)5?{~mZlwDiS3RLIq>l@$FUd;TsmkwmVt7)|nVh>I0btiGG|9i-?Ec#HGb`M{- zVJae82clHp&2!NALO5jTP~9CYk8 z#_MrLvPAB8n^m#R$)9A(x#>#aucqoDu0o$13^ zF#;64?y{5*a$3%~RpfvCV5mfwqqtWmgOxQzN|)H4?|`AJHIF)mK+19il67c9oWn5I zTDM@6-Jvi>Cf#F)wc&J>R+P-|4OJVeT5o2S1>dq{GTFV#vCifqAHy|hB-{8`v{;X)Uexc{U{8s$8TbEZG(}MVh9DIJ&n|x2%jl zlRfcnT~ipff+z3brxcz<;gN~MnZ2uB^1>#DDyXA%mQE6Pz;*34z?5Pp?V&CoSjv&_KSJhTFw{cY@HNQq$*f zhGApAP~6yfQCplu?5g?k&S{E&Zn&_)nF+tu*=5K=+*qV}70TLF(Gj$v-`l0rKJm2{ z4G%4~^?P*4t|ohqC>|YCRO2;@gEJp zEp<4{*`jnaU=o9b%JdSb6kG~{Al&l_QS!ZyBHWk5ngz21^5sc=PmB^F#)W6B!2St4 zIsH*k0LAwn<1yJCxNYc%qxMz=Fxs1^BUVk&Zzh5G#xkcsY))^l0dtp*4nt;1HRZ3k z`o9B1h`p5+17I`e1%mKtSEbWLb0p3ZCZ6{MC!Gi)I9GQK;5w>ZLXgZQ!$$1Fuqn0~ z(s}vig4uW*Np--rW_C74{_2BR>ygdNrd#J`Y8sv=yGk+m_FTh;Rn$ny7bj~huHuFJ za_$o5yIA&F$7B`Bl*RsdkhqqI8Wj_t&b+rbJ$#2cZO--`cc#A%`o|U@)q;F|tZ@<} z{4Ae+SDI>xu$T%?Km-C*tSGoBEVOps$;gbsfm+~m42ov;85P6&QESWG;Fwqk(GO1d z?_-@cx*UTG_onWQvIt=`oU#PW?Zk2jVSatTD2HIod9q_K-RNL=vIt0dXry>~S8wU(&6n|@t~nDGJm-}J40zZhhrZh#~rxjQk*zR8`+fL zZ*&#kWEz$g0+FWDnyVJMD+*O}GqO~8qAk|?%b4Q2@LKc}6x%8@YW$HB@5auNjFLNQ zQzX*lW_f~%a{^rjT{+r$ETDs{j!#uRobvUS$oOyibPuK(8eN=^8lkS0*v-9nxxS^* zB2AvK`#!`6a6fxN$9e??ls0m2Y>>G=TMCk6aaB7K#9FT{V^RCB=iZ6Kb1~|;(=V|d zLP*>s>aqp`$&->rOHKE(yE9@(9{eqj*=-|YA?;JUTPM$Ovj8CG1|?Owf_>2E?IX-# zaa5{xcqk19KouLNbDa0bk|jPjpWxK^sX2`TuiAA@noXY)|G@(wDOa?69JYHZn50Q2 zmbCB%*8Sx{fEu0aCDe`>i2?4I`L)WBzz=>w#u}kb{2yErSNI2^Lth8^`6hB@p~HG@ z*DuA+;OEix#TM6@f+d()c4HCTVM4EJ6X`T{Z$dZj9GFBye`5kzu1L+Cj1GSMgpN8wd`#hXs*@_tsk@ za+%975ZBv2FgxV}3$yt9O( zWm%6e1z+Q7EXB+HkfiQAYbGm&Aw;t`-Ah20zc2jdQV*?R6R>_C7lRid|K|4yL4t-eGZs) z(-Y4}1@_x6b?C_S5B2Ho(;K|h-axRn3^4umVdas!(>VV>`6^)DRC~CsMScG4GI$*Ak!QLliA)YtVc_Zgvz3R zCWNK9Ncg!Ks#`k`^de_!J^CD{yQC5KRNeT@ApS@~Wa8R*hr^_f$B6FdhXi5_vBwMV zsFGjQ|Bf?+(2Rgd@PbJBgC7$5&o~AQzdQR#I%zIQVOCa`;?09ha8a@waqCU%jn@qK z)xwyhi<5@am?oMQ#es5h9`sTS|LB8r?!erp3hC;!|?UNA;M>52Kv zTFVj>^2)GwLD-hQqKbM}^-U}0&<9nvD@H4)G3g3~ey{8%KFoBEVs%eMAgR|Y(z><$ zrrHT48}Y0(b8`Jfe_l9igvzE~WUEMeuvZ1mi?}8|ldmKmiK#Yy#Z5CcvU<^?Rdt`| z0c2ukriK&?&-`ziCdOBXfXY{I2X&+UP3#wIG3iIplb zJZqe~WlrO&M=w(HWkiPkOj$Y~{0~e(=%cR`%X?^e(XHmuf?v307oWM$jDN^=qBjqi z%c{D-S}|Gw={jyKH0X&_lg%atEVXp#h)v4gMy^c^zp)h-P#!IW-`}uOZOw*1VyXTT zoEmSph?gef1srcbtCzJ`WKkmkXqjjX$Ax-C#;qI;e}(UN{zm-XLD}1kdTPOil!nQ4 zgrK2ryiw@OXmt>)cHrmzYLZwZ`Zgt7#*AR1gWyDDiCQ&qGxr9fQuW^OH{=W}a;aen zztI~#FS8{rgo(;}y|W|#bj~*}{A3@SsEhLk`~ExW2*RPft;+xkpmf&M!~3B_0jnl4 zSAd_@)fuN6LmCIaNce=PlO@Am=Qnu z5_AE{lUv0VeykqRX+wB{Khf7y!Cz`;h78sCyJYi>yUYV-ak_{pz)9?fAb28lHXt26 zX(C>`bHZV?h6F5>;UY2S3!y!o&+EIBm5z)VuAP@_&dBH8$jH7K9&QkDa@4~KOCq5K zoiY7&k&d0K&0}i4BPyWs$JR&`^}H06gP-G-j1IATrwHGr(dF<84B1`#lzy~S>S^xW zZT0&3Zk7~WY0SS&7L~U6>w%nv03Y&=-ep1pIybqMnUI@;h&ei#v|L~cf zFXW&(K~GwW(8n4H3G;CD?Ng~nEbjCiS^V1&xqKwVZvj|~iQeyhqLh5}bbm*5rF7|Y zMrOEi-Ya<>?t5w3Wc;Js0i7Xn+O5*8u;zJK1Dwr^ytz3Ykhet!j-A?o(s! z$4k^N@rgH8p;*_N`zticePa3)VhR+C9F7b8iMxV4oG{Yy_0I?OvR%rsQa5l(xpN2XZ|2{k6UR# zr*Wj8I+GzstibWy+D8o2B~2M$zTi>x0K6ji8kuXOpcmq6XIsJk%1cZ9WH?@}-EO@v zg#kiGg(;OI=#MJbj$m}(SIbL{X_i@q0oGaNB}1m(x8M2oiv3AgUVA&R3vtd4h3n+% zP-o1S3Rv)~8QdCgCvI-CQ=A`eGEqDInIb6v^*guaihkW#NAoOhnwETGZElsZ(`oN#$v_Afyp@7x~LyC1ip78yn81qV>}v%Q2TKEmoe>D4Qhu{Nq;7q$%L@ z{^CGW){E6$k!{1qi)8k0<&Y0V`9ek?(er^jYeewB z2dx$N<-fQZ>%t22;@*MGdL$(P5?dQz*&4Z7ovrGtAW3OVtzzvi{W!5q?IO5L6BAYE4wS-7Rf0P zRPf{-7x`Yi>VV|89od;G>fI=5wz6rGw6~PZmwy-mD$z-)j%W@T4&4*oa{BMz1}QtY za|2V}X`TKgrSv%mnJe%OH_m2jI?54I)M(;J(eB`;1t^+!WgW9MAF-AE64akK7v9hJn&A7=U!LL+-7U@r^SZN#^yS6&+PPSeJnReD5dBHHb*?JA2@4I3 zRT$5=8Q%v2x$1BmFR3cOQGh{Q@BL5Uckk}|VaSGF$fWndc~0VsPi+KdRu!M>WCX7! zIGQfrUX@FF-cWQT-7(4RPaEz&xk?06hpib-X4+P+Ze!A>JR&AJcr$>~ugaw9{>##_ z|AMNRgA1ZqNQND%Z1&SjIc^UZ0p0nP3UVVERrEeE+jR`PaJrnE5-56hJ~r}Wqzj@0 z@fHQiXCWTl2D}c;k<{OK%cC*bX)9TuQ;9h6Luy$;-&dqO_05BdrwrIXNW~UYem6ET z;7|;hh|1mjCUGlfttCuHAOUUm6rz#wnvCh$0Hu56vDo5CB^ukGxk>jup8Yb*oUw%7 zOa-|_N%8xp;g|YRxVNdRm{x;hD#@; zz^|=lPI9k;G3QlVp_KyZGQDS;c_{{;MhK9hO3RHb;&~!XmvSMkfN#)qW7GMmDc`Z& zk?#?Uu0RVz^w1iJzT9LVH83nnWtSyqeXH_Kp;7^7+(EZ|G)3R;xV6N6xVYkK^7@E^ zcUH-wmH8>Txn|Xi)#!7{f@Ss6i<*@Dv*N1jrm)ZvrULel)p1J7pFjHJ2R+xKz-3AJ z|jH;jLf$qiN4;O|;%C!bF^ z(-WZX*i0z1?h*}FB1xI5BUF(pad3J1P;k()fY>s?>y6#bgUi^b@!TbbbpCmQg8i}> zt^Fm91?9alCg5N08o8F+mZ&hau+q4;qozH_q3EgJ(ih@uIj%ku%zNEj^vT?5yE|gu z_1N!8-K(zE^4RARqEd(BSfL8L0?*(n6b74_XL zo8{~$UM#-1VXcFEI*#c|8BM?c+)6@>JBW2KVxiPFVFsFAJl9 zsNz07ph~Tg;YKV9bZbo6HN;Md)0myQqize1U>cqwiYyV@2v{E&BK#=tojWU;)Vj^| zWF91MUEMu8!mRX(ZYTppl~i%r~d@0JVWQmqq+Azcp6!=GB*WZv4WH96`Xq z+MBbv1MPuM+FuN^fE^}>^c@+PB=)4t+v+t8wUATjNy*`>GYT$*3J1L(4#b_*xT664 zVP5?B*c|N;ufS35q}yz&R(rwK?H-=q{%S+B=lUpgT5!KeNi0?7SemJ}zq%amgsI2g zQ1jNQR}TWv*f(F|r-8vu!kzcKh8<57h3AW1tddC9lp9=-be~gBV$W-YE3A600eGUX zA@ge>(^$-4*_<|jKIiKS8`Nfm{5meoFJ*MVcvfx+9iygj?6W!c8ZB)VbJ1XDhL*Q` zZ->?9T}puW7JGW)%1MacPTi}FXo23JQS zu1TMgq4ss4eoYdA;JipWv}+_-$sUS}j&6CdR(hIv=k$=VsUgV%{yBPU+JpOQ*=dmz z6F2=lO0s83u=P%XF5?MzUKFTHi^=*gimznff@HUGSw-+eFqQ~o3^xw|oLbkq4!6DA z6j?gFkI_|UxS-0CO+1q`@Gz#9Tgg$n7Gho1PNn=){ul*_AoPZy>z z3+!Pk1D}wPUo)(rTQpK30@mrR2J-g(zrBoGwvSj~Ruaxq7er>17dXocAt6DU+F0}) zt{taOgNkDdPqOVp1@p66Mf)6&>b<=d7rp~PQ+h1Ck#;eXoBfoYZ)&l3%p;q>?Lu4r zqJ!(JsO+c{C)R1iom8CKJY7hysw16Yb{LA5JsY&B1&{^*=67&nsr?bcbkdrx3*U8< zfjsQqL~7kR07Ub*b;Ua|Y=*Qs19mew0^{F2=YPg}b(~@?)ALn^-6z-1Md|2!Odl@x zO1J+?bfQiF9f2NnCdJTgCP!O;S6te7<@CuX(x$O=$pL$WKG2>jrWtpzjaD0k%${-d zw%(>d&?YYMdDKCex#MM$IZ0M{&k6t_=N1z%WYH>_{YipsZ zt!=S(bp%4X$awlvP$qQ$N_KzQ>$;B9|2VMfT$0t!Wgo%4x?=2rI$BxI^1j~PVwv;# z$fWOwd4b+@eS4%n;XORX!tnlq)y^HUTjd^eR&9*H9%6f(s=x*XsqRncfc?OzuN3sJ zMmNHRUp|*Pb?B}#4m|6=E|sTM#;RveWeL!BGH;G3)~>-Lvon$pfupTo1H; z8RmJuLk;(O)>Sf1ciWK2vqRt4!jMG);mdd0f+~K1V5Nvgw;F6OvxK!}8V38;ds0-L zV-{UE+d`${G+7mHHu|+wT|PPBgjsa>tm_Uz;#gmYAVA= z86@U`28;(tZ#A=z1Q3{zhYuUPLBoTP8r08q@ZKdnBhysb+4Aqs>;brV5dOa-@#*D_ z*yrGkRoe00pKRtnb@Jpqq6O2xP5K0$BqtN-8EH1q+FI@(5n1hI>_U7hv_|xjo@%KLP}ITR&FNxu$?P!afqk1D;hoOOcLKBmgXx zsX_XZ>nr~CL@~Vp`(K94O8NA}45pmg2q7*p+@)p%1O#Xo;t%GqDk#WN`;r&#YN*R{ z#QX^lHTc^NWVcUiVajW%XUpzBExW4Pan1|2wU*YS|KieqRD zwdgX;PN`BLMiBU6@ixWJ?gI2BEfHi^?4!_>G1Iu-%py8^c+4Z_AkCT|?sU-TVO)av zxIhDqbqG?iQc7V8AoNB`#ceX^$So>FIVRtUMMD3QR_hnSbZP|z#H2f6^L=N@Kl9U0 z;4Z^Dflf;V9ke(!I!Qt2#g7~t4^2-`lg3+7!EYH~$25Pf#PwyLw@N)u;Y1{@z1FN} zIQzW+F_or@oVLD(+ZW%Z{Pa>nv~0+-u4?WQ+kLd;Oeg$VLk8I_Bg-@I+WUf}V+K+Mwt9EN2rE*zq>w04!j9|pVL{ zmS|8h@kv`g6nwC}rD2M@x1o?cGl#D-+9ZU}X|n*UtCiH6M%MFF7)K&C;J*%El;PD! zr#ZSqVclQUKFr=-X>I6(J5EG)DR9L-#bKxp`t6S8k6@0kDd1wHe3Unwo~U=U9K5>ewKgMu zm8T*8xS4QBJ1{A(q3i(*l&AfRuYs0-A^%f#@sS$53C$hCC2oJ%&fKHq_-1HvV%QaT zm5$90!&Q|7J;lhvD{AnE|0?Pj4NlCuD=MJ&UErR51lbTuo70*Y!Fu`0$KP7#3#-T6 zV2LeOdCFl;W=aY5n(|r9G`@gQZ#->0+n@MR)jHi;%#LAU4s)&30*uWbo|b_X1Ru|M z(UtncU;sx9nZ_x=z)k~+>;9gX&ByJ>T!PyTulYX)8iokF1;T~k1QPHTsAo|b_^ti%m>0;nHW z7xVCb{nPU=`kui>S?cqOo3lmDxfkC8X3XPs3*u64E7qB5P5TIq9UnHH(b#92zmAd5 zMXaa>(|bE#IRVnGdRjUzb4a9{d+1N^+WFc(n^H1(s5~t*u~m`qtS^X7M$ASotYD+_ zJ8-Q9@+FNQH*#DqvOXZQEal0>*A?bgxi>E)0!nh0liu2OW6_DPQf?j=Gau(N&ouAK z(U%e}D}q_4JwNYR4R@s0?^QRCu|0LQJ*7-&J)L9bJqH2|8m!J1eVpcCRpjHR#HJSn zi4WALzu0K6>_>8*`3=~aPu>?$>wl}fT~S5?0+G-i@}jU#u+i9I z$`A(ALB-=Gi#mW{#k3PXMPRdqDtCPx&e}>#mwu7Q>#Pdqg3ceMf!Ni=e2x>#+6)fE zR!x;lmo6U?@VEI$WsM}J_9jW{u!*0OeVO&8m@_-bmD#L%msVO545_sDG;oozH(TXsfvY<{q%YaUr6Ni988zV(< zrxgDmy^yK!m=&TPXUDKk4+xmsF+sdYc2K{tfh1%pQUnpX2%M3Ex#DQ;ORKyI-~)Xt zlCr2%lwEvRdvS_BX#a`Sd?(9*LXexlC&z5&RJ>o26&I#AWv0DrH8Ra# zY&mghDlQaB@vRw_^|itRIm4HdsPf_d>hDw1-t>CTriK7t^hM~FEtdtrrgNYq{MTU2 zU(k7E0n^hlZUD+Yv5M)@*&EvYXGCNum+m@j%eJ0RQ|?N@?G1j!Qycnxbc5Zv$FWA+ zVuqT#@=ot;j>iHo(CcF_tlfsaT=OnD{SR8-v=hm!7prZ-u#WfI*CQa@HJ>9I;YOdR za`EwKwSCr{C$zgUBMEzOT=2+9}Un%wqE?p=GDn4 zgqojI;+_HfhB-MmE5b7J|Ah?7IlJzi469JuC#x3)>$2vrPrZ~eyw7%>@?X{G^UKIZ zaf4kCo=^erJI23kz>6fozs44w0g4CKE*pEDrn=~7+QHp+C@r;?Kt-*bjfJJ!LM}ki zdDT@C^9D_Qk;gZrZsw5eq$i%`W6WO*d~cpjb%gP~N8tR_?HeY12;(``I#eGx(vhXk zr5*9&N7c9bj&LP^i71;yxI63x{^gaQO0vXyPqC-0-T{bI+jjO`{|5KSA#)}vzwPSI# z{&#!;F!8n+9Kp*F>`x*HY27C=6ZWk}3WF!>{F0FU30zxT6=6ToPO`uLG{dhi5Z1E_ z{eEy;n z&UG6mrTRejynMI0tJ~f&NBwCI8)NvHNA?D#Pl)>CnPTVKxdWE+Cv4tCAOnNem`|M8 zgRNe&nHuz^s{5JVGt{FCk8vf=6^`|1M}{vqyy>7mH*O?N!_>0V94xcc2rt5Wg9DI6 zBw+*)#g&P~4Jw3nU6q^gT+S!u(jt$o3fubyj}E=~Psg}$1v3K_-n)icWN)weNj<-o zkUBr6=rGAN($E4FAH@7aa54#3C4>_ z$0c_T{D^i-rFoSqwD$-2RDkw2SkQA$93>&OCso>OIR@@}qlt$@`tsWDD*!j|`>-OH z@4uo|`GBoC^6*Uv(pDhyCw@7MEttx~%>K8tBJ~?WE(rM>uz-36Aqhgi@FWGeLX9{= z%u&l|>_87@jMzjxmH^G90s>D-N=fVMXHR<<_dB|;wcuO!8+3n_NE*-EJ%3`8r9 zr4mjM6&ekqh?Pt-Cpv<~t5vH*WJj|T5ea4-wg^GT zqZ3|ofqz{_&zcJ39b1_J(zV;<@SYPWma)WE!6b=z)_edhGh$G|J7suC(@GOjQuY7> z2r!QXMrZy$1Y2QS5%qphUD`fi`Qw$i#$|QmA&rjPn+c*aBfGM;8U<~2r?M?TVU-kpiT-{rTTBJgHM ziBYVZ*%C9d(&+qb`wUKw2Foe<8G-kSHW=Yt5Zw#QGaY0=@A447jkd)5)}M)AM0|Ir zXYlPW5@W_{t2S3S99b)koVnd#bIJJYhuMW`OHm58ZJ^t#QT)pbqgT5R<^@pFwe#<7z<(O23Rdra-0|vR47$O! z6&mG6f3J>fq`u$d91--^gchW;H$^q>+g4Z7){U(`Gc&esViK^l9(|FbtgbWYj63#D z?jie-!K#4ACzHA2OP@UKBZ~Zp3ZJ|`$1?gGEafYbkn=lP8Vog2SiAictiq8#(sgGwrwDeUltSz5K*T zWNET|5)tCY;hYZxLBcjVn9hfZ){CJK6%8p9t@st?sg#t=XbJ*AC6Rz1ad`ne;brOJ z%q8We$6ZsEFQ>2txVGz5&{SEypB@rH3fb3}`6gPRa_hpWgRvgiOb#I3LhOnrU!3Z< z*(h!ufk;cyFh;}K@TYX;FF*@BGe4zxiWYI}&{yg*gg16u`y%kja50DUJ(V$bDsh(% zrC`2088{LugJ>-N1=GO!tCP$)16Io8CB){wyEP@ooYE;_X{-k9&ymWcZq~CMn>UTK z9mCIRDR0T(hog20RYp14>C0N>IVhgg9H=^LyH05}IbJ-V>Q)vzAGkeVJhnyvUlI%y zrQ9-kuw*HB8-2e!X^x-D(KdG#zd4(US_u30p#{^q$tm(byZ`}ZbALTRV&RWa#6&rp-tz( z$akzScv4nP4{JdB7T@r6sp@fhr1)M2|J6$ncMLERkMVh zw5l(B-5)lo@I0Flf0`fkH{j-8U*7Ai`~u z=ih=NAiA zgvev;jN>jsxGI+&HkgVs(O;}s&I^nS#6S`aSiRuP(91oueLgQWuPiue05oMTd=N%E zdflzzve2uNTGaOKNrnI6K+Rylv z9=dJ3r6YT=qz5P-Z>y1mcUkLHlI$4l`BXTw?0VoCcq8GtHkZ6k+U7LhUzSAb9jM#( z)2xdPedVvTCV3E4X90=BPrsj9-^Y0NVwbgT^{jYTEmdp%6;q(K#Yx7)gL>>B9_qkC{tYgTLqYMXb8p_R)?lc zWbOi_-%5D_qUWE2F(f*&n4av!!kod=*;mKPd&@rqDs^I zNxm)e(Lrr@!$d}=y;p#jQ5WUZWP(`fafAj$;f4etA|{r=kcV~tgk@>MHNh^~-^o6QRcu{E0mYHUSO(}nurbwq+_BxDxG7aGtu z519l%B!<^dsC;rPkoBo#nK>WB(u`lQSRZ}&25rpx!!xn>8?ir|=J$xU;#E6xW#Pb* z-~;0T5>1SFa^ZQiZ_mU-Xkq2H8i0`TeSMDyt(!#RO9kVV6^H@Qdp=dB{Zmekf_z=d zOC~7g_N%3Fl%981aY?V;M2foJuE7EaLZVxPZV{)qEV~9jJtTny!3gRnQy3ur7$Cz( z!IV=}dmCou_Ju?N^Gt|f0rzI#nvP>ND;+z;LN@Tdq9qASt9{{G8lphxjRlX;#UC$1 zrv#N=LCeK=T*91K(7(mH4|8kMYlMq?k3uHvp_Dw|E|ffrKAEaCeUfIw*s;ynBcTc60g;dy8Bq%>!g*$MwB$_4Y6xiH+ct6A z2Rbd}0M#E_XDn*v@bKm&{qnhuR_&_)!l}}DyHOUbRJQMRGx}RqM@`YIN&b0+4DSWa z0h<#c!zjnHYnHYsC91n-N34$#hFKkr@xeb3k|+BQhY0qdj%P3o5Sq^y?@-c6Dd|ug zKT<^yQv)0iH%4@e`rkq(1X8&3dIyDY76c+k@veUyc>#s>k1w%{*iLOpvU2#80k=2i zojK!a(i%GL4Nj-&{BOtBm_?w2QBu&`vI1bTt(gQTJvqPmUD|ik*EH1G)YbS9igRx- zIx^>(!Sh;I|DiGR`_5MQ2R(QbpN`)5@=4*r&kp15=*YTl#(Ot&60O61zx)`ef`O#fn-M}=iVZL#Hg4uG_vu*i5; zcPFY@r#dX{(_}0gh<;_pl0Ru^eHJGdMc5ghb9tfY%=PD;c*Ur!B#Z{-o~O|LJ{miA zIYtZuAxMtb-L>-ootL({7J5eX`I9`kLzLx2VOIv=SJ2$mqE}`2r{=QfQ}#no+UVELr34K+KG-GTUngS6yLwuz| z@}Wyfh1{^4yo!pc8; z@f!PjTc%ZnUqxw`HHPg{^o*+1z=-TK2zZWd4x-PJm{O|Bx5iRLju~%f3xO{=f&1^e zBC3(HE>F9F3hdmY+BJRiS4iA{lg((6tTg2A9;fKhmKZD1<716>(Y*Xq4j&8}aN5WC zsTej60UCh&HaHjAz#6AM)^*XOlkz29d#Kg-7}a^}B*&B8wUZ*%`BcoKJ77-1@X?mH zsmz8eSHWPW;~5Le?&BVhLJ7a1t!a|h>$;M3cWb4Y1%Fk!!5g1DgYv>d_)Ap!*X+yD zZN5fNwd5R!*2ebtZFNZZMgf5IAU0O#Je1+t+OPVRN9cpBOq;_!C!jlUs3H za<}iQ$r*cY#y2|f@>&jr?qzt(+4otYs7K>TzetWp<|tXlwog(2<*afaLuJHp01{=F()mn8W&%gFa3~)N0R>oqOdFw$hmt^@9!MSx{xOMS!3bE5v$8R_``yn*-dV#O&(y zWsREftw%rwYtt?nlit|W8?!1KY>-zCJLre12k#jW(*L!iNvv_B2e-`NAWOfvf`F&P zyZFV8@=+M8REr;vv76LwRL^Fd+MP#HgmnEje?+VVBocX)a++M8A``hPv9?|}W%CuI z&w8TA(vo>Ul&cQ-^qM_zjd1!L>y(E}Kx_*E7@vVW~~2$l)Y=swgFeDQ^aWOq5#ljCQF zBiyi^Gh$R(7B>?i(r+%p2SIda^Bgb!h=77)jj+v35HyRg*gguI#^aWmr7ZMnS!pB# z2)FgyUXjh?Ly!oho?0FH+H`R59v(lNA;}^Af&s7fM;^W)0zq$3U?*Xu)mH|gU1y*m za$+8ucqO*)zw})BT6n*MuubIU*FB9AI36no`Yw@0S<`6*2)9OxXZ1ysaBX zb`SRHJnpXHI00d?nqe$xem4;m7h;8g?_L7I&5J1N_S&A)WS?K)S-Wavx)Sv@STaEM z4^NRIy$2;le?uR-!Ur}Uvg<}pY8!u6z2OBJcG~jt>RWNyK60|tI&hv$RSM?x{tcJPtv$ zT`yz#Ob8u+%GqXx@soGZZijh2*ZwE14$dv)sF7dg52{E#*jR3q;I@gD znOVOL$6OL_(y$l*kxl0x+0;KiO4Gk;GiM^GBLo~)%v%5-EjJDkaQh1+(#keQN@ZQJ z{!f=(nSt&r)d5QDJln>W=P0Dlc+olB{OJ*~2Upa@~#jQ=4v&h;1nJ3C)lqRcO~1wGf{*7C%Ke;wO>VZqKSh-y=1NXWKmS0B_ZD7}5)O9s)6{uyRe2TUZ{UsNeS| zDP_Q>7)KjKznd4-!uNJIX^C>wyv%yUcBA--2_qxMNuk`n?^cMnvFsr7N!8mn4;rwT z=kB@B;H+meO$TLq_%SW&!UoYlrUnqOAxSEu-M6M#4|L@3IU9#8&8CA`swPD57Rk5l zAs~YN**6K7BUbIsaW{Hy%Ow%3=+ed5gCp<*>~?P>xZf=l<;7aI*$12Z@z3@G>%IIC zu}v#`Iv;S<9d4w{ucf=7<{sNe)Nj7UR+1!v(!b}*F|huG53`dTcUp=ozraQ~o}>C8 zQvbkYaID|T;0VYlv>CZ$j1FyWcp)ymsI){)KQU08rgl&ytJiAT^@5>0PRMdvKk>`V zT0@ilJaXKd=Mp)&;TEfz0m;ZqO-HX7y~@sOX6DT$^cW88c7c>Znxug+HGESWLFX?u z$VRICCy9&YK&1Po62-YDdGq0vGcd@5fK)x(2P}?D0Huamk`bC3h%g;(cdNA|_}_8* zhAbS((uHs8&)FO)D--+*IMCT(I6Ey04T5|P?CKeRv>k|BPkC8#o)P67L?G2_k7;e6 zL;-uS!G~^|aZ>>UG9+|8c;el`)kF}${ zH!yaZ-48 zZ63VD6&ZO(W2H~W>&hU#S2Yl4e%H=-W&$pWctX0McEyxf_h?0RN*Ax2y$?^Dh#!6U ziw%DBPoHVyg)F|vu$W{>aP{48@!a}>bvgae7FX*jhC-)uE2)Q!DVwrs4zuZ*6nov$Ov6G^zs^B^5cti>;aoI3=_(Eo zT-6Mn;cDf{|3FH$V8qOICJ63s(Ikw^><8?RD@t*okI8N!Eh&o4hqBS=h89780^zPV zV^~}ywmokK24U6M(3SY`KteHXF_F3s`dpA<;vBL`!t(R!@sK=BhDv!c9QxDU{Uw}t zFJaa{vsGuT_bB`{468yrm=R-QGefky_%O}T_|Dfhkeu%E@4rbrwtpwbVnBmo0)6q${$hOF(W5r8QOP!RRNR{u zHkk2HZG%b<`P0?t*3AqE>1^o}QZC7wf3v57U*>ZB5gbqK&9IbeO*B^B*xJSQ!eDG~!3*J~W5t6^~`9Yg*RlaU$I zP5HP=r=d~oq#rGM-~68!z=jfsQDwzy|2^QGJX3GJUmT7dX33|V1MSOt z!}j{}_gD29_6HS(?Zd|I(HgyUDOef3g*2kV(z!8I#5Nm|RH7y2l0{N5!e(?Z`|`JX zJ__wGe1y1n=lTLv=zbV`>2S7v`@Z$p93Q-axi2D`MrZG^LoLQmcG9Ms;_vcuAmU^l z8?ArmiCXh6mIg+V`&K4Ylbh6&Q_HDa*=N7w60GbO$8^?fE4%7Efa9lWs=rrrx=kBc ze%>j5a{HK0TN=xr`(_Wn(%g&al0p3FO8`kw|;OFLvF!AHtyEn4n4g0?r_*15lYtB%vX;&2#ts|YO z-#Vy!GFFCxk-3nJGc8tHsE-^gs)7tcFpcVi2mN!e5_N)zFrb61r8`rB`_e9FOCP`q zvos2VeZ^3YII@aEo5L>* z(Yh!`My6L1+2PXaz!g;urLP%f^e7Vsp6QG*WnoTV_iBF%{@X?KC)uZ+N_+i}gm5xW zlN0MFG_x-EWv;Kl*r`+eb$bX&7*nS&gWEgCb}jGTrC3?)!_78t1&ndnrII10q}W*1 zR+p!^;-RaP3_pfud?b@!0fa4AOaqZ#5~m|0=6vxX`8#-@anMtkTys1fScWAt0ENVU z!7-j`p=gjLNe$P6%y=$}vvPWQ=Fb4hT(GecoVyBdHc7`)40`nH)l1&EA=9DZDsQ{y zS=Q%^z^&4%OtI+p!xI8R(-QCYVcbjVb^>t~he2aYYhiX`-SYb`20#6uDQVUZJOl29 zVsCDDesm-=Sta2+7%*JitKSJLEJX08-H-l+?#?`c7;;l?ws(6JvN|mDO9alI`_#i) z)#M&G9-hL}m3jA{qGSoMO8sBRrX05A#wQIO&90Q+@{3dtqt&8`RK zet8;C#XWvu)USTb_=S>n^aWmaRpqpleMO`nHdMC2suwRXlwxp%mqmj*+x)6ZZg zxu0)%n*g+?29!dsq{@!UqzbH%Q_V9oLgStp3ag=`v_gQO?)R{&dh){w_46J z)-WiOe1thmBE9;@-g=bn7f!?82NbjczqzWw7m?n}x`0-Bo#bsFL<#=-wbAdm0jD-6 zIaGiWc2@$fpcx_>>vfYL1Zux213yc}I%&^N1#{(bUt@}d|CLCbt%*|IIn|_4prFs_ z?%FOEKR=y)2J^nr)ts4VLzq6Y3_g|mbpEoHQ8J}$q)tB(Qs>ir&=_MCefX%@B(R|& z2Qu>pmdp&UYyzJCu_xmn08T__zZlAi#9dJwwk~@K9e9~be#ietrA1$_@tmc+EHU&!rrQ|wg9)pZK<--z{H3gFO0N8P?L50R_*tL-J3%Fo59%M_tZ(bF$eHN-zBiT zNiCp0ogGz+W4M>-jCN}M^S3JEEQf%}J&%-)jDl|Qq00n5XQqkG@>8{=a9(G>v! z?=Aw_75k0yrDQ^smdU6X83ZC#1;|p6~6$;9(H^8p`oTmxcy!ah?xw z%E^~@!ibCtJ-ogIHo#1cIf{-!^o`_&E-50@U%bg~%=Gb|fQR+Q!4-z-L8i+08Yutk z%s%2{zl4{(_&ZBbMGS_o9zQ!{ce|8e6mmO=eqUJeebM5l^|sog_C0YERlVjnb-ntH zV?yamiEWTs6hRm=RZ6@lP;mV>#*m-8j!XS(HUJeSA10RMu$;yM)^u)Teszk<^N(0- zzcr0c<(0;I_bg+wN0KqgNuD5oa3`9!_>Q>B@#H+Atql_@ewOZz(`I#-k@_>t!XoHp zZ^a``5;(EW9IT$034PyJPmXoHi;VERXgGZAh|m606?87HbnNNGT!v|LBwnmUtP!rt z3lMx1Z}Sc3uUZ|y4uBbRv}1^=UvZdJiF0oZ2?ky#+ah9;uC9Mn_6Xyt^GC&0yG)6#U)(ufNfvbaR&&g>!H zKcqwRW+EUtYR9r7anV~1j20z9(1^o(lYnKQlqX{}n7Z|VF6aIhkd`f%uCq>7@bFGF z_638(9=OUMFJOY>QWIh)){e$t>{0nAJpT*AmuAk>8n0l|SJ>|~9 z3JpdYRaoJ}u%dzagDd2sV304WZ?p1wXKrsngWfGV325{sT=74J1ityN7t6)S)=Z^I z-I5-PB`;=cA+IfrZXJ%_@>xxjTwn1@8|rk5ry=L-(X}=eE>yyjbwp}(O1eMi&|!nv z<5GHp3ZN3)kW?T=kg|FJ^GJYJOvm%X2*mQ11#0N>FcSS7>TNA$*xf_&kO$gR)%fq? zxFBx@OHUu%PPw@op?xbu!KY+h#sh6O-Xja?kTG)BInjwi4&7`CzM_iTlbGkQeBe?N zeVLeJq|rdt2qfhCw)rJ+{lG^Bln}Lts#b+rw9_^v3P@fn1ZrZb#0c8PM#J{7s$x~= zg%@&iAjYRYxJ~Squ|8h_!zIN@P>#KqiuVUrQg5a;EIvw5*5Q3x+$JcrVmjE|p1Ne8 zj=-1iM`fuE9#DRYOY^>k=hKDnj_a$7RqcXf=H_gJbE+{&NF~3B?dspf#>-U%9G54m z|yv5I3L4~LzElx=KOE`UZMJ?5^)d04JAH=kk*J*9fUbzZs=n%`J{C&o(vw6=Y^8Bmj_#>Ua{~HhEpO3Oe z`q4TkT9uCalazewD6I{SF(Y(dchHfqp3O=h5;#+{n+$tq3h$De9^F2*xgTOMfGPZ@ z<$2;gBD3BoNt&_Ng4*eBu2_KO(L-asrT8sSCUStGeFL9U8xzB@<0=Tp&}Kav@ES)Z zj280Re5oZ}qHR~6@%FspDdVeTEHPx>t^UP}vg=mg(^+TN=rrb- zUvxfsWnaIJ$Sjl>wWscJ5sH9R2ztprSeeEI|5L4`pEUlNac2o12n^$hj7VI%U)Xf4 z>n!zHQd9KmV>|4(p@D9157v7Gh+h3SBZB?GMlK_n@fwfTf01mIK(eHMjwcgg+?~C*ve^ zyT2M>dqsV?bpOj-^!eAl8#NvC3o4TSq?fA01fA34+v$T|<+eNCw(CMQvstz;c*AYr zH11uWo|U_=Dasj1#xghBc?$SmNMWhiq-EI58OmnrLR?nou+K6qY-)_=lY>!8uGpt9is8P*r;Ez5eJlTjg(Wr;Ykw+bTDJvJnGO!{{!`A$lAD2H z6^>vX-v3x<{f~8r-=6c2lKm$UJ5nlbsSo&!MTCmAyk@3fsW+vD!88-+6GDKx{2&_< zpr8q{)66nY-xBkC-^r1Lug9CH z9Sel|$@m;vt}YGcz@<<5E1R?CVzVos;#4%3ko^JI;b}eMTT0hcOZdTm0cri%Us^h7;SHV^<-<}{{J1r{*9lionfz{4k6s`WP#VH0J}$gt z@(&xyNfc1%2&A0Xbk|D{ZAciDcIU#pHavfUxn_Cu=K;^+WVQr9OcA|MF3g}7_F0vE za8g4U@(TAooV+O2dwY6!pzfxBzz)B?Kd78KZ?P0N1LND8RN+i}%Kt2UcM$sjisH5y z#L+)-0H8I8wQm;RD#IFBa^)a%?xUm)pvgvc{h8^QFmN+M+3O3bacOUnP@1Xlya|ol&@&?v65bi720R=`?xvP11x&$#* zJicd57-UP%TwYAx?mFF3p4C4Ze8`|BsmJX^kt9b#z6l!71;xQCW7jGa8kUq$P956d zmxu;Pf~KkJeVhx6z><6Mlig^Us@!CoEs;+P1K%Bb%MFZ{tC zf%t}glR~9rZ6a-2!yd$IFylYo(r=25Jl(h$ZC)k%@??zFc2YV7yY+}jh7R(s7J#LV z*-vp+pLh4suCFQ4?fNAS47nbI{7&+h!(=6{T3NV6*qHqYJ~8lltbFg#qT{n?cB4Ry zjzpM7V)wRCL4oS@*L(mf>PxNnk9v)p zx>x8_fWTP9D`8^rPTPrd_{2LydjLb5lzow2Tks^wa^GGAB?vP%&(!8P^z0Wr>SwP> zCpbY6nv6Er(rj!;ozmhNsyFNI_4?AFaB$4_Q)#wC(2%wER!hTJ>AkQ!LOrrPK}U(H zuXAabH#n-51EJn(*23vu&|i^9Br6HsFGRdlplw5WF%Tx&6t363mp&4E>X*xgDsz8} z5)}RDDxNJyg3$l)S&+#7zkCaq|EK=F3tHF3sL?Hs%d+tSSgzhN5&Al7weD25#Bawv z6^yR1J7u3ZhPx_;N3#wM^#mbNWh^B1C)=NXDF{S&Ovdt%@e_z?AdqPv3NRVS;~QLI z%rd7ku+Ge5*^Ag)rUszm4SDIc6}MYDn(qGgDBbUNsNz9=ZRb)HVJc0;8rx`&RUR^g zyonc%=AxO1%|ZUx&tRVFr{8IRo{JV2seJvNNG#663e~&oPG@4zZHzm@x&CPxxTe7| zedzxd{)|fgcp`57q`owq^E`$i>!t(mH>aFEk{PE17pgHOX%#4|m8h@D1PF{7o+ z_e^DhV;c>6Ceks_p4(#}UUOKhw67y9B#+9{S^;7y(2cCf6-EMUJfe*9#G-c%5s1iN zGu(${WiI9g;lpxWJLh7@s7=xLvHYAoR^S%YPt;xF+jlFA|4{fIhAv$9u_ znP&O^QyBEh7d%ncNdQX^xyh*vfmPyyag78$cw75)fz{ zZa9XC%0OVuXMTDpA^pHbOFoBz5cIU{_VFK%S{P?3oEdjJ^ggAG|NQGg!KO zdbr?zz?dlj2i@^p&!0k1XmAX1?C7t9?uHMlb*oSAn(U?(OXKaHXU!|JX(@MLO`yfT zqp$oi1o|QjN^xA9gI!HX$3Q0Yjo!PPons<9l`T)*r0Tp^TM8}6`9TmC{HsYA*weUn z+(F{gc4yzLr=tkDQqMNwp!6}E$owD~dKo=Y%|!onwqy9a7jSRW9A&-Yy z?1QwHxEQ@IZ`ZjYVz0F0pQH`cKS~6Y&gY*bLuu*UFtm`sp-*(L;3hXWv>0BWGeOBy zkftH=^`t_%!ZLf8nd^ah^ydtKikE0wKwH*;qu_fD%BjPv^=!MN*_#?& zi?`qZ*N23Q|GVMv30BDjw)1_exEy-w^uqSq?@&LIY!OoLpILce5%$1j6RQ<-HF^oh zYZsPl&aGXWKI@6@*Ldv*KZTy>)4qz}&|>dgD}vMaD=118|49zDu&c5{3_P9MVi{sa z)~_$Z_Cgqu(F?enLL8b8_qOaZ_9E3zjgj92Lx?`y`)qxK(sw4diK zO{{XPA0%!#Gx$chu2GBv#37j9XPUd>gWFcz}MsYvqou6k=N;_NSm6T8tw=9 z`TQCSG29uQbMg?fB?2eAFtj45$9NAYg zVJWbW%$PK_$3$-@Vv0t;-@Cnl@-mr9X;xS-Y6KKH{u#GxBLedAM`-Z$VswBjP0G^1 zo7Li^R`b#0$6-_0$kX3YK>%=puk$e;_zk=e5B*hoq-y+m_3f*s&vfgMzz_8rn+i)c zWptIU0FM)O}&ageL4ZK;x+rd@(z&V%zKEh z(&n7D|LB^oba78P5V1)SxG`r8ha%-3;G@(Du$L?8l2rpLA}oe7s=>2%5|oXo)#32 zv3&ZO{AQRO<4OpfuG*lY$1=1RqnH?%{{S*T03?(YvvF(eCZ-_$FwlC?@digzD3aq3 zNbVSoZz!eGWdaa7J{0>=@h9FzX@`MO(De9l2j5a4&_P1Z?fzGfy;PAAE}`;rd%N9=6%h*1TM$;o1-bh(pKxc`aB5GH9|dOC1D-3ri!&^)$V+0daAfWuOl52H*||J{W||J401g8cdJg2jaKCf{o1Rg$Dv>FD}XSivHEklMuwpaju` zBnY<9Wkdofur$}N%k2#hbS8+=pjX;)$PdH0GG|ICC#PuPsd+Ikp^ez-#y?)QoLLG3 zi!`2ky$RlG#qwg$#BP$*!|1WTn0Dx07+0Z2Iof%;ix}G+=(&R;c`yCwZ`Tv-*W8Gi z5BrDT;V^FgQZ^>|S;7^vy-{fR5P>QB*RzYX z_PB)JIu03-*htDQnZaY$^qXGkv$u1wSUFcjfk$~5DDo8n%z zS?`oEzQJPVFy9QL64&wJwZtgi;m+!i^nNiQ$x&Ajx~!V_!)sIn=fib8*>~P&JnnUQ5dX%@!3pG8oV~zoBEK!9f*pxLWOA4Rhqfr=7D1bO|HxRDUPYLz-E8^05 z)zF32Ym*A_JdE^qJkE54El#cD>F10+bI#^ISuGPhRc<+KskQ*lnwOR=BQE!Hv25T4U2K&QhDvx zp;&Au9hrxdH7>D=nVfpf3RV0I2QlmYuI_kSQO=ih^M^mv-yXK_>CTP7@QjQM_?sXU z`n^3B9O;Z9Uy@I{TZ-=-$LP(kXDOX{+f8Ma2gbO<>j^LlYI4wxZSLkp*CsMvUyQH1 zjsk-JQQ^B84(y6)6}C?$r;#^vc63Gf{qxiHT2C3gQ+;?uZ8HCpa7Byjzp@$da28vWb(+!{-k*Ox~x~B%3Z-NrOwu%!mVty=cSnf)s4nc~v>hZq)#GP=1#W$_F(Q;npj4j$CMJ)q*;3=Vb} zAeNSlSS|* zQaBQNVuDOmn9aNXN~v+cCLeY>!_>7lO;AG}CT>QF#s_%4O|d0=hFs5WUXMWH^CoD5G+%RhcNAWSb+gYU#4Y8WGQSYFuwGRK@&ua0L-LK4Qf9fAvue-P0SDKxcEAH5nJ_}fOavgro z1q8~tv=qi69FFNbMgb%SoNJmS3?vDv}eeu^+n9%Q^71oo=RwSq$M$ zXE^jfztSkT^?_p{sHT4+RE5lrwA?o1}sC5E(-tbF_H=a1|czu~G!Ig#JL<3F<-#&6h3f!4L)aUth-G!clIxA~5~;+^%3Ilf{Hs<}irc=xQ8d{3ySD5$3c((r@E-8|NRYif|{qF~1d7={IWux!@(or$hix z`C^}%ew^Hg3WMRX4&`ijR)piUVlXUQRUi0bUJO>xi+ICn9oW6prigzw(Mk?fb1vxf zgRT|T9G;ENV+VHtJOTNE_R`t>gym~{?w{Ar*IV>G zS`AHPC!*@l9H7}krCPoPOag4<5mdbS{kwp0H|lk$G9Je7q01ljgh=hx|3hW{KUBsU zTc~c2Uu;WlRyJMtymK~Q3!sBy#Hx$GEOhiuC6958d-ca8jKnWmhwd&mEC@^pOg(tK zAoO*cG+yAS$&e+hA6*1cE{`hZTl#voPrAjEAoX8ES6a7mg5(G0P#sVIPNTh~O=~!v zMtfIf)Ur=f$TV6HYo-Ly^y+n~WbS#{hx4U61d&(<>92kk^tEU#bUXS^;x{-ZznS+!(%35$?D6-cK>t(o?SI z^of#}A~kAt@4Dz2!4{#+=-Y*#mYHDjt@-MYvn{q`6F2CuU@8-k;)Pip1HQoz6kCyV zzG@>r&dWD|wSL3M++*zPDVl9IrIkj~rIK-U0W&+U=4wr|k(Cs|CTEl3EEpaP8#<}2 zUln!h_*~rfxwztnpQV^Re_MA2=*z~&`%vi9e>|c2$CJD{2?0g*I1{2Ke^C{eqvt7S z&fbg*n#Kf-^pe}#%C-d;0l2v;DiZEQFyhloQzb;3*M!Gpg>%c^x| zM?$>3ATR$=jVA!H3@IO_@OUCx9e3py&pZ<*Wu?NC9-TqF0#qJ0abLD-H4gEuCr84# zCCsTPni|?AfNapy`;)uhFlM>^Nmp;pV`aT~(c#!jxMu+SIKYF$&T|x&s$9J=&ert3 zrJCnT@{U9CUKOWM2mmLm(a_JWMc>!x&3sr6h^Ey%L3fdZ=EsSZ(~%TVuibr0^YQ98 zOeH1QI;^;Cq^a6Lcf%yO=Ss!sSeR|WZO_Q10~8h~&rH*i7G{00yquROc4DV0>FA>r zqw8MmxA|eRad5;8`fauGI@NKpa)f9``zokeG(hJF(wSHdl8$%C*^!%2_KabsX#XX^ zIOZFuAE{SGHfSQlY&VDwHEx*{K@ z5W2bN!^+>jKq<5AC2BgQx|AXGF46AA6|$~}t<6?v>qJ)cwjdiHtF?xEP-89plu$zi;rU+^nj&VMtuQt=|M!#Y{rkyFP%^sKngSuJIKY6N z4X&YetkHhZ6O~m<1}%~_!155c(Z`y68=ST7PPzW5jE;PJu)xffbQKjI>E();F8wyF z8!C+Inv8YN%zr;g6D^jov}YE1`Qs$zFD7Bj;u+TNNJGTw8Q1bj?Dn4ZK<%wb@1C{X zfd;|v&jdP?2j5>yzo}jsDJix4$vb#bOPQ-@lKU*Ma{p=b72q`mvyMo&bN3_KAz#z; zD!!{pF-Kkb>uY`jX}>lHTv#re>!>ux+X5Ftjg$w+i7=@&Ml22-w^YO6fm61G4{oZ_Q!}s%pi8+x*<@%xzqhaJvnz+au)C{PTa)M(nF zKQ0&%)s1B<|JyN-#Oe3TzrHbkjr6BdOp=g3MNESU^~I9Gs;|m&Lt4r_#7{;RdGaI# zy2|IU6BsoM@M_r^Jj6+edszDo`M{sQ<@7Y2)|jEd33ywsX?+wNdyi{y-w%+}*)1M( zJ{4-DAY8VLoL2kk*?hK|ZW&l81js3DRq3x2hjwli91|NZUE z=fzF_se?p|bf!O!#r$$!S{knz*cI?({QVnFb%3Ly7#8%j<=t>=Wy6?qwT%ss&77M2 ze75t}!h2mDZM3OYFRE;_tLIm^md#M^Q+n{JudH`00BLK`>H`Ai>Ypydx?2 z+|xphDG)aTqD@YflIEJ_8VWv@DXZvG!tJ7P@NJH$@!5GO23?BT22(YdFXK0IHMN+h zwh3iABv?2kt<`vKhS87N%TqCW6&-=qjDLdKy%XqDRFDo{P}j4E>bk{4_`i*#e@b^l z)mzN^enevT6iGkPHQ9DOA;3A;PV9x`;iShOTg}4BuX$QRj$(YwK7Wn0XmMP13TVE{(dv#^gJF1k*YM&ac-H4C% z<(Nuv`CVh$`i}?&&!FD-s2Y1h2JhCRJ}ia#YcaaUjm_f z4ZP-{G2ZjwK4W2LF5L`w@T$RZIs0-lDs&_^_-1)b`+EAWo&h*I-P*xNYXym>((PAD zeAsp4Xj&9me|PEkda{%zts*n$!xwCS2eIgQw_JkVrFIzN?A`iKK^Eb4Ql`*IPAeF` zf*e?gqly_8=%ohH#W+8zB=pj!^D0^)q4>I2Ws|bw`gb4RgE)7)PZtqfuhM@h;I~gT z(kHmWOFVG;$NZhU$&*X%1t%l}`ACafY01cbj2dwzn(>2=1yDCBTt4egrD8eC~`z zU8g|NOOd=#{R{()rp~Fh8EOI%Pz|Az_+xY4ug{3^qiB#%Z$7>1w#U?InoDSvm?)mC zBPaN{TD3E0FEZGXapGsnnXh!4Xdt=A5iIB)|1@eB9>?GihYgi zZf*;M5O!6_$ZX@=;lr~g`FsLxtcyo`@E+3G!|uZ~W1vyp>+0_3E5M`s6cI#^&dBdr z0{e8j?VEa_3j6@gn2uugqPh+Rf#{?Wr2MF~Uw-iqc5V|EgNiH-zt|~$SYcI|Ndz0x zRpF({Y`Vdv#sk=0PE^^41bm~G4a~IkNLg7KJd?d=?$sFGC`L!h()*c=R{m&l_N`5R zX?7LO5?P0$$`7;MkooBu*gd9{+i}qBtu|gaK(0X^AvXU}rJQ1PvFiowc~4ys9?V(t z$J?OkR8w&v|Mi!SvRj|4GevQfwa3QaN6ZNE$36Q$4I)?W2+a)jhVWzFUh)T(n96F! ziIrM2MIxMd<^yA(pypPqXYQ}FmzF`3W~j)T3-zwv{7GkG;O<+Ce6~+M>D17Do=)88 zRiv|z(GRxKrpwgj$*Wkfu)&;7WC$GfM~mC?xs~P?g?IFM#R=uSq$#f5$r$e*H~bBw z*ZR`CLdTwYUEuA08uBm4p0)57$Hhrrr7cw8I^tE}1&R!CSzNN_^B@!u^!|nrwB*t` zk5a<%KzAT1O;d;u{cN{JT4@9HAznC`!Q@?uBwZG!$PN7*oWzDbWUsQ+ACohSWI&=t zwR^1xY5*9;KW)&!y`9D@ARUBtDEztUDv0z`E)UqYc$M2@yLUie`c<)>n9sI3Fe!-4 zJAP8?FrY&f|5iNndd^_0TRgfny3SS&er$1%-dmFTtm;VSNtoBYcLQen3g-MdH#Vg{ z?G{}icEjLwgIxPQ{#nqi%s(A;HChshz~xeI7qLDg?IHY+V;OcH6B_sfGV<3lp59J^bMUhrVd)jgT^v1<}9Qy7|P^K-q&K4m5&F z+#+-J$2a!Mq=}plU6{mqZyJ{KZF4wrgPKxb^1z-VAZXk>Jw*WRtpH>Qmo!>Ix$L{= z&CGh}YAH|1m^a#Sn^z!gN-w=ky?3>fe!C7 zOT4vtt4(Tea7zgPdf9VLI|ci*SUn8fbE5K1KXhS&kNFnRVa{r)N){kmB*!_BBfi8S z3{QH>@&Ow*;O4Stu=m1WkaJ622p#&Ka(g^m?mMmZ`y0)Rq5`W87hU85WguDp#8VAk$WB-)))HY3Ryn=gek%JSHR~{db5UmF{v?hz+*aGt z>CVsNkeRx9P?)`4`S1)^M>DyPF18^C`;BV#F-7jP1)AK(<{Nu)qH!wz>4~0`o7n5= z^c_ zQ^HJ7of42cdrKovTdB2zPIZS3gg|3~j3iUxaU$lIc!fp$pIp}V=|9!KAkGit3~y~L z2}whA`_zf!jX9O~T% zPP)p@d+7a|pTcA|CL?$5hv>zgi1dZa5fb+N4?>B^OE5$eO8Ro6^I66088Sd#s->)^`QO_OY_Hwc3 zEt6sfzZP8Bg9Q?X;J0G*A1_v2yX{&U`_|MEZsDa@P-sN!`>kUoK`QR5-aLBBj-9~Crg zI#pfL4%Mk&KH$E3SRmkp;v3VS;AAK!BB*DKnjp+%!*d8tHw@ zfaM89R_0{UD~cvaahWQtdr|EO9zEUaXr@8E_=MEzjw#VJb_`m7mB<3++FUn!4Wcyq zSzOP_{td^6v#rmQQM+!d4%pQ=2z+VD{|0aeMXTG}cNIV$_>n5nyYy&+80fC9xd#tB zl4Q$=)E9;Sc)&<&y{DR>kVssTe$0F0(K<+MP>1V`&YV^{#B5AFaoq1)yABhD(10aY zI0ZA$ea+Di*4kSR6X!p+TK4Wg^V2lm&8+$5a$I!q)W%)m&RX+0*HLeJUsiMQ7%R$A z`YdO{?T|0a=p;#Lc^P>x4LIWtM@4!wscsDIOy9_)BmQk-Lc`-%DMMN+f=tv)d~ED{ zUv?y2A_*M7eMyEwxN3<4ynbH5`9$H5*&pKRT4c|TJnY;SPwfhOg8EWbt(7t&wQu_6 z9drnk_2znfuM^l@ntXd_Y2h1NTHo>}K|PfpIUA~f7y|jtuzWSsAoKe8S~0CmI#wX> zXd=lEHIEjp3-D$rBY|coo_tPsf7w1R?bN*&RH=qnFy-~hMTKAVLLCgW*dmtr8_e-N z$}TG%zf%O-qPKffN}Sk1EF(n?_DL~C+HMF1*iV_V{BW9BcX30GK-r-6as?7Ij5WJ#W&k?5%`z7HoI7K&O~3gv z=oV*x-6&7kFBLtU7S+kO=h@-~PWT)3qnV%FWVDpJbiVbX6459VPp4Wv8&M<}D`&s% zm5@F-`kb!ix0|PzPRJZWDBSVaME6_bvkaU4^G;Hk%f-ITTjf*x2~_`PGUZYgB>@w8 zOS;{fD=~(BP2{$Z^jEc|70dBOOjpx-tfoOv!Gq=vuV(QxLO0KITWyCGk}dZ>Nw3W_q}a?z3NY_0(k|g z&{>{1tl!_LeH8gJAVil^?#f8;LQ(d5y>Y#Pck>yd$Nc>It!EQs*PFWCjNpfNjacmp zpO^ZoY7b+ca@j6D!@k?92DQ$$ z3cMY#2LpRvW|kA-R{i{pm7&+SCdu~;n$C}dFNvM@+Fbt@g_LF@O+JUb|DHEsXn13x zc^{g^-S)UT3aLRlbb`TaHs{A&>IJ&ZK9LA`2e+9VC@mb~kY->$BX#rKh-y{aKuuZs z@gRlg)>6x-R1pzo<#Pgy`siljo+2mk~RMQ*F+)}(Er(1K}MJ@O0Bx&^oM!c zH$J1{>h->FHAWw=7R8TxWMVC@58|yL^G2iTgV?;jBN;0jKMhM09y-0o`Og&4a$LBsBXPSmApwPx|rT31^9$Z@9Rqr zkZH06fzp^b1}Xu&d0XQfQWBEwqp#=JG9ia;ONqG%;yIgP4>-LdB5zQ!wfGtRC`3(d z^nE_E4nceIn+h;{wMF5T;M9T7T66K9VczwTHI)mhuU+RDnOIy`20Q2G=}2J41Veen z4?4*ouKP<1U;OdRY%X6-DHx1FVEeA^;D$2?_E6CUq*m`nRp%gS4j^g#67MJtDb$Mt zH+x?6-T2iXmZaLkZ17G`SunzPr0SNC|PoMH^3Th zX9eM(IoT`-@6bU4JoXdxd#UJN$1$2caB4N6vjY2nS^!v0OVb~W+}eG%MS&Yzet3@U zo-jzHZc7vsR0EqC6`!cfVtKI0qZ@9xxHhse$cB$Tj+naxbh~5NWKr{6suTxaJlFPi zhG>FkZLTd7T@(o%ys{Z*_IpN?;vr-tU7p^2_dP(*vxbEP5~>|z(ZbPw*H9a8UKo{k zy(+>~^S|=sry5cMfPGFXtY*GD_Zk$Y<|Bv0Fz>u*y_DNP`;UPda&v|Q8^!mF7Ma8R{tQ^@I{?-RTL!uB)2*zLOJi&~#vt~^g?x}QygMC-KZ z2NOb{C!~363CD_N62^WCO1X0RwtUmkYdR2Z@Vi+uuFpO#bR0wkjUH08-g|EY78$R^urx-1(r zGDsGx=LMyfw)FXAiT;$~BG+ znB3zynyoPGks7Uc8xO|U5sqFU$EfFL3404kgym0Xfj?DSzTFt$L$&1vhVln z1(fEH8q)DqOz-r zq~QYaI5Cc$ZLg|$s_8CVD3F$z<;C<#2*kGh>Ni)}l`TMbq8((_YM6aMsaN2LR` zf`8MqPsNi>H;9s@8Dy+`fdMS?9GBpqG>}OxTStv_&39-vCVmPe4_j{Bn)DXazQ2Cu z>iPtH3!^Pz$(gY)&Z&6A4(loXx`ImQG`*07LM5j@vfyh#+@5uj2tJ)a*OoJ3Ynb>- zIrqX_(f7@c&3Ws=$P7<+M$xSR0QKbN`oQSYmr-yH)T8;nIz8+V23ssoX8nbE*bzZ2U%;t&rK*V z4p;Je?q7RNxZ^GA-P`LnRuY&#);__5@nS;1QbxZxUmNztUO{V@ZOIAt^mZoriVB;t zyklSQKd;2@3x|AOFKFanebdFMk@!EW{?htqRgvdz;Hm)cFiZ)PvpV`Q@#*|e(*lWu zFXW*5nAMMc-&_rqCiQ%xL0Qx8BV66UqYK_Y+v5qMQw4e|TJvZZ`=zu+Z{bZ3j_ zM0t2-FNguCKW>=`LnavSW5wCQ0%dA~5&^wcmGyg!cE*DYbgl05@9yGT9i5+Sxz4%+ zJ$?kzBkNoD!LO`ndDkNXe{=plGMK7M*TQOF#hK1qN1juyf>0-KyuNFPvvH-z=8a5E~)yIAzDdfbt zuk;6bi9=DnFl{-3EcFV#uwN^sH|dyzj*gW$?#HyuD|Ap@YVQhJh%o=x2Yf0$_rYn4 zQXEuU-Ny6Vbjt3NSxmf8_*PmA&?DD`PjO$Sl}l%Dq+%#J94vb?vYHtpGi+aVb|FDd?fb`n2LCZG2oMDBL`kDweK96GCQhsdTqQd+ z7|^f~{c6yt`V2Jsq+5Xc3EcP2g7TZYp&>04y6e7f)%c-KC@ebHJe4AR%VWwqHpuFF z2|LR@<^@3Hn9;YmoT>^+(zUZ+dS0fu9g+i)R8txeB5lHwKrA7T!*1?=q<3-x##%3H zz;(mG<<}Nmm~B6#c~DlyD;BC=re-LPN?vuv5|6+8Mp;pdqRp8R)mFdovCCk=r55Ol zfR_n}49yO0;cJvxOD-={b-gL;&G7WTe1@oCct{aE&?ME2AMi8x)$ysj8r9)|1*&KL z(;3qJ)23q!rFGMzjH|;%7V;D$w|O+Ha>hTKU6HYucsZG+lM(MpURk7vTVFkcRiQf0 zQL98V(}$Oz_7Cq2AJ&yiT1Ce$ZPI@b4C%uz&EUsIUU8uTL$xK_5_!qrV8H)UwL|$X z-yr3lVy-cCD5t|E1;SUY@*kWS@@==zS_l?Z(TmNBIFVa>Mip!II67=?G zamP394or|avVt!*eTL9>H{3g4(r%NldsCRlN}gg=^uBF%%kF}P-5cKf>cU`Abrj)i zVbj{+8~^*0ZsGWCdRyd516IJ&`dQDn$v?bZ0_tCjM|--Umx-u_19K=Ik1*IODN)=tA!GUJTc_$6#{5v_pX|1h@Xk!*3%^=Ke%WGm1w|(`FstC?K68N zTd&NBd=k&KAGsO9OQ|Z!iZW)DhNxZcss_7Y-~J3Hf~Koe@cg@Am;Et+b1%4up#sp! zxd6r#rw^|pohGz<~BO8dp1ti+-$cz zu+WM=7@qS|7QwTXB~VwU8HR78TeyCko;sN4<&X7VR!Gz z0r$KEU-iB3#UWJp%g#fLUk)AL>PN$6|MSSKTqNU5a%sEXxcWzwD)O~*_bfprWPYT3 zKajn|rmkZ9YrIx9OU_k6E9TFjpNaCfWn|w`6{kP1k*1HNFWH*}4(lX6W5f7$Gp6>B zyy4fu&3SnpwwYFKR_qc)1#RGSSI$tD**K}6)ZVXQm^(V!F-Zh_#{Vqs{#mvDUaN3T z>{^g9Cy`S;&Q6cZ9b4xdM1P4wE`4OvYQ#!ra&JMM0QV0=PiqFCRdg)1UvIMwwtyd} zFAhCOoWX8QuY^wO(Ir-XOpvBiay~h0lxlDFnaM-+zD*E#4rDR%k*nQev6S9XE*H0@ ztj=7(q^ddm_P(bZ{W_63Yq8eZe?i@W`Qo_o0M zbnPJsnLPG~b~}yNb54M{9$rxH6FM36_Me%Agx{L~L{9OA9RGcl zdjWd$i<&lnZ~+2ghWZ!0oYwKDS1gSpcI8J0PR~K)ZmK631nK-!C+>^IDhrgziNAf~ zc7<0Y{jn$Xn>v6%m{=x5!+k4k5Ga#_mQ)65Q z_p@#VA1zuc`R^@knDiO*ZWaihs;aUpfthm%AFNYMfB@K&162y6jAqQxl8n%Vse-Cj zG0@Lkzv-ZC`kBrim$@pPX@@(%J$!sCz#YrBtCw)ei4;s2xkrIYhA*ekx@W$boo8 zz-$)s2ROFW(Rq676N~+6gNdOsq7Fgf|ByawCFh@QsTGj2&!hu>GMItpbfN{n zn3RlgVe=1EuhK+AZ8MY^mv>^poon6-Yuj`XkKcdlv|L2JEor-F1B#joqlnZW99UOw z`v+#*CQE4f?k=8e7$WND0{fWL!LO+V@Y>_HzooCiBbt-XKPv=Kb0{bYNJL{4*fZyh z&BVw0wsxT3Ozvws@}Q&pE0n>xtmW5jRrjn7usVgY4WyE|5j{XsKA&u6$M~KeDVRbg z{)>U04_`N_*_=#bP|z;%U^Au%n%x@oEbtB8RaTaS&wUmBxRb|qOP-^xpAK4r*yKtgqW(Qn_%B4Ym;3n=cVG;o0p{y zKQ;>hNNOCZ^TB>&$c!N`-RAwQK(|jpL|<(tv91-yPpI6mlkxfOrxf>tGux7KkOm$U zLk#|`{XpPjK*8*ab{aYQV*n+U-}5>>4>Wt2GAY2B9*^I<)c&Q=xYrQDM&r;}b<4dqFy8mr`sMMtWo@giZM^Bk7`VC4s5@~sEp$@7C;9q@xjhw zSSZok85}|6HCEiHpqNB?vz3P2R@9A4xKg@s>l2^heh-<6|cRGGUR6Jz_&~qt` zoM0iia>Cy}Vn>O(aB>@3&=QhF@Xd{|<7Z$-6~-7`SG`gh7yp}yLyz)b_=LIrXF4sW z%42j*Mat$E5a4eeJUQ$-?UYP$gi!wy!$s6(u0%waxRY$Yh;YK(964zQybgBqz>KB?DbV85^0{)P_Nz{Bd*ndOV z-XqYMvzI&4BhcJc#~neu*WnA%Q;;$HQdk;dy_PB*bxg)09&EPiMhLcajQM0C6{dMH zFrY{2bS>ZIM z7qoSXnZ+#IkCIdlVQD{R{or)&?|Ym=`{W=;QpM5|Bpr!-r8=vK^TDO`MO*wE+c!`5ns~K&MWhvv zAh_>B6cH#{bvJgXNxwgT$Q=xV32XQ<%x;1)=;VEyDxiR=L>T*AcJhN$$NREg|7Ks= z=l6`=I>^CLQmVu(1o5XlV}^?Rz3GGoz))-hTPAD^ z_qf~emK84@Nzu);Klckv!7H1|n2G1EJzN*_dmaD%W#jo=mF1PLi>ts?T)P)_mvwlma-)yttW zBj+^iq8MF7W~u^s)x{3y)eZ^9>G|IWT0~*}U)xXL^KjdJNmg?)Y>0HDB!6Y9%RsH0 z8abdHEF8g5@CwZ?j>+`&LjTJ|Hxqn?wnV4aF=f1C@bEaKMpc59llQ>B?on(|g*itH zub;Z*wbzQ%*9W$^^al*>sx+q!9zBb#^oG0@;dA1~~T%MEk1TslO$LUcJ~Ah|-7Xn$dOh zslVmv&R@Bjy&``5y8yM{@YiZS^V+9C=I_+NvYn4c?2V`s8>;2Z%OIy|nAKON1e$jF) z=yA(Xp)L^e@u5$x{@STrLtZOZCH8as zp^?syI6+!C2?xwxTy@{zGeOUApaHR_az?$fo0h> zgE)G_OM@pvsMgj>X%o?%iHvmJ`4pXO#ph%w$(pR%qMzQg05a9*k7NK;{m0=FN@vbM zrl_r3ne3BB|IXAsRW1i41Z_>xHox?K%ynd+GuL|hLh%DvnuOyxBJoFB@;7x+PhWxb zb5g=@wjS9$*La9EW@-6g6awdr-q(J4r@cGR7${tm0aSuL7paw>vOc1~ntoxWzR5`* z2KG7{hV}s|AJF{K?0FE@E+Cpkw!do)CDxy=f34aNtcOz<;ITKjSf4#tJrrIN?E7f# z?v7OEzeMuzO6f7{a&|wjpVUcw)56h2aWJ|i?Kv;)o7|;4=lF%i&PTuOY^Bn7gLmx7 zxm@&3;RAdKcLJO0ey7mk#Zljak0N6@~w8&l2{gd7u{50c6M)n(=j zNR9Yft~{<}TT&9W>zBA4E8&pMEHiiQvv0IbUmkm(Dbrq^rXHvgOLo}cvHm;^GI5{b zeJTY72$%Rg`JrduN=E~ohq7LXxV7rIXSX30hc=ZYH1J}AcJ{;p#0oKgmh6c`mQ8>Iu}_mtN<}I^#-YM?&INYTWsCYCO{=ZQO zNkqV<6dj7l2Mns$h$9?-Q=s~H_bGOfu3e#^l75i+HV4}zqrS>WrN%_w1}zrtMkfPBApMWW4@=WBThiav?r zEIT6Mdt8~L@qJGK{4<-fzqW79o@}BUnPj|@*utvKa4|x%JwJE7L$CJ^6={z+#m)3b zunU~G#}Rp-N74d_oMo`gJyPHYG6xA{n*M3GBa^x#w*EgweB1cMmhup+!|a<^fBs`E zM-f^7(HJKY;8AOA+B1kRJpujo1?sQ<{-Sw;vHM2pDhnJHD(OvTcKJ5yL2U{nPX(Gv zBOyBiX!C*)8<{}Zh2YOKvzbW9U2Og<#1>V1yQr+hqV?iRn6+tDDn<0eg15Wj!D7h! zVjheWi$-5cLam(EP>*!HO$a83r(SC!Kf}QR%+MG!46Wt zYed&I?(eeeDWEg!nIM=cXT0UyCwLuCD)oJ6B_XPs*?V(SpRm}fnDzn)CU*-|60<7> z{!`Q$F9F)_`S~H>Ry!JwW@9>Z9yn#p3>QQm0`{rnyTC|kp~@cAN0nJ*->{M?bjG}7*u=;BwZyI|CH%JUG!CjFoF0qlhZ zhmONTsutOIUDDuKgRb&--pOYkfyOE6atU~sAn042lFi`#2TAaxSIP9F84Q=Hc8q_{E zte-}R>vbi@|GNU`G&kk-&XE7bJ;X(;Cgv}(@{g;vL6{uRd>{rp$V0h!La9u=L|9VI z+0g5y+x$_R*K`}<2pU%m*=w2M%|BA@kcz}d&3bDI46Ac}1w`Wbv0yThGxj^^#^?FU zRfz^vSRm3>xCx|H9tR-8>rAlFKry6vApmalzeiem`DOK{lD?J08^=FQ{W|Ykav(;3 znP+5}MD_1!%mq1$%c?tOPf_sZ?yEnac4s2}mM_I*UZ3O_wDe-72*fYSOq)4B8Fz99 zB);H$xg8b;@)sw%t}} zE6Q_f&<1okxleTm=HC^3ITqB2_fJ zvoiA^o+1SPbrwh4*b`Y|O470!U!g{*aUk9UdPQw)N2=Oqv)l8Gv18+C*1aKLJMOh< z6!r<*D{jv-tcH(UZ~JNTSDdZH@r^sKmPAIQAItfP>B@KlRVnIhxJ+gTnWMd17u{X{ zIvk|h6OF|^98cI`xw)Tolmtcmaso`MP&BwA{C7)IRa@NW@z3vv#HU9ekN&i{-6UK( zgbtWtbP>05v7mw0V}b=`Uhm_F0w-7PZaDrXnkO*nh`0*GqvEs9r?VEr*=~GHM@1bIGiEr!H zKYEpjo+axqf6#uT0sreEqI5S|;3|Jk7&Tk~$Ht zczV~g#0&pl`(+fN82qo=U5PQk40^pztbfXz%Q1k;Mb%V+2DQ^La$oay9*SYZfR<|?4%N3(t@CWo>t;7c?kV#- zb0Sq3Y8(rx$+>OEob74J8 z$CnUYS}f+co`>N}*Bf)XkksSFrU*1| zr1!<9!e10ag(za)cA$vo!!baa8@2{&eKj~Xh0OCr80{RI^vL>AGPuY^=;g%C}3C-tiweu zfM&-*Jm=~*0!v;f?+rdW0o_M2wk}jQfE;xxro+4o_}$^~_kO~38!2H4YTR6P#(DS2 z4Z~Cx;rh4H!jUu@{z->9b}mkkPZA+}CyxJ@Y{1E*QwvE)k0Jv8i~IKdb5E3@;QnwY z^j^s`gPT6;x~74)?ENRZ>}DwC4fnr@HAVMdq5eR-5G%WUFCJs`6T@MDu^`-90VZbU zb2hln?lthvHuJP!0c}je-Wgy8)9+*xqZ5`wtVqlbe{M&cJI^%HHCNN2Gti^TSJp3_ zt#N2%@5MEoV|C6h3}2xa#4Qc*_+IY-AKd2Q9gySrmPoO-u-I3aJ9p5ga=E6C+^6~T zads4=rWTG2URPbBulzXnM1&m3_K~2canYVIUKT%xSM$LLJ^FY-1ErnvuN%l==V2<^ zVg!fCD+d2i3K5tT*Llp^Wlj_e;`5V6P|a9ftCGp$&QXrG$$Z{P8+q~a=iUm{*^Bmy zm!*Y~W*<8$AL~`b$^yx;?nnB3JmvM#qyC$)A-Qb(Px%9T7#D1pY44Cfj*p&m$0t1E zyun*7|MjAY_r7*~&_%tnTYR5Ik-odnS(tbX|LT4q*R*eIB=c-;Lb23m*jw%UX+IS= zhP)L@Ylkbb97>X(`+#{-jHeoa(vc~H;SeM(4r=$km@$amAsD+2No3`fjjTw4YDIF` z^BG9+uZJq&UMdEkwWm=dcT{k)mg>54rsNu^Xee=_y4RuJHu$gkf&8DcM}xQ;=Rp#? z3SQggtqNQ&V#Z{5n7wgW%aj1pQ0qhM-j_~v+d{3eO{yiE+&F$8eRLQBB8G`_2_?(> z3Mi9Dwt|7N5NBZl;^-M7(fDEU56_NS5e}>pi^_F&e(O<27E%4OtsL)7znQ{%B&4hN zbfBFO?;iJGO~3MA^BBIfDdiKn=sQGihA|MSt{f8nY!X-KwVtryKE1@y`-m-lUL7+- z9^(|3>|w3+AOi6zO4MK08hUS$(;xK=Z;bTN%p-7t!nKi&SNp*WwU_t53bq z7)6TMCnp?>{&-|TMaGPSBbLE~v_waLJ(yN^q78 zVGd!zm;<~Q2_#pS(|ejVoDivhZ}uyayP&|Bi|X*LSRN!^ z=S}+<-34S;_~cDVMAZpmd+}>|`-fakI_g|3lmNOgG_^3a_Y5{KD{{s2t?y%#Y$Cf~ zt542S(naK8Mg-7d20-aBQO0!$w9OOqPDGtsAWGslEzF*@I9vCA=QJb94VJ?V0`@+B zZOOKl*GdH`--k)F#E()EO9WJ>j%0A_NyFbYWGW$N{X=5G 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

    + +
    + 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)
    From 84d4a8d2ab2461cbc2a18ae0f06002dc59dccb02 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Fri, 22 Mar 2019 16:42:54 +0100 Subject: [PATCH 309/507] Added Tensor<0> instantiation --- source/fe/fe_values_extractors.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/fe/fe_values_extractors.cc b/source/fe/fe_values_extractors.cc index 8d0c417f6eb5..751fdcafdb09 100644 --- a/source/fe/fe_values_extractors.cc +++ b/source/fe/fe_values_extractors.cc @@ -53,6 +53,7 @@ namespace FEValuesExtractors } // Explicit instantiations + template struct Tensor<0>; template struct Tensor<1>; template struct Tensor<2>; template struct Tensor<3>; From 6be05fa06147de6b65241c105a2d10418b15a80c Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Tue, 19 Mar 2019 13:39:57 +0100 Subject: [PATCH 310/507] add SparsityTools::gather_sparsity_pattern() --- doc/news/changes/minor/20190319DenisDavydov_b | 3 + .../deal.II/lac/dynamic_sparsity_pattern.h | 6 + include/deal.II/lac/sparsity_tools.h | 28 +++++ source/lac/dynamic_sparsity_pattern.cc | 19 +++ source/lac/sparsity_tools.cc | 111 ++++++++++++++++++ tests/sparsity/dynamic_sparsity_pattern_19.cc | 105 +++++++++++++++++ ...ynamic_sparsity_pattern_19.mpirun=3.output | 71 +++++++++++ 7 files changed, 343 insertions(+) create mode 100644 doc/news/changes/minor/20190319DenisDavydov_b create mode 100644 tests/sparsity/dynamic_sparsity_pattern_19.cc create mode 100644 tests/sparsity/dynamic_sparsity_pattern_19.mpirun=3.output 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/include/deal.II/lac/dynamic_sparsity_pattern.h b/include/deal.II/lac/dynamic_sparsity_pattern.h index ed2a200179cc..372f7fadf529 100644 --- a/include/deal.II/lac/dynamic_sparsity_pattern.h +++ b/include/deal.II/lac/dynamic_sparsity_pattern.h @@ -518,6 +518,12 @@ class DynamicSparsityPattern : public Subscriptor size_type row_length(const size_type row) const; + /** + * Clear all entries stored in a specific row. + */ + void + clear_row(const size_type row); + /** * Access to column number field. Return the column number of the @p * indexth entry in @p row. diff --git a/include/deal.II/lac/sparsity_tools.h b/include/deal.II/lac/sparsity_tools.h index e428bef3ff48..d681b847968c 100644 --- a/include/deal.II/lac/sparsity_tools.h +++ b/include/deal.II/lac/sparsity_tools.h @@ -292,6 +292,34 @@ namespace SparsityTools const MPI_Comm & mpi_comm, const IndexSet & myrange); + /** + * Gather rows in a dynamic sparsity pattern over MPI. + * The function is similar to SparsityTools::distribute(), + * however instead of distributing sparsity stored in non-owned + * rows on this MPI process, this function will gather sparsity + * from other MPI processes and will add this to the local + * DynamicSparsityPattern. + * + * @param dsp A dynamic sparsity pattern that has been built locally and which + * we need to extend according to the sparsity of rows stored on other MPI + * processes. + * + * @param owned_rows_per_processor A vector containing owned rows for each + * process in the MPI communicator. This input should be the same on all MPI + * processes. + * + * @param mpi_comm The MPI communicator shared between the processors that + * participate in this operation. + * + * @param ghost_range The range of rows this MPI process needs to gather. + * Only a part which is not included in the locally owned rows will be used. + */ + void + gather_sparsity_pattern(DynamicSparsityPattern & dsp, + const std::vector &owned_rows_per_processor, + const MPI_Comm & mpi_comm, + const IndexSet & ghost_range); + #endif diff --git a/source/lac/dynamic_sparsity_pattern.cc b/source/lac/dynamic_sparsity_pattern.cc index 95ca12cdc4b7..c697a45a1b42 100644 --- a/source/lac/dynamic_sparsity_pattern.cc +++ b/source/lac/dynamic_sparsity_pattern.cc @@ -406,6 +406,25 @@ DynamicSparsityPattern::symmetrize() +void +DynamicSparsityPattern::clear_row(const size_type row) +{ + AssertIndexRange(row, n_rows()); + if (!have_entries) + return; + + if (rowset.size() > 0 && !rowset.is_element(row)) + return; + + const size_type rowindex = + rowset.size() == 0 ? row : rowset.index_within_set(row); + + AssertIndexRange(rowindex, lines.size()); + lines[rowindex].entries = std::vector(); +} + + + template void DynamicSparsityPattern::compute_Tmmult_pattern( diff --git a/source/lac/sparsity_tools.cc b/source/lac/sparsity_tools.cc index 1a18621296bc..b62a712c26b7 100644 --- a/source/lac/sparsity_tools.cc +++ b/source/lac/sparsity_tools.cc @@ -911,6 +911,117 @@ namespace SparsityTools #ifdef DEAL_II_WITH_MPI + + void + gather_sparsity_pattern(DynamicSparsityPattern & dsp, + const std::vector &owned, + const MPI_Comm & mpi_comm, + const IndexSet & ghost_range) + { + const unsigned int myid = Utilities::MPI::this_mpi_process(mpi_comm); + + AssertDimension(owned.size(), Utilities::MPI::n_mpi_processes(mpi_comm)); +# ifdef DEBUG + for (const auto &set : owned) + Assert(set.is_contiguous(), ExcNotImplemented()); +# endif + + Assert(owned[myid].is_ascending_and_one_to_one(mpi_comm), + ExcNotImplemented()); + + std::vector start_index(owned.size() + + 1); + start_index[0] = 0; + for (DynamicSparsityPattern::size_type i = 0; i < owned.size(); ++i) + start_index[i + 1] = start_index[i] + owned[i].n_elements(); + + using map_vec_t = + std::map>; + + // 1. limit rows to non owned: + IndexSet requested_rows(ghost_range); + requested_rows.subtract_set(owned[myid]); + + // 2. go through requested_rows, figure out the owner and add the row to + // request + map_vec_t rows_data; + { + unsigned int cpu_rank = 0; + for (const auto &row : requested_rows) + { + // calculate destination CPU + while (row >= start_index[cpu_rank + 1]) + ++cpu_rank; + + // since we removed owned, we should not end up with + // our rows + Assert(cpu_rank != myid, ExcInternalError()); + + rows_data[cpu_rank].push_back(row); + } + } + + // 3. get what others ask us to send + const auto rows_data_received = + Utilities::MPI::some_to_some(mpi_comm, rows_data); + + // 4. now prepare data to be sent in the same format as in + // distribute_sparsity_pattern() below, i.e. + // rX,num_rX,cols_rX + map_vec_t send_data; + for (const auto &data : rows_data_received) + { + for (const auto &row : data.second) + { + const auto rlen = dsp.row_length(row); + + // skip empty lines + if (rlen == 0) + continue; + + // save entries + send_data[data.first].push_back(row); // row index + send_data[data.first].push_back(rlen); // number of entries + for (DynamicSparsityPattern::size_type c = 0; c < rlen; ++c) + send_data[data.first].push_back( + dsp.column_number(row, c)); // columns + } // loop over rows + } // loop over received data + + // 5. communicate rows + const auto received_data = + Utilities::MPI::some_to_some(mpi_comm, send_data); + + // 6. add result to our sparsity + for (const auto &data : received_data) + { + const auto &recv_buf = data.second; + auto ptr = recv_buf.begin(); + const auto end = recv_buf.end(); + while (ptr != end) + { + const auto row = *(ptr++); + Assert(ptr != end, ExcInternalError()); + + const auto n_entries = *(ptr++); + Assert(n_entries > 0, ExcInternalError()); + Assert(ptr != end, ExcInternalError()); + + // make sure we clear whatever was previously stored + // in these rows. Otherwise we can't guarantee that the + // data is consistent across MPI communicator. + dsp.clear_row(row); + + Assert(ptr + (n_entries - 1) != end, ExcInternalError()); + dsp.add_entries(row, ptr, ptr + n_entries, true); + ptr += n_entries; + } + Assert(ptr == end, ExcInternalError()); + } + } + + + void distribute_sparsity_pattern( DynamicSparsityPattern & dsp, diff --git a/tests/sparsity/dynamic_sparsity_pattern_19.cc b/tests/sparsity/dynamic_sparsity_pattern_19.cc new file mode 100644 index 000000000000..b0b8d0f497bf --- /dev/null +++ b/tests/sparsity/dynamic_sparsity_pattern_19.cc @@ -0,0 +1,105 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + + +// check SparsityTools::gather_sparsity_pattern() + +#include + +#include "../tests.h" + + +void +test() +{ + const unsigned int N = 10; + MPI_Comm comm(MPI_COMM_WORLD); + const unsigned int myid = Utilities::MPI::this_mpi_process(comm); + + IndexSet owned(N); + if (myid == 0) + owned.add_range(0, 3); + else if (myid == 1) + owned.add_range(3, 7); + else + owned.add_range(7, 10); + + const auto rows_per_cpu = Utilities::MPI::all_gather(comm, owned); + + IndexSet ghost_range(owned); + if (myid == 0) + { + ghost_range.add_range(3, 5); + } + else if (myid == 1) + { + ghost_range.add_range(1, 3); + ghost_range.add_range(7, 9); + } + else + { + ghost_range.add_range(4, 7); + } + + DynamicSparsityPattern dsp; + dsp.reinit(N, N); + // hard-code some sparsity + if (myid == 0) + { + for (unsigned int i = 0; i < 3; ++i) + for (unsigned int j = 0; j < 5 + i; ++j) + dsp.add(i, j); + + // add to ghost to make sure they are reset + dsp.add(3, 9); + } + else if (myid == 1) + { + for (unsigned int i = 3; i < 5; ++i) + for (unsigned int j = 0; j < 5 + i; ++j) + dsp.add(i, j); + + for (unsigned int i = 5; i < 7; ++i) + for (unsigned int j = i - 4; j < 10; ++j) + dsp.add(i, j); + } + else + { + for (unsigned int i = 7; i < 10; ++i) + for (unsigned int j = i - 4; j < 10; ++j) + dsp.add(i, j); + } + + deallog << "Before gather_sparsity_pattern:" << std::endl; + dsp.print(deallog.get_file_stream()); + + SparsityTools::gather_sparsity_pattern(dsp, rows_per_cpu, comm, ghost_range); + + deallog << "After gather_sparsity_pattern:" << std::endl; + dsp.print(deallog.get_file_stream()); +} + + +int +main(int argc, char **argv) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + MPILogInitAll log; + + test(); + return 0; +} diff --git a/tests/sparsity/dynamic_sparsity_pattern_19.mpirun=3.output b/tests/sparsity/dynamic_sparsity_pattern_19.mpirun=3.output new file mode 100644 index 000000000000..fd13cba169f2 --- /dev/null +++ b/tests/sparsity/dynamic_sparsity_pattern_19.mpirun=3.output @@ -0,0 +1,71 @@ + +DEAL:0::Before gather_sparsity_pattern: +[0,0,1,2,3,4] +[1,0,1,2,3,4,5] +[2,0,1,2,3,4,5,6] +[3,9] +[4] +[5] +[6] +[7] +[8] +[9] +DEAL:0::After gather_sparsity_pattern: +[0,0,1,2,3,4] +[1,0,1,2,3,4,5] +[2,0,1,2,3,4,5,6] +[3,0,1,2,3,4,5,6,7] +[4,0,1,2,3,4,5,6,7,8] +[5] +[6] +[7] +[8] +[9] + +DEAL:1::Before gather_sparsity_pattern: +[0] +[1] +[2] +[3,0,1,2,3,4,5,6,7] +[4,0,1,2,3,4,5,6,7,8] +[5,1,2,3,4,5,6,7,8,9] +[6,2,3,4,5,6,7,8,9] +[7] +[8] +[9] +DEAL:1::After gather_sparsity_pattern: +[0] +[1,0,1,2,3,4,5] +[2,0,1,2,3,4,5,6] +[3,0,1,2,3,4,5,6,7] +[4,0,1,2,3,4,5,6,7,8] +[5,1,2,3,4,5,6,7,8,9] +[6,2,3,4,5,6,7,8,9] +[7,3,4,5,6,7,8,9] +[8,4,5,6,7,8,9] +[9] + + +DEAL:2::Before gather_sparsity_pattern: +[0] +[1] +[2] +[3] +[4] +[5] +[6] +[7,3,4,5,6,7,8,9] +[8,4,5,6,7,8,9] +[9,5,6,7,8,9] +DEAL:2::After gather_sparsity_pattern: +[0] +[1] +[2] +[3] +[4,0,1,2,3,4,5,6,7,8] +[5,1,2,3,4,5,6,7,8,9] +[6,2,3,4,5,6,7,8,9] +[7,3,4,5,6,7,8,9] +[8,4,5,6,7,8,9] +[9,5,6,7,8,9] + From 35aed646e7878f1bb5fd0f1a9948e5ec5b2f3b2d Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Sat, 23 Mar 2019 03:12:19 +0100 Subject: [PATCH 311/507] New variant of mesh_loop. --- doc/news/changes/minor/20190323LucaHeltai | 3 + include/deal.II/meshworker/mesh_loop.h | 110 ++++++++++++++++ tests/meshworker/mesh_loop_class_01.cc | 144 +++++++++++++++++++++ tests/meshworker/mesh_loop_class_01.output | 55 ++++++++ 4 files changed, 312 insertions(+) create mode 100644 doc/news/changes/minor/20190323LucaHeltai create mode 100644 tests/meshworker/mesh_loop_class_01.cc create mode 100644 tests/meshworker/mesh_loop_class_01.output diff --git a/doc/news/changes/minor/20190323LucaHeltai b/doc/news/changes/minor/20190323LucaHeltai new file mode 100644 index 000000000000..265ceaaf7c17 --- /dev/null +++ b/doc/news/changes/minor/20190323LucaHeltai @@ -0,0 +1,3 @@ +New: Added a variant of mesh_loop that takes a class and its member functions as workers and copiers. +
    +(Luca Heltai, 2019/03/23) diff --git a/include/deal.II/meshworker/mesh_loop.h b/include/deal.II/meshworker/mesh_loop.h index f2a53f05023b..8589fbba064b 100644 --- a/include/deal.II/meshworker/mesh_loop.h +++ b/include/deal.II/meshworker/mesh_loop.h @@ -392,6 +392,116 @@ namespace MeshWorker queue_length, chunk_size); } + + /** + * This is a variant of the mesh_loop function, that can be used for worker + * and copier functions that are member functions of a class. + * + * The argument passed as @p end must be convertible to the same type as @p + * begin, but doesn't have to be of the same type itself. This allows to + * write code like mesh_loop(dof_handler.begin_active(), + * dof_handler.end(), ... where the first is of type + * DoFHandler::active_cell_iterator whereas the second is of type + * DoFHandler::raw_cell_iterator. + * + * The @p queue_length argument indicates the number of items that can be + * live at any given time. Each item consists of @p chunk_size elements of + * the input stream that will be worked on by the worker and copier + * functions one after the other on the same thread. + * + * @note If your data objects are large, or their constructors are + * expensive, it is helpful to keep in mind that queue_length + * copies of the ScratchData object and + * queue_length*chunk_size copies of the CopyData object + * are generated. + * + * @ingroup MeshWorker + * @author Luca Heltai, 2019 + */ + template + void + mesh_loop(const CellIteratorType & begin, + const typename identity::type &end, + MainClass & main_class, + void (MainClass::*cell_worker)(const CellIteratorType &, + ScratchData &, + CopyData &), + void (MainClass::*copier)(const CopyData &), + const ScratchData & sample_scratch_data, + const CopyData & sample_copy_data, + const AssembleFlags flags = assemble_own_cells, + void (MainClass::*boundary_worker)(const CellIteratorType &, + const unsigned int, + ScratchData &, + CopyData &) = nullptr, + void (MainClass::*face_worker)(const CellIteratorType &, + const unsigned int, + const unsigned int, + const CellIteratorType &, + const unsigned int, + const unsigned int, + ScratchData &, + CopyData &) = nullptr, + const unsigned int queue_length = 2 * MultithreadInfo::n_threads(), + const unsigned int chunk_size = 8) + { + std::function + f_cell_worker; + + std::function + f_boundary_worker; + + std::function + f_face_worker; + + if (cell_worker != nullptr) + f_cell_worker = std::bind(cell_worker, + std::ref(main_class), + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3); + + if (boundary_worker != nullptr) + f_boundary_worker = std::bind(boundary_worker, + std::ref(main_class), + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4); + + if (face_worker != nullptr) + f_face_worker = std::bind(face_worker, + std::ref(main_class), + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + std::placeholders::_5, + std::placeholders::_6, + std::placeholders::_7, + std::placeholders::_8); + + mesh_loop(begin, + end, + f_cell_worker, + std::bind(copier, main_class, std::placeholders::_1), + sample_scratch_data, + sample_copy_data, + flags, + f_boundary_worker, + f_face_worker); + } } // namespace MeshWorker DEAL_II_NAMESPACE_CLOSE diff --git a/tests/meshworker/mesh_loop_class_01.cc b/tests/meshworker/mesh_loop_class_01.cc new file mode 100644 index 000000000000..bda23d029d24 --- /dev/null +++ b/tests/meshworker/mesh_loop_class_01.cc @@ -0,0 +1,144 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Test assembly using a class and mesh_loop + +#include + +#include +#include +#include + +#include +#include + +#include + +#include "../tests.h" + +using namespace MeshWorker; + +struct ScratchData +{}; +struct CopyData +{}; + +template +class TestClass +{ +public: + using CellIteratorType = + typename Triangulation::active_cell_iterator; + + void + cell_worker(const CellIteratorType &cell, ScratchData &, CopyData &) + { + deallog << "Workgin on cell " << cell << std::endl; + } + + void + copier(const CopyData &) + {} + + void + boundary_worker(const CellIteratorType &cell, + const unsigned int f, + ScratchData &, + CopyData &) + { + deallog << "Boundary worker on : " << cell << ", Face : " << f << std::endl; + } + + void + face_worker(const CellIteratorType &cell, + const unsigned int f, + const unsigned int sf, + const CellIteratorType &ncell, + const unsigned int nf, + const unsigned int nsf, + ScratchData &, + CopyData &) + { + deallog << "Face worker on : " << cell << ", Neighbor cell : " << ncell + << ", Face : " << f << ", Neighbor Face : " << nf + << ", Subface: " << sf << ", Neighbor Subface: " << nsf + << std::endl; + } +}; + +template +void +test() +{ + Triangulation tria; + GridGenerator::hyper_cube(tria); + tria.refine_global(1); + tria.begin_active()->set_refine_flag(); + tria.execute_coarsening_and_refinement(); + + TestClass test_class; + ScratchData scratch; + CopyData copy; + + auto cell = tria.begin_active(); + auto endc = tria.end(); + + deallog << "CELLS ONLY" << std::endl; + mesh_loop(cell, + endc, + test_class, + &TestClass::cell_worker, + &TestClass::copier, + scratch, + copy, + assemble_own_cells); + + deallog << "CELLS+BOUNDARY" << std::endl; + + mesh_loop(cell, + endc, + test_class, + &TestClass::cell_worker, + &TestClass::copier, + scratch, + copy, + assemble_own_cells | assemble_boundary_faces, + &TestClass::boundary_worker); + + + deallog << "CELLS+BOUNDARY+FACES" << std::endl; + + mesh_loop(cell, + endc, + test_class, + &TestClass::cell_worker, + &TestClass::copier, + scratch, + copy, + assemble_own_cells | assemble_boundary_faces | + assemble_own_interior_faces_once, + &TestClass::boundary_worker, + &TestClass::face_worker); +} + + +int +main() +{ + initlog(); + MultithreadInfo::set_thread_limit(1); // to make output deterministic + + test<2, 2>(); +} diff --git a/tests/meshworker/mesh_loop_class_01.output b/tests/meshworker/mesh_loop_class_01.output new file mode 100644 index 000000000000..63a972588dd9 --- /dev/null +++ b/tests/meshworker/mesh_loop_class_01.output @@ -0,0 +1,55 @@ + +DEAL::CELLS ONLY +DEAL::Workgin on cell 1.1 +DEAL::Workgin on cell 1.2 +DEAL::Workgin on cell 1.3 +DEAL::Workgin on cell 2.0 +DEAL::Workgin on cell 2.1 +DEAL::Workgin on cell 2.2 +DEAL::Workgin on cell 2.3 +DEAL::CELLS+BOUNDARY +DEAL::Workgin on cell 1.1 +DEAL::Boundary worker on : 1.1, Face : 1 +DEAL::Boundary worker on : 1.1, Face : 2 +DEAL::Workgin on cell 1.2 +DEAL::Boundary worker on : 1.2, Face : 0 +DEAL::Boundary worker on : 1.2, Face : 3 +DEAL::Workgin on cell 1.3 +DEAL::Boundary worker on : 1.3, Face : 1 +DEAL::Boundary worker on : 1.3, Face : 3 +DEAL::Workgin on cell 2.0 +DEAL::Boundary worker on : 2.0, Face : 0 +DEAL::Boundary worker on : 2.0, Face : 2 +DEAL::Workgin on cell 2.1 +DEAL::Boundary worker on : 2.1, Face : 2 +DEAL::Workgin on cell 2.2 +DEAL::Boundary worker on : 2.2, Face : 0 +DEAL::Workgin on cell 2.3 +DEAL::CELLS+BOUNDARY+FACES +DEAL::Workgin on cell 1.1 +DEAL::Boundary worker on : 1.1, Face : 1 +DEAL::Boundary worker on : 1.1, Face : 2 +DEAL::Face worker on : 1.1, Neighbor cell : 1.3, Face : 3, Neighbor Face : 2, Subface: 4294967295, Neighbor Subface: 4294967295 +DEAL::Workgin on cell 1.2 +DEAL::Boundary worker on : 1.2, Face : 0 +DEAL::Face worker on : 1.2, Neighbor cell : 1.3, Face : 1, Neighbor Face : 0, Subface: 4294967295, Neighbor Subface: 4294967295 +DEAL::Boundary worker on : 1.2, Face : 3 +DEAL::Workgin on cell 1.3 +DEAL::Boundary worker on : 1.3, Face : 1 +DEAL::Boundary worker on : 1.3, Face : 3 +DEAL::Workgin on cell 2.0 +DEAL::Boundary worker on : 2.0, Face : 0 +DEAL::Face worker on : 2.0, Neighbor cell : 2.1, Face : 1, Neighbor Face : 0, Subface: 4294967295, Neighbor Subface: 4294967295 +DEAL::Boundary worker on : 2.0, Face : 2 +DEAL::Face worker on : 2.0, Neighbor cell : 2.2, Face : 3, Neighbor Face : 2, Subface: 4294967295, Neighbor Subface: 4294967295 +DEAL::Workgin on cell 2.1 +DEAL::Face worker on : 2.1, Neighbor cell : 1.1, Face : 1, Neighbor Face : 0, Subface: 4294967295, Neighbor Subface: 0 +DEAL::Boundary worker on : 2.1, Face : 2 +DEAL::Face worker on : 2.1, Neighbor cell : 2.3, Face : 3, Neighbor Face : 2, Subface: 4294967295, Neighbor Subface: 4294967295 +DEAL::Workgin on cell 2.2 +DEAL::Boundary worker on : 2.2, Face : 0 +DEAL::Face worker on : 2.2, Neighbor cell : 2.3, Face : 1, Neighbor Face : 0, Subface: 4294967295, Neighbor Subface: 4294967295 +DEAL::Face worker on : 2.2, Neighbor cell : 1.2, Face : 3, Neighbor Face : 2, Subface: 4294967295, Neighbor Subface: 0 +DEAL::Workgin on cell 2.3 +DEAL::Face worker on : 2.3, Neighbor cell : 1.1, Face : 1, Neighbor Face : 0, Subface: 4294967295, Neighbor Subface: 1 +DEAL::Face worker on : 2.3, Neighbor cell : 1.2, Face : 3, Neighbor Face : 2, Subface: 4294967295, Neighbor Subface: 1 From 2325e6aa4c666d06ebf54575fe28dcf303be8df8 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Wed, 20 Mar 2019 00:24:12 +0100 Subject: [PATCH 312/507] FEValuesViews::View --- doc/news/changes/minor/20190320LucaHeltai | 5 ++ include/deal.II/fe/fe_values.h | 75 +++++++++++++++++++++++ tests/fe/fe_values_views_types.cc | 67 ++++++++++++++++++++ tests/fe/fe_values_views_types.output | 46 ++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 doc/news/changes/minor/20190320LucaHeltai create mode 100644 tests/fe/fe_values_views_types.cc create mode 100644 tests/fe/fe_values_views_types.output 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/include/deal.II/fe/fe_values.h b/include/deal.II/fe/fe_values.h index 713f1c64adad..71b50d966407 100644 --- a/include/deal.II/fe/fe_values.h +++ b/include/deal.II/fe/fe_values.h @@ -1871,6 +1871,69 @@ namespace internal { namespace FEValuesViews { + /** + * A class whose specialization is used to define what FEValuesViews + * object corresponds to the given FEValuesExtractors object. + * + * @author Luca Heltai, 2019. + */ + template + struct ViewType + {}; + + /** + * A class whose specialization is used to define what FEValuesViews + * object corresponds to the given FEValuesExtractors object. + * + * When using FEValuesExtractors::Scalar, the corresponding view is an + * FEValuesViews::Scalar. + */ + template + struct ViewType + { + using type = typename dealii::FEValuesViews::Scalar; + }; + + /** + * A class whose specialization is used to define what FEValuesViews + * object corresponds to the given FEValuesExtractors object. + * + * When using FEValuesExtractors::Vector, the corresponding view is an + * FEValuesViews::Vector. + */ + template + struct ViewType + { + using type = typename dealii::FEValuesViews::Vector; + }; + + /** + * A class whose specialization is used to define what FEValuesViews + * object corresponds to the given FEValuesExtractors object. + * + * When using FEValuesExtractors::Tensor, the corresponding view is an + * FEValuesViews::Tensor. + */ + template + struct ViewType> + { + using type = typename dealii::FEValuesViews::Tensor; + }; + + /** + * A class whose specialization is used to define what FEValuesViews + * object corresponds to the given FEValuesExtractors object. + * + * When using FEValuesExtractors::SymmetricTensor, the corresponding + * view is an FEValuesViews::SymmetricTensor. + */ + template + struct ViewType> + { + using type = + typename dealii::FEValuesViews::SymmetricTensor; + }; + /** * A class objects of which store a collection of FEValuesViews::Scalar, * FEValuesViews::Vector, etc object. The FEValuesBase class uses it to @@ -1900,6 +1963,18 @@ namespace internal } // namespace FEValuesViews } // namespace internal +namespace FEValuesViews +{ + /** + * A templated alias that associates to a given Extractor class + * the corresponding view in FEValuesViews. + * + * @author Luca Heltai, 2019. + */ + template + using View = + typename internal::FEValuesViews::ViewType::type; +} // namespace FEValuesViews /** diff --git a/tests/fe/fe_values_views_types.cc b/tests/fe/fe_values_views_types.cc new file mode 100644 index 000000000000..e6f573900a24 --- /dev/null +++ b/tests/fe/fe_values_views_types.cc @@ -0,0 +1,67 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Test FEValuesViews::View + +#include + +#include + +#include "../tests.h" + +template +void +test(const Extractor &) +{ + typename FEValuesViews::View::template OutputType< + double>::value_type t1; + + typename FEValuesViews::View::template OutputType< + double>::gradient_type t2; + + deallog << "Test<" << Utilities::dim_string(dim, spacedim) << ">" << std::endl + << Utilities::type_to_string(t1) << std::endl + << Utilities::type_to_string(t2) << std::endl; +} + +int +main() +{ + initlog(); + + FEValuesExtractors::Scalar scalar(0); + FEValuesExtractors::Vector vector(1); + FEValuesExtractors::Tensor<2> tensor(2); + + test<1, 1>(scalar); + test<1, 1>(vector); + test<1, 1>(tensor); + + test<1, 2>(scalar); + test<1, 2>(vector); + test<1, 2>(tensor); + + test<2, 2>(scalar); + test<2, 2>(vector); + test<2, 2>(tensor); + + test<2, 3>(scalar); + test<2, 3>(vector); + test<2, 3>(tensor); + + test<3, 3>(scalar); + test<3, 3>(vector); + test<3, 3>(tensor); +} diff --git a/tests/fe/fe_values_views_types.output b/tests/fe/fe_values_views_types.output new file mode 100644 index 000000000000..5eacce960a2d --- /dev/null +++ b/tests/fe/fe_values_views_types.output @@ -0,0 +1,46 @@ + +DEAL::Test<1> +DEAL::double +DEAL::dealii::Tensor<1, 1, double> +DEAL::Test<1> +DEAL::dealii::Tensor<1, 1, double> +DEAL::dealii::Tensor<2, 1, double> +DEAL::Test<1> +DEAL::dealii::Tensor<2, 1, double> +DEAL::dealii::Tensor<3, 1, double> +DEAL::Test<1,2> +DEAL::double +DEAL::dealii::Tensor<1, 2, double> +DEAL::Test<1,2> +DEAL::dealii::Tensor<1, 2, double> +DEAL::dealii::Tensor<2, 2, double> +DEAL::Test<1,2> +DEAL::dealii::Tensor<2, 2, double> +DEAL::dealii::Tensor<3, 2, double> +DEAL::Test<2> +DEAL::double +DEAL::dealii::Tensor<1, 2, double> +DEAL::Test<2> +DEAL::dealii::Tensor<1, 2, double> +DEAL::dealii::Tensor<2, 2, double> +DEAL::Test<2> +DEAL::dealii::Tensor<2, 2, double> +DEAL::dealii::Tensor<3, 2, double> +DEAL::Test<2,3> +DEAL::double +DEAL::dealii::Tensor<1, 3, double> +DEAL::Test<2,3> +DEAL::dealii::Tensor<1, 3, double> +DEAL::dealii::Tensor<2, 3, double> +DEAL::Test<2,3> +DEAL::dealii::Tensor<2, 3, double> +DEAL::dealii::Tensor<3, 3, double> +DEAL::Test<3> +DEAL::double +DEAL::dealii::Tensor<1, 3, double> +DEAL::Test<3> +DEAL::dealii::Tensor<1, 3, double> +DEAL::dealii::Tensor<2, 3, double> +DEAL::Test<3> +DEAL::dealii::Tensor<2, 3, double> +DEAL::dealii::Tensor<3, 3, double> From 8e227a8497a5dd75b3d9a0e1d08525249cacc706 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 23 Mar 2019 04:00:35 +0100 Subject: [PATCH 313/507] Create local variables in output_results --- examples/step-41/step-41.cc | 11 +++++------ examples/step-42/step-42.cc | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/examples/step-41/step-41.cc b/examples/step-41/step-41.cc index 662829c1507b..f2e5ec11716b 100644 --- a/examples/step-41/step-41.cc +++ b/examples/step-41/step-41.cc @@ -101,7 +101,6 @@ namespace Step41 TrilinosWrappers::SparseMatrix complete_system_matrix; TrilinosWrappers::MPI::Vector solution; - TrilinosWrappers::MPI::Vector active_set_vector; TrilinosWrappers::MPI::Vector system_rhs; TrilinosWrappers::MPI::Vector complete_system_rhs; TrilinosWrappers::MPI::Vector diagonal_of_mass_matrix; @@ -262,7 +261,6 @@ namespace Step41 IndexSet solution_index_set = dof_handler.locally_owned_dofs(); solution.reinit(solution_index_set, MPI_COMM_WORLD); - active_set_vector.reinit(solution_index_set, MPI_COMM_WORLD); system_rhs.reinit(solution_index_set, MPI_COMM_WORLD); complete_system_rhs.reinit(solution_index_set, MPI_COMM_WORLD); contact_force.reinit(solution_index_set, MPI_COMM_WORLD); @@ -544,10 +542,6 @@ namespace Step41 BoundaryValues(), constraints); constraints.close(); - - active_set_vector = 0.; - for (const auto index : active_set) - active_set_vector[index] = 1.; } // @sect4{ObstacleProblem::solve} @@ -588,6 +582,11 @@ namespace Step41 { 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); diff --git a/examples/step-42/step-42.cc b/examples/step-42/step-42.cc index ec2b52df7944..5b6127b94263 100644 --- a/examples/step-42/step-42.cc +++ b/examples/step-42/step-42.cc @@ -701,7 +701,6 @@ namespace Step42 TrilinosWrappers::SparseMatrix newton_matrix; TrilinosWrappers::MPI::Vector solution; - TrilinosWrappers::MPI::Vector active_set_vector; TrilinosWrappers::MPI::Vector newton_rhs; TrilinosWrappers::MPI::Vector newton_rhs_uncondensed; TrilinosWrappers::MPI::Vector diag_mass_matrix_vector; @@ -1023,7 +1022,6 @@ namespace Step42 { TimerOutput::Scope t(computing_timer, "Setup: vectors"); solution.reinit(locally_relevant_dofs, mpi_communicator); - active_set_vector.reinit(locally_relevant_dofs, MPI_COMM_WORLD); newton_rhs.reinit(locally_owned_dofs, mpi_communicator); newton_rhs_uncondensed.reinit(locally_owned_dofs, mpi_communicator); diag_mass_matrix_vector.reinit(locally_owned_dofs, mpi_communicator); @@ -1341,14 +1339,6 @@ namespace Step42 all_constraints.close(); all_constraints.merge(constraints_dirichlet_and_hanging_nodes); - // We misuse distributed_solution for updating active_set_vector. - // We can do that because distributed_solution has a compatible underlying - // IndexSet and we don't need the vector anymore. - distributed_solution = 0.; - for (const auto index : active_set) - distributed_solution[index] = 1.; - active_set_vector = distributed_solution; - pcout << " Size of active set: " << Utilities::MPI::sum((active_set & locally_owned_dofs).n_elements(), mpi_communicator) @@ -2037,6 +2027,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; From 58d1cb115547e27141a38df25996d3cf155df3bf Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 23 Mar 2019 04:01:02 +0100 Subject: [PATCH 314/507] Range-based for loop --- examples/step-42/step-42.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/step-42/step-42.cc b/examples/step-42/step-42.cc index 5b6127b94263..32394d47b7bb 100644 --- a/examples/step-42/step-42.cc +++ b/examples/step-42/step-42.cc @@ -1549,10 +1549,7 @@ namespace Step42 fraction_of_plastic_q_points_per_cell = 0; - auto cell = dof_handler.begin_active(); - const auto 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); @@ -1569,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) { From ec6b54594a5b1a81b7b9de696f54ac51efd95ac3 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sat, 23 Mar 2019 04:02:15 +0100 Subject: [PATCH 315/507] Remove a helper function for DataOut_DoFData --- .../numerics/data_out_dof_data.templates.h | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/include/deal.II/numerics/data_out_dof_data.templates.h b/include/deal.II/numerics/data_out_dof_data.templates.h index 8f492389d791..e499cc548829 100644 --- a/include/deal.II/numerics/data_out_dof_data.templates.h +++ b/include/deal.II/numerics/data_out_dof_data.templates.h @@ -629,21 +629,6 @@ namespace internal {} - template - inline typename VectorType::value_type - get_vector_element(const VectorType &vector, const unsigned int cell_number) - { - return internal::ElementAccess::get(vector, cell_number); - } - - - inline double - get_vector_element(const IndexSet &is, const unsigned int cell_number) - { - return (is.is_element(cell_number) ? 1 : 0); - } - - template double @@ -651,8 +636,9 @@ namespace internal const unsigned int cell_number, const ComponentExtractor extract_component) const { - return get_component(get_vector_element(*vector, cell_number), - extract_component); + return get_component( + internal::ElementAccess::get(*vector, cell_number), + extract_component); } From 52148c0b5af11e34c3cad073574055372b364fc6 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Sat, 23 Mar 2019 11:46:30 +0100 Subject: [PATCH 316/507] Fixed typos. --- doc/news/changes/minor/20190323LucaHeltai | 3 +- include/deal.II/meshworker/mesh_loop.h | 31 ++++++++++++++-- tests/meshworker/mesh_loop_class_01.cc | 2 +- tests/meshworker/mesh_loop_class_01.output | 42 +++++++++++----------- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/doc/news/changes/minor/20190323LucaHeltai b/doc/news/changes/minor/20190323LucaHeltai index 265ceaaf7c17..d4b08ab3de45 100644 --- a/doc/news/changes/minor/20190323LucaHeltai +++ b/doc/news/changes/minor/20190323LucaHeltai @@ -1,3 +1,4 @@ -New: Added a variant of mesh_loop that takes a class and its member functions as workers and copiers. +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/include/deal.II/meshworker/mesh_loop.h b/include/deal.II/meshworker/mesh_loop.h index 8589fbba064b..8a76d18bc1d1 100644 --- a/include/deal.II/meshworker/mesh_loop.h +++ b/include/deal.II/meshworker/mesh_loop.h @@ -394,13 +394,13 @@ namespace MeshWorker } /** - * This is a variant of the mesh_loop function, that can be used for worker + * This is a variant of the mesh_loop() function, that can be used for worker * and copier functions that are member functions of a class. * * The argument passed as @p end must be convertible to the same type as @p * begin, but doesn't have to be of the same type itself. This allows to * write code like mesh_loop(dof_handler.begin_active(), - * dof_handler.end(), ... where the first is of type + * dof_handler.end(), ...) where the first is of type * DoFHandler::active_cell_iterator whereas the second is of type * DoFHandler::raw_cell_iterator. * @@ -415,6 +415,33 @@ namespace MeshWorker * queue_length*chunk_size copies of the CopyData object * are generated. * + * An example usage of the function is given by + * @code + * template + * class TestClass + * { + * public: + * void + * cell_worker(const CellIteratorType &cell, ScratchData &, CopyData &); + * + * ... + * }; + * + * ... + * TestClass test_class; + * ScratchData scratch; + * CopyData copy; + * + * mesh_loop(tria.begin_active(), + * tria.end(), + * test_class, + * &TestClass::cell_worker, + * &TestClass::copier, + * scratch, + * copy, + * assemble_own_cells); + * @endcode + * * @ingroup MeshWorker * @author Luca Heltai, 2019 */ diff --git a/tests/meshworker/mesh_loop_class_01.cc b/tests/meshworker/mesh_loop_class_01.cc index bda23d029d24..6550600dd61b 100644 --- a/tests/meshworker/mesh_loop_class_01.cc +++ b/tests/meshworker/mesh_loop_class_01.cc @@ -45,7 +45,7 @@ class TestClass void cell_worker(const CellIteratorType &cell, ScratchData &, CopyData &) { - deallog << "Workgin on cell " << cell << std::endl; + deallog << "Working on cell " << cell << std::endl; } void diff --git a/tests/meshworker/mesh_loop_class_01.output b/tests/meshworker/mesh_loop_class_01.output index 63a972588dd9..1aa484b21ebb 100644 --- a/tests/meshworker/mesh_loop_class_01.output +++ b/tests/meshworker/mesh_loop_class_01.output @@ -1,55 +1,55 @@ DEAL::CELLS ONLY -DEAL::Workgin on cell 1.1 -DEAL::Workgin on cell 1.2 -DEAL::Workgin on cell 1.3 -DEAL::Workgin on cell 2.0 -DEAL::Workgin on cell 2.1 -DEAL::Workgin on cell 2.2 -DEAL::Workgin on cell 2.3 +DEAL::Working on cell 1.1 +DEAL::Working on cell 1.2 +DEAL::Working on cell 1.3 +DEAL::Working on cell 2.0 +DEAL::Working on cell 2.1 +DEAL::Working on cell 2.2 +DEAL::Working on cell 2.3 DEAL::CELLS+BOUNDARY -DEAL::Workgin on cell 1.1 +DEAL::Working on cell 1.1 DEAL::Boundary worker on : 1.1, Face : 1 DEAL::Boundary worker on : 1.1, Face : 2 -DEAL::Workgin on cell 1.2 +DEAL::Working on cell 1.2 DEAL::Boundary worker on : 1.2, Face : 0 DEAL::Boundary worker on : 1.2, Face : 3 -DEAL::Workgin on cell 1.3 +DEAL::Working on cell 1.3 DEAL::Boundary worker on : 1.3, Face : 1 DEAL::Boundary worker on : 1.3, Face : 3 -DEAL::Workgin on cell 2.0 +DEAL::Working on cell 2.0 DEAL::Boundary worker on : 2.0, Face : 0 DEAL::Boundary worker on : 2.0, Face : 2 -DEAL::Workgin on cell 2.1 +DEAL::Working on cell 2.1 DEAL::Boundary worker on : 2.1, Face : 2 -DEAL::Workgin on cell 2.2 +DEAL::Working on cell 2.2 DEAL::Boundary worker on : 2.2, Face : 0 -DEAL::Workgin on cell 2.3 +DEAL::Working on cell 2.3 DEAL::CELLS+BOUNDARY+FACES -DEAL::Workgin on cell 1.1 +DEAL::Working on cell 1.1 DEAL::Boundary worker on : 1.1, Face : 1 DEAL::Boundary worker on : 1.1, Face : 2 DEAL::Face worker on : 1.1, Neighbor cell : 1.3, Face : 3, Neighbor Face : 2, Subface: 4294967295, Neighbor Subface: 4294967295 -DEAL::Workgin on cell 1.2 +DEAL::Working on cell 1.2 DEAL::Boundary worker on : 1.2, Face : 0 DEAL::Face worker on : 1.2, Neighbor cell : 1.3, Face : 1, Neighbor Face : 0, Subface: 4294967295, Neighbor Subface: 4294967295 DEAL::Boundary worker on : 1.2, Face : 3 -DEAL::Workgin on cell 1.3 +DEAL::Working on cell 1.3 DEAL::Boundary worker on : 1.3, Face : 1 DEAL::Boundary worker on : 1.3, Face : 3 -DEAL::Workgin on cell 2.0 +DEAL::Working on cell 2.0 DEAL::Boundary worker on : 2.0, Face : 0 DEAL::Face worker on : 2.0, Neighbor cell : 2.1, Face : 1, Neighbor Face : 0, Subface: 4294967295, Neighbor Subface: 4294967295 DEAL::Boundary worker on : 2.0, Face : 2 DEAL::Face worker on : 2.0, Neighbor cell : 2.2, Face : 3, Neighbor Face : 2, Subface: 4294967295, Neighbor Subface: 4294967295 -DEAL::Workgin on cell 2.1 +DEAL::Working on cell 2.1 DEAL::Face worker on : 2.1, Neighbor cell : 1.1, Face : 1, Neighbor Face : 0, Subface: 4294967295, Neighbor Subface: 0 DEAL::Boundary worker on : 2.1, Face : 2 DEAL::Face worker on : 2.1, Neighbor cell : 2.3, Face : 3, Neighbor Face : 2, Subface: 4294967295, Neighbor Subface: 4294967295 -DEAL::Workgin on cell 2.2 +DEAL::Working on cell 2.2 DEAL::Boundary worker on : 2.2, Face : 0 DEAL::Face worker on : 2.2, Neighbor cell : 2.3, Face : 1, Neighbor Face : 0, Subface: 4294967295, Neighbor Subface: 4294967295 DEAL::Face worker on : 2.2, Neighbor cell : 1.2, Face : 3, Neighbor Face : 2, Subface: 4294967295, Neighbor Subface: 0 -DEAL::Workgin on cell 2.3 +DEAL::Working on cell 2.3 DEAL::Face worker on : 2.3, Neighbor cell : 1.1, Face : 1, Neighbor Face : 0, Subface: 4294967295, Neighbor Subface: 1 DEAL::Face worker on : 2.3, Neighbor cell : 1.2, Face : 3, Neighbor Face : 2, Subface: 4294967295, Neighbor Subface: 1 From 704fb9c003aa49144e1f601620c6f9d22f5f1b3c Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sat, 23 Mar 2019 16:28:24 +0100 Subject: [PATCH 317/507] Improve example in new mesh_loop function --- include/deal.II/meshworker/mesh_loop.h | 34 ++++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/include/deal.II/meshworker/mesh_loop.h b/include/deal.II/meshworker/mesh_loop.h index 8a76d18bc1d1..d1244d395013 100644 --- a/include/deal.II/meshworker/mesh_loop.h +++ b/include/deal.II/meshworker/mesh_loop.h @@ -417,29 +417,37 @@ namespace MeshWorker * * An example usage of the function is given by * @code + * + * struct ScratchData; + * struct CopyData; + * * template - * class TestClass + * class MyClass * { * public: * void * cell_worker(const CellIteratorType &cell, ScratchData &, CopyData &); * + * void + * copier(const CopyData &); + * * ... * }; * - * ... - * TestClass test_class; - * ScratchData scratch; - * CopyData copy; + * ... + * + * MyClass my_class; + * SratchData scratch; + * CopyData copy; * - * mesh_loop(tria.begin_active(), - * tria.end(), - * test_class, - * &TestClass::cell_worker, - * &TestClass::copier, - * scratch, - * copy, - * assemble_own_cells); + * mesh_loop(tria.begin_active(), + * tria.end(), + * my_class, + * &MyClass::cell_worker, + * &MyClass::copier, + * scratch, + * copy, + * assemble_own_cells); * @endcode * * @ingroup MeshWorker From 12b0494f570392e488c04df158cc5457a5dd59d4 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sat, 23 Mar 2019 16:30:43 +0100 Subject: [PATCH 318/507] Pass queue_length and chunk_size to inner call to mesh_loop() --- include/deal.II/meshworker/mesh_loop.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/deal.II/meshworker/mesh_loop.h b/include/deal.II/meshworker/mesh_loop.h index d1244d395013..9aa0ff436991 100644 --- a/include/deal.II/meshworker/mesh_loop.h +++ b/include/deal.II/meshworker/mesh_loop.h @@ -535,7 +535,9 @@ namespace MeshWorker sample_copy_data, flags, f_boundary_worker, - f_face_worker); + f_face_worker, + queue_length, + chunk_size); } } // namespace MeshWorker From 80891eef627410791a88faf4208e51845be3a504 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 19 Mar 2019 22:47:24 +0100 Subject: [PATCH 319/507] New assign_co_dimensional_manifold_indicators function. --- doc/news/changes/minor/20190319LucaHeltai_b | 5 + include/deal.II/grid/grid_tools.h | 31 +- include/deal.II/grid/tria_accessor.h | 18 + .../deal.II/grid/tria_accessor.templates.h | 34 ++ source/grid/grid_tools.cc | 73 ++++ source/grid/grid_tools.inst.in | 6 + .../grid_tools_propagate_manifold_ids_01.cc | 74 ++++ ...rid_tools_propagate_manifold_ids_01.output | 367 ++++++++++++++++++ 8 files changed, 607 insertions(+), 1 deletion(-) create mode 100644 doc/news/changes/minor/20190319LucaHeltai_b create mode 100644 tests/grid/grid_tools_propagate_manifold_ids_01.cc create mode 100644 tests/grid/grid_tools_propagate_manifold_ids_01.output 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/include/deal.II/grid/grid_tools.h b/include/deal.II/grid/grid_tools.h index df3711d54f44..5a341b9e9f2a 100644 --- a/include/deal.II/grid/grid_tools.h +++ b/include/deal.II/grid/grid_tools.h @@ -2632,7 +2632,36 @@ namespace GridTools copy_material_to_manifold_id(Triangulation &tria, const bool compute_face_ids = false); - + /** + * Propagate manifold indicators associated to the cells of the Triangulation + * @p tria to their co-dimension one and two objects. + * + * This function sets the @p manifold_id of shared faces and edges to the value + * returnd by the @p disambiguation_function method, called with the set of + * manifold indicators of the cells that share the same face or edge. + * + * By default, the @p disambiguation_function returns + * numbers::flat_manifold_id when the set has size greater than one (i.e., + * when it is not possible to decide what manifold indicator a face or edge + * should have according to the manifold indicators of the adjacent cells) + * and it returns the manifold indicator contained in the set when it has + * dimension one (i.e., when all adjacent cells and faces have the same + * manifold indicator). + * + * @author Luca Heltai, 2019. + */ + template + void + assign_co_dimensional_manifold_indicators( + Triangulation & tria, + const std::function &)> &disambiguation_function = + [](const std::set &manifold_ids) { + if (manifold_ids.size() == 1) + return *manifold_ids.begin(); + else + return numbers::invalid_manifold_id; + }); /*@}*/ /** diff --git a/include/deal.II/grid/tria_accessor.h b/include/deal.II/grid/tria_accessor.h index 9698bb6038e0..47bd2399170f 100644 --- a/include/deal.II/grid/tria_accessor.h +++ b/include/deal.II/grid/tria_accessor.h @@ -632,6 +632,24 @@ class InvalidAccessor : public TriaAccessorBase types::manifold_id manifold_id() const; + /** + * Dummy function that always returns numbers::invalid_unsigned_int. + */ + unsigned int + user_index() const; + + /** + * Dummy function that always throws. + */ + void + set_user_index(const unsigned int p) const; + + /** + * Dummy function that always throws. + */ + void + set_manifold_id(const types::manifold_id) const; + /** * Dummy function to extract vertices. Returns the origin. */ diff --git a/include/deal.II/grid/tria_accessor.templates.h b/include/deal.II/grid/tria_accessor.templates.h index bd9bc7b43cd2..3f74a7fdbc11 100644 --- a/include/deal.II/grid/tria_accessor.templates.h +++ b/include/deal.II/grid/tria_accessor.templates.h @@ -520,6 +520,40 @@ InvalidAccessor::manifold_id() const } + +template +unsigned int +InvalidAccessor::user_index() const +{ + return numbers::invalid_unsigned_int; +} + + + +template +void +InvalidAccessor::set_user_index( + const unsigned int) const +{ + Assert(false, + ExcMessage("You are trying to set the user index of an " + "invalid object.")); +} + + + +template +void +InvalidAccessor::set_manifold_id( + const types::manifold_id) const +{ + Assert(false, + ExcMessage("You are trying to set the manifold id of an " + "invalid object.")); +} + + + template inline Point & InvalidAccessor::vertex(const unsigned int) const diff --git a/source/grid/grid_tools.cc b/source/grid/grid_tools.cc index 44d49753d166..219159c1facd 100644 --- a/source/grid/grid_tools.cc +++ b/source/grid/grid_tools.cc @@ -3756,6 +3756,79 @@ namespace GridTools } } + + template + void + assign_co_dimensional_manifold_indicators( + Triangulation & tria, + const std::function &)> &disambiguation_function) + { + // Easy case first: + if (dim == 1) + return; + const unsigned int size = + dim == 2 ? tria.n_lines() : tria.n_lines() + tria.n_quads(); + + // If user index is zero, then it has not been set. + std::vector> manifold_ids(size + 1); + std::vector backup; + tria.save_user_indices(backup); + + unsigned next_index = 1; + for (auto cell : tria.active_cell_iterators()) + { + if (dim > 1) + for (unsigned int l = 0; l < GeometryInfo::lines_per_cell; ++l) + { + if (cell->line(l)->user_index() == 0) + { + AssertIndexRange(next_index, size + 1); + manifold_ids[next_index].insert(cell->manifold_id()); + cell->line(l)->set_user_index(next_index++); + } + else + manifold_ids[cell->line(l)->user_index()].insert( + cell->manifold_id()); + } + if (dim > 2) + for (unsigned int l = 0; l < GeometryInfo::quads_per_cell; ++l) + { + if (cell->quad(l)->user_index() == 0) + { + AssertIndexRange(next_index, size + 1); + manifold_ids[next_index].insert(cell->manifold_id()); + cell->quad(l)->set_user_index(next_index++); + } + else + manifold_ids[cell->quad(l)->user_index()].insert( + cell->manifold_id()); + } + } + for (auto cell : tria.active_cell_iterators()) + { + if (dim > 1) + for (unsigned int l = 0; l < GeometryInfo::lines_per_cell; ++l) + { + const auto id = cell->line(l)->user_index(); + Assert(id != 0, ExcInternalError()); + cell->line(l)->set_manifold_id( + disambiguation_function(manifold_ids[id])); + } + if (dim > 2) + for (unsigned int l = 0; l < GeometryInfo::quads_per_cell; ++l) + { + const auto id = cell->quad(l)->user_index(); + Assert(id != 0, ExcInternalError()); + cell->quad(l)->set_manifold_id( + disambiguation_function(manifold_ids[id])); + } + } + tria.load_user_indices(backup); + } + + + template std::pair get_longest_direction( diff --git a/source/grid/grid_tools.inst.in b/source/grid/grid_tools.inst.in index 23dd04b907b6..4d04f4141da7 100644 --- a/source/grid/grid_tools.inst.in +++ b/source/grid/grid_tools.inst.in @@ -375,6 +375,12 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) Triangulation &, const std::vector &); + template void + assign_co_dimensional_manifold_indicators( + Triangulation &, + const std::function< + types::manifold_id(const std::set &)> &); + template void regularize_corner_cells( Triangulation &, diff --git a/tests/grid/grid_tools_propagate_manifold_ids_01.cc b/tests/grid/grid_tools_propagate_manifold_ids_01.cc new file mode 100644 index 000000000000..d6ab8c290dcf --- /dev/null +++ b/tests/grid/grid_tools_propagate_manifold_ids_01.cc @@ -0,0 +1,74 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Validate GridTools::assign_co_dimensional_manifold_indicators + +#include +#include +#include + +#include "../tests.h" + + +template +void +test() +{ + deallog << "dim = " << dim << ", spacedim = " << spacedim << std::endl; + + Triangulation tria; + GridGenerator::hyper_cube(tria); + tria.refine_global(1); + tria.begin_active()->set_refine_flag(); + tria.execute_coarsening_and_refinement(); + + tria.begin_active()->set_manifold_id(1); + + auto validate = [](const std::set &set) { + if (set.size() > 1) + return 1; + else + return 0; + }; + + GridTools::assign_co_dimensional_manifold_indicators(tria, validate); + for (auto cell : tria.active_cell_iterators()) + { + deallog << "Cell: " << (int)cell->manifold_id() << std::endl; + if (dim > 1) + for (unsigned int l = 0; l < GeometryInfo::lines_per_cell; ++l) + deallog << "Line " << l << ", " << (int)cell->line(l)->manifold_id() + << std::endl; + if (dim > 2) + for (unsigned int l = 0; l < GeometryInfo::quads_per_cell; ++l) + deallog << "Quad " << l << ", " << (int)cell->quad(l)->manifold_id() + << std::endl; + } +} + + +int +main() +{ + initlog(); + + test<1, 1>(); + test<1, 2>(); + test<2, 2>(); + test<2, 3>(); + test<3, 3>(); + + return 0; +} diff --git a/tests/grid/grid_tools_propagate_manifold_ids_01.output b/tests/grid/grid_tools_propagate_manifold_ids_01.output new file mode 100644 index 000000000000..8b385d57b1bd --- /dev/null +++ b/tests/grid/grid_tools_propagate_manifold_ids_01.output @@ -0,0 +1,367 @@ + +DEAL::dim = 1, spacedim = 1 +DEAL::Cell: 1 +DEAL::Cell: -1 +DEAL::Cell: -1 +DEAL::dim = 1, spacedim = 2 +DEAL::Cell: 1 +DEAL::Cell: -1 +DEAL::Cell: -1 +DEAL::dim = 2, spacedim = 2 +DEAL::Cell: 1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 1 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 1 +DEAL::Line 3, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::dim = 2, spacedim = 3 +DEAL::Cell: 1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 1 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 1 +DEAL::Line 3, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::dim = 3, spacedim = 3 +DEAL::Cell: 1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 1 +DEAL::Line 4, 1 +DEAL::Line 5, 1 +DEAL::Line 6, 1 +DEAL::Line 7, 1 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 1 +DEAL::Line 11, 1 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 1 +DEAL::Quad 4, 0 +DEAL::Quad 5, 1 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 1 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 1 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 1 +DEAL::Line 7, 0 +DEAL::Line 8, 1 +DEAL::Line 9, 1 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 1 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 1 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 1 +DEAL::Line 1, 1 +DEAL::Line 2, 1 +DEAL::Line 3, 1 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 1 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 1 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 +DEAL::Cell: -1 +DEAL::Line 0, 0 +DEAL::Line 1, 0 +DEAL::Line 2, 0 +DEAL::Line 3, 0 +DEAL::Line 4, 0 +DEAL::Line 5, 0 +DEAL::Line 6, 0 +DEAL::Line 7, 0 +DEAL::Line 8, 0 +DEAL::Line 9, 0 +DEAL::Line 10, 0 +DEAL::Line 11, 0 +DEAL::Quad 0, 0 +DEAL::Quad 1, 0 +DEAL::Quad 2, 0 +DEAL::Quad 3, 0 +DEAL::Quad 4, 0 +DEAL::Quad 5, 0 From 6f189b7be7b30559c8840d4a4c652f4dd2dbaf17 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Fri, 22 Mar 2019 00:27:14 +0100 Subject: [PATCH 320/507] Added flat to control overwriting of non flat manifold ids. --- include/deal.II/grid/grid_tools.h | 17 +++++++++++++---- source/grid/grid_tools.cc | 15 ++++++++++----- source/grid/grid_tools.inst.in | 3 ++- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/include/deal.II/grid/grid_tools.h b/include/deal.II/grid/grid_tools.h index 5a341b9e9f2a..13a53614955e 100644 --- a/include/deal.II/grid/grid_tools.h +++ b/include/deal.II/grid/grid_tools.h @@ -2636,8 +2636,9 @@ namespace GridTools * Propagate manifold indicators associated to the cells of the Triangulation * @p tria to their co-dimension one and two objects. * - * This function sets the @p manifold_id of shared faces and edges to the value - * returnd by the @p disambiguation_function method, called with the set of + * This function sets the @p manifold_id of faces and edges (both on the + * interior and on the boundary) to the value returnd by the + * @p disambiguation_function method, called with the set of * manifold indicators of the cells that share the same face or edge. * * By default, the @p disambiguation_function returns @@ -2648,6 +2649,13 @@ namespace GridTools * dimension one (i.e., when all adjacent cells and faces have the same * manifold indicator). * + * The parameter @p overwrite_only_flat_manifold_ids allows you to specify + * what to do when a face or an edge already has a manifold indicator + * different from numbers::flat_manifold_id. If the flag is @p true, the edge + * or face will maintain its original manifold indicator. + * If it is @p false, then also the manifold indicator of these faces and edges + * is set according to the return value of the @p disambiguation_function. + * * @author Luca Heltai, 2019. */ template @@ -2660,8 +2668,9 @@ namespace GridTools if (manifold_ids.size() == 1) return *manifold_ids.begin(); else - return numbers::invalid_manifold_id; - }); + return numbers::flat_manifold_id; + }, + bool overwrite_only_flat_manifold_ids = true); /*@}*/ /** diff --git a/source/grid/grid_tools.cc b/source/grid/grid_tools.cc index 219159c1facd..1b5939f12c65 100644 --- a/source/grid/grid_tools.cc +++ b/source/grid/grid_tools.cc @@ -3762,7 +3762,8 @@ namespace GridTools assign_co_dimensional_manifold_indicators( Triangulation & tria, const std::function &)> &disambiguation_function) + const std::set &)> &disambiguation_function, + bool overwrite_only_flat_manifold_ids) { // Easy case first: if (dim == 1) @@ -3812,16 +3813,20 @@ namespace GridTools { const auto id = cell->line(l)->user_index(); Assert(id != 0, ExcInternalError()); - cell->line(l)->set_manifold_id( - disambiguation_function(manifold_ids[id])); + if (cell->line(l)->manifold_id() == numbers::flat_manifold_id || + overwrite_only_flat_manifold_ids == false) + cell->line(l)->set_manifold_id( + disambiguation_function(manifold_ids[id])); } if (dim > 2) for (unsigned int l = 0; l < GeometryInfo::quads_per_cell; ++l) { const auto id = cell->quad(l)->user_index(); Assert(id != 0, ExcInternalError()); - cell->quad(l)->set_manifold_id( - disambiguation_function(manifold_ids[id])); + if (cell->quad(l)->manifold_id() == numbers::flat_manifold_id || + overwrite_only_flat_manifold_ids == false) + cell->quad(l)->set_manifold_id( + disambiguation_function(manifold_ids[id])); } } tria.load_user_indices(backup); diff --git a/source/grid/grid_tools.inst.in b/source/grid/grid_tools.inst.in index 4d04f4141da7..0c64e7ff346a 100644 --- a/source/grid/grid_tools.inst.in +++ b/source/grid/grid_tools.inst.in @@ -379,7 +379,8 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) assign_co_dimensional_manifold_indicators( Triangulation &, const std::function< - types::manifold_id(const std::set &)> &); + types::manifold_id(const std::set &)> &, + bool); template void regularize_corner_cells( From 3686b4d5e6a89a47303ddc002397b2fdaa3cc323 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Fri, 22 Mar 2019 00:36:10 +0100 Subject: [PATCH 321/507] Update include/deal.II/grid/grid_tools.h Co-Authored-By: luca-heltai --- include/deal.II/grid/grid_tools.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/deal.II/grid/grid_tools.h b/include/deal.II/grid/grid_tools.h index 13a53614955e..6cc0507cafda 100644 --- a/include/deal.II/grid/grid_tools.h +++ b/include/deal.II/grid/grid_tools.h @@ -2633,7 +2633,7 @@ namespace GridTools const bool compute_face_ids = false); /** - * Propagate manifold indicators associated to the cells of the Triangulation + * Propagate manifold indicators associated with the cells of the Triangulation * @p tria to their co-dimension one and two objects. * * This function sets the @p manifold_id of faces and edges (both on the From 695b6db5b7f1f8c3aa10fbf25b3f2a60838f76ee Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Fri, 22 Mar 2019 00:27:14 +0100 Subject: [PATCH 322/507] Added flag to control overwriting of non flat manifold ids. --- source/grid/grid_tools.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/grid/grid_tools.cc b/source/grid/grid_tools.cc index 1b5939f12c65..7aa180cbffaa 100644 --- a/source/grid/grid_tools.cc +++ b/source/grid/grid_tools.cc @@ -3775,6 +3775,7 @@ namespace GridTools std::vector> manifold_ids(size + 1); std::vector backup; tria.save_user_indices(backup); + tria.clear_user_data(); unsigned next_index = 1; for (auto cell : tria.active_cell_iterators()) From 0a2b402e80275c22411733c2bfcaf9d271d214fc Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Fri, 22 Mar 2019 00:44:29 +0100 Subject: [PATCH 323/507] Make sure we only change manifold ids once per face/edge. --- source/grid/grid_tools.cc | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/source/grid/grid_tools.cc b/source/grid/grid_tools.cc index 7aa180cbffaa..32c252689d23 100644 --- a/source/grid/grid_tools.cc +++ b/source/grid/grid_tools.cc @@ -3813,21 +3813,31 @@ namespace GridTools for (unsigned int l = 0; l < GeometryInfo::lines_per_cell; ++l) { const auto id = cell->line(l)->user_index(); - Assert(id != 0, ExcInternalError()); - if (cell->line(l)->manifold_id() == numbers::flat_manifold_id || - overwrite_only_flat_manifold_ids == false) - cell->line(l)->set_manifold_id( - disambiguation_function(manifold_ids[id])); + // Make sure we change the manifold indicator only once + if (id != 0) + { + if (cell->line(l)->manifold_id() == + numbers::flat_manifold_id || + overwrite_only_flat_manifold_ids == false) + cell->line(l)->set_manifold_id( + disambiguation_function(manifold_ids[id])); + cell->line(l)->set_user_index(0); + } } if (dim > 2) for (unsigned int l = 0; l < GeometryInfo::quads_per_cell; ++l) { const auto id = cell->quad(l)->user_index(); - Assert(id != 0, ExcInternalError()); - if (cell->quad(l)->manifold_id() == numbers::flat_manifold_id || - overwrite_only_flat_manifold_ids == false) - cell->quad(l)->set_manifold_id( - disambiguation_function(manifold_ids[id])); + // Make sure we change the manifold indicator only once + if (id != 0) + { + if (cell->quad(l)->manifold_id() == + numbers::flat_manifold_id || + overwrite_only_flat_manifold_ids == false) + cell->quad(l)->set_manifold_id( + disambiguation_function(manifold_ids[id])); + cell->quad(l)->set_user_index(0); + } } } tria.load_user_indices(backup); From 24c7c5ece12d284ebdd898b5d322e6cac7cd198f Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Fri, 22 Mar 2019 00:46:04 +0100 Subject: [PATCH 324/507] More descriptive name. --- source/grid/grid_tools.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/grid/grid_tools.cc b/source/grid/grid_tools.cc index 32c252689d23..10f5dd627244 100644 --- a/source/grid/grid_tools.cc +++ b/source/grid/grid_tools.cc @@ -3768,11 +3768,11 @@ namespace GridTools // Easy case first: if (dim == 1) return; - const unsigned int size = + const unsigned int n_subobjects = dim == 2 ? tria.n_lines() : tria.n_lines() + tria.n_quads(); // If user index is zero, then it has not been set. - std::vector> manifold_ids(size + 1); + std::vector> manifold_ids(n_subobjects + 1); std::vector backup; tria.save_user_indices(backup); tria.clear_user_data(); @@ -3785,7 +3785,7 @@ namespace GridTools { if (cell->line(l)->user_index() == 0) { - AssertIndexRange(next_index, size + 1); + AssertIndexRange(next_index, n_subobjects + 1); manifold_ids[next_index].insert(cell->manifold_id()); cell->line(l)->set_user_index(next_index++); } @@ -3798,7 +3798,7 @@ namespace GridTools { if (cell->quad(l)->user_index() == 0) { - AssertIndexRange(next_index, size + 1); + AssertIndexRange(next_index, n_subobjects + 1); manifold_ids[next_index].insert(cell->manifold_id()); cell->quad(l)->set_user_index(next_index++); } From f29c46e8cb4c83d65d6ff2ae916e3395d7d87272 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Fri, 22 Mar 2019 01:01:17 +0100 Subject: [PATCH 325/507] Fixed indent. --- include/deal.II/grid/grid_tools.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/deal.II/grid/grid_tools.h b/include/deal.II/grid/grid_tools.h index 6cc0507cafda..fed508b798d6 100644 --- a/include/deal.II/grid/grid_tools.h +++ b/include/deal.II/grid/grid_tools.h @@ -2633,8 +2633,8 @@ namespace GridTools const bool compute_face_ids = false); /** - * Propagate manifold indicators associated with the cells of the Triangulation - * @p tria to their co-dimension one and two objects. + * Propagate manifold indicators associated with the cells of the + * Triangulation @p tria to their co-dimension one and two objects. * * This function sets the @p manifold_id of faces and edges (both on the * interior and on the boundary) to the value returnd by the From c36ca78847311bb7d09ea3c026cbec3c4994f292 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 24 Mar 2019 11:30:55 -0400 Subject: [PATCH 326/507] Rename file generated by doc/news/changes/header --- doc/news/changes/header | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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.

    From 954924788b115733a5cbf90205cbc498a68b8d46 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Sun, 24 Mar 2019 11:28:00 -0500 Subject: [PATCH 327/507] CMake: Also filter SYMENGINE_CXX_FLAGS --- cmake/configure/configure_symengine.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/configure/configure_symengine.cmake b/cmake/configure/configure_symengine.cmake index 4867772178fe..4485401c9bec 100644 --- a/cmake/configure/configure_symengine.cmake +++ b/cmake/configure/configure_symengine.cmake @@ -33,6 +33,7 @@ MACRO(FEATURE_SYMENGINE_CONFIGURE_EXTERNAL) # # Overwrite the compiler flags imported from SymEngine # + SET(SYMENGINE_CXX_FLAGS) SET(SYMENGINE_CXX_FLAGS_DEBUG) SET(SYMENGINE_CXX_FLAGS_RELEASE) ENDMACRO() From aac4b05f59e2b4d4d690cac0bab1aef09b4b2dff Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Wed, 20 Mar 2019 11:52:01 +0100 Subject: [PATCH 328/507] add DynamicSparsityPattern::nonempty_cols() and nonempty_rows() --- doc/news/changes/minor/20190320DenisDavydov | 4 ++ .../deal.II/lac/dynamic_sparsity_pattern.h | 18 ++++++ source/lac/dynamic_sparsity_pattern.cc | 40 +++++++++++++ tests/sparsity/dynamic_sparsity_pattern_20.cc | 60 +++++++++++++++++++ .../dynamic_sparsity_pattern_20.output | 5 ++ 5 files changed, 127 insertions(+) create mode 100644 doc/news/changes/minor/20190320DenisDavydov create mode 100644 tests/sparsity/dynamic_sparsity_pattern_20.cc create mode 100644 tests/sparsity/dynamic_sparsity_pattern_20.output 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/include/deal.II/lac/dynamic_sparsity_pattern.h b/include/deal.II/lac/dynamic_sparsity_pattern.h index ed2a200179cc..1cb5b8f706f3 100644 --- a/include/deal.II/lac/dynamic_sparsity_pattern.h +++ b/include/deal.II/lac/dynamic_sparsity_pattern.h @@ -615,6 +615,24 @@ class DynamicSparsityPattern : public Subscriptor const IndexSet & row_index_set() const; + /** + * Return the IndexSet that contains entries for all columns in which at least + * one element exists in this sparsity pattern. + * + * @note In a parallel context, this only considers the locally stored rows. + */ + IndexSet + nonempty_cols() const; + + /** + * Return the IndexSet that contains entries for all rows in which at least + * one element exists in this sparsity pattern. + * + * @note In a parallel context, this only considers the locally stored rows. + */ + IndexSet + nonempty_rows() const; + /** * return whether this object stores only those entries that have been added * explicitly, or if the sparsity pattern contains elements that have been diff --git a/source/lac/dynamic_sparsity_pattern.cc b/source/lac/dynamic_sparsity_pattern.cc index dcf53e1bbcef..c12ef6141f5b 100644 --- a/source/lac/dynamic_sparsity_pattern.cc +++ b/source/lac/dynamic_sparsity_pattern.cc @@ -23,6 +23,7 @@ #include #include #include +#include DEAL_II_NAMESPACE_OPEN @@ -554,6 +555,45 @@ DynamicSparsityPattern::n_nonzero_elements() const } + +IndexSet +DynamicSparsityPattern::nonempty_cols() const +{ + std::set cols; + for (const auto &line : lines) + cols.insert(line.entries.begin(), line.entries.end()); + + IndexSet res(this->n_cols()); + res.add_indices(cols.begin(), cols.end()); + return res; +} + + + +IndexSet +DynamicSparsityPattern::nonempty_rows() const +{ + const IndexSet all_rows = complete_index_set(this->n_rows()); + const IndexSet &locally_stored_rows = rowset.size() == 0 ? all_rows : rowset; + + std::vector rows; + auto line = lines.begin(); + AssertDimension(locally_stored_rows.n_elements(), lines.size()); + for (const auto &row : locally_stored_rows) + { + if (line->entries.size() > 0) + rows.push_back(row); + + ++line; + } + + IndexSet res(this->n_rows()); + res.add_indices(rows.begin(), rows.end()); + return res; +} + + + DynamicSparsityPattern::size_type DynamicSparsityPattern::memory_consumption() const { diff --git a/tests/sparsity/dynamic_sparsity_pattern_20.cc b/tests/sparsity/dynamic_sparsity_pattern_20.cc new file mode 100644 index 000000000000..2f1836836d2d --- /dev/null +++ b/tests/sparsity/dynamic_sparsity_pattern_20.cc @@ -0,0 +1,60 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2004 - 2017 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. +// +// --------------------------------------------------------------------- + + + +// check DynamicSparsityPattern::nonempty_columns() +// and nonempty_rows() + +#include + +#include "../tests.h" + + +void +test() +{ + const unsigned int N = 100; + DynamicSparsityPattern dsp(N, 2 * N); + + for (unsigned int i = 0; i < 5; ++i) + for (unsigned int j = (i == 0 ? 0 : i - 1); j < i + 1; ++j) + dsp.add(i, j); + + dsp.add(50, 50); + dsp.add(51, 51); + dsp.add(90, 52); + + dsp.add(N - 1, 2 * N - 1); + + const IndexSet cols = dsp.nonempty_cols(); + deallog << "Columns:" << std::endl; + cols.print(deallog.get_file_stream()); + + const IndexSet rows = dsp.nonempty_rows(); + deallog << "Rows:" << std::endl; + rows.print(deallog.get_file_stream()); +} + + + +int +main() +{ + initlog(); + + test(); + return 0; +} diff --git a/tests/sparsity/dynamic_sparsity_pattern_20.output b/tests/sparsity/dynamic_sparsity_pattern_20.output new file mode 100644 index 000000000000..ee0ac1f04cf0 --- /dev/null +++ b/tests/sparsity/dynamic_sparsity_pattern_20.output @@ -0,0 +1,5 @@ + +DEAL::Columns: +{[0,4], [50,52], 199} +DEAL::Rows: +{[0,4], [50,51], 90, 99} From a5577ea660d98051e9c8d682485f9749e85b2a8d Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Sun, 24 Mar 2019 17:40:20 -0600 Subject: [PATCH 329/507] CI: kill older running builds --- Jenkinsfile | 14 ++++++++++++++ contrib/ci/Jenkinsfile.osx | 22 ++++++++++++++++++++++ contrib/ci/Jenkinsfile.tidy | 24 ++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index c2b78f390a13..2475c22dafbe 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 diff --git a/contrib/ci/Jenkinsfile.osx b/contrib/ci/Jenkinsfile.osx index 5a404aabb774..68205e5b8bed 100644 --- a/contrib/ci/Jenkinsfile.osx +++ b/contrib/ci/Jenkinsfile.osx @@ -19,8 +19,28 @@ Settings to apply inside Jenkins: - 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' @@ -95,4 +115,6 @@ pipeline } } } + } + } } diff --git a/contrib/ci/Jenkinsfile.tidy b/contrib/ci/Jenkinsfile.tidy index 82d7e69a39f2..80ebb236a8c3 100644 --- a/contrib/ci/Jenkinsfile.tidy +++ b/contrib/ci/Jenkinsfile.tidy @@ -19,8 +19,30 @@ Settings to apply inside Jenkins: - 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 @@ -88,4 +110,6 @@ pipeline } } + } + } } From 4276e8f3451d346447a6f6f428480c09c1e276b0 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Wed, 13 Mar 2019 09:10:43 -0400 Subject: [PATCH 330/507] add Trilinos error checks and fix nonlocal sparsity graph entry - Bugfix: Use GID64(0) instead of MyGID(0) which is a bool - add more checks to other function calls - add comments - fix for rectangular patterns --- source/lac/trilinos_sparsity_pattern.cc | 27 ++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/source/lac/trilinos_sparsity_pattern.cc b/source/lac/trilinos_sparsity_pattern.cc index 33887b18c551..ad5880afd9f1 100644 --- a/source/lac/trilinos_sparsity_pattern.cc +++ b/source/lac/trilinos_sparsity_pattern.cc @@ -793,17 +793,34 @@ namespace TrilinosWrappers if (nonlocal_graph->IndicesAreGlobal() == false && nonlocal_graph->RowMap().NumMyElements() > 0) { - // insert dummy element + // Insert dummy element at (row, column) that corresponds to row 0 + // in local index counting. TrilinosWrappers::types::int_type row = - nonlocal_graph->RowMap().MyGID(0); - nonlocal_graph->InsertGlobalIndices(row, 1, &row); + TrilinosWrappers::global_index(nonlocal_graph->RowMap(), 0); + TrilinosWrappers::types::int_type column = 0; + + // in case we have a square sparsity pattern, add the entry on the + // diagonal + if (TrilinosWrappers::n_global_elements(*column_space_map) == + TrilinosWrappers::n_global_elements(graph->RangeMap())) + column = row; + // if not, take a column index that we have ourselves since we + // know for sure it is there (and it will not create spurious + // messages to many ranks like putting index 0 on many processors) + else if (column_space_map->NumMyElements() > 0) + column = TrilinosWrappers::global_index(*column_space_map, 0); + ierr = nonlocal_graph->InsertGlobalIndices(row, 1, &column); + AssertThrow(ierr == 0, ExcTrilinosError(ierr)); } Assert(nonlocal_graph->RowMap().NumMyElements() == 0 || nonlocal_graph->IndicesAreGlobal() == true, ExcInternalError()); - nonlocal_graph->FillComplete(*column_space_map, graph->RangeMap()); - nonlocal_graph->OptimizeStorage(); + ierr = + nonlocal_graph->FillComplete(*column_space_map, graph->RangeMap()); + AssertThrow(ierr >= 0, ExcTrilinosError(ierr)); + ierr = nonlocal_graph->OptimizeStorage(); + AssertThrow(ierr >= 0, ExcTrilinosError(ierr)); Epetra_Export exporter(nonlocal_graph->RowMap(), graph->RowMap()); ierr = graph->Export(*nonlocal_graph, exporter, Add); AssertThrow(ierr == 0, ExcTrilinosError(ierr)); From 7ecef4009d01ff5b3420c94b9f5bfecddfaaa9ba Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Mon, 25 Mar 2019 17:38:14 +0100 Subject: [PATCH 331/507] Update include/deal.II/grid/grid_tools.h Co-Authored-By: luca-heltai --- include/deal.II/grid/grid_tools.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/deal.II/grid/grid_tools.h b/include/deal.II/grid/grid_tools.h index fed508b798d6..05f6b4a835ad 100644 --- a/include/deal.II/grid/grid_tools.h +++ b/include/deal.II/grid/grid_tools.h @@ -2637,7 +2637,7 @@ namespace GridTools * Triangulation @p tria to their co-dimension one and two objects. * * This function sets the @p manifold_id of faces and edges (both on the - * interior and on the boundary) to the value returnd by the + * interior and on the boundary) to the value returned by the * @p disambiguation_function method, called with the set of * manifold indicators of the cells that share the same face or edge. * From 88362a235229fb83b00d554766f3f6a98978d640 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Mon, 25 Mar 2019 21:55:27 -0600 Subject: [PATCH 332/507] fix indentation --- contrib/ci/Jenkinsfile.osx | 116 ++++++++++++++++++------------------ contrib/ci/Jenkinsfile.tidy | 106 ++++++++++++++++---------------- 2 files changed, 110 insertions(+), 112 deletions(-) diff --git a/contrib/ci/Jenkinsfile.osx b/contrib/ci/Jenkinsfile.osx index 68205e5b8bed..b9c556d55d02 100644 --- a/contrib/ci/Jenkinsfile.osx +++ b/contrib/ci/Jenkinsfile.osx @@ -41,80 +41,80 @@ pipeline stage("main") { - agent { - node { - label 'osx' - } - } - - post { cleanup { cleanWs() } } - - stages - { - stage("check") - { - when { - allOf { - not {branch 'master'} + agent { + node { + label 'osx' } } - steps + post { cleanup { cleanWs() } } + + stages { - githubNotify context: 'OSX', description: 'pending...', status: 'PENDING' - sh ''' + 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 + ''' + } + post { - currentBuild.result='NOT_BUILT' + 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') + stage('build') { - sh "echo \"building on node ${env.NODE_NAME}\"" - sh '''#!/bin/bash - 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 - ''' + steps + { + timeout(time: 1, unit: 'HOURS') + { + sh "echo \"building on node ${env.NODE_NAME}\"" + sh '''#!/bin/bash + 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 + ''' + } + } + + post + { + failure + { + githubNotify context: 'OSX', description: 'build failed', status: 'FAILURE' + } + } } - } - post - { - failure + stage("finalize") { - githubNotify context: 'OSX', description: 'build failed', status: 'FAILURE' + steps + { + githubNotify context: 'OSX', description: 'OK', status: 'SUCCESS' + } } } } - - stage("finalize") - { - steps - { - githubNotify context: 'OSX', description: 'OK', status: 'SUCCESS' - } - } - } - } } } diff --git a/contrib/ci/Jenkinsfile.tidy b/contrib/ci/Jenkinsfile.tidy index 80ebb236a8c3..6aa1179e43dd 100644 --- a/contrib/ci/Jenkinsfile.tidy +++ b/contrib/ci/Jenkinsfile.tidy @@ -42,74 +42,72 @@ pipeline stage("main") { - - agent - { - docker - { - image 'tjhei/candi-base-clang' - } - } - - post { cleanup { cleanWs() } } - - stages - { - stage("check") - { - when { - allOf { - not {branch 'master'} + agent + { + docker + { + image 'tjhei/candi-base-clang' } } - steps + post { cleanup { cleanWs() } } + + stages { - githubNotify context: 'tidy', description: 'pending...', status: 'PENDING' - sh ''' + 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 + ''' + } + post { - currentBuild.result='NOT_BUILT' + 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') + stage('build') { - 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' - } - } + 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' + post + { + failure + { + githubNotify context: 'tidy', description: 'build failed', status: 'FAILURE' + } + } } + } } - - } - } } } From cf260b33da27544e8d3b91deb70563cb6a781af0 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 21 Mar 2019 08:15:44 +0100 Subject: [PATCH 333/507] Fix problem with GrowingVectorMemory for LinearAlgebra::distributed::Vector --- source/base/mpi.cc | 12 +++++ source/lac/CMakeLists.txt | 8 ++++ source/lac/vector_memory.cc | 37 +++------------ source/lac/vector_memory.cu | 57 ++++++++++++++++++++++ tests/cuda/vector_memory_01.cu | 76 ++++++++++++++++++++++++++++++ tests/cuda/vector_memory_01.output | 5 ++ tests/cuda/vector_memory_02.cu | 60 +++++++++++++++++++++++ tests/cuda/vector_memory_02.output | 23 +++++++++ 8 files changed, 247 insertions(+), 31 deletions(-) create mode 100644 source/lac/vector_memory.cu create mode 100644 tests/cuda/vector_memory_01.cu create mode 100644 tests/cuda/vector_memory_01.output create mode 100644 tests/cuda/vector_memory_02.cu create mode 100644 tests/cuda/vector_memory_02.output diff --git a/source/base/mpi.cc b/source/base/mpi.cc index b8cd45e7c26a..de4204d548a9 100644 --- a/source/base/mpi.cc +++ b/source/base/mpi.cc @@ -720,6 +720,18 @@ namespace Utilities } #endif +// There is a similar issue with CUDA: The destructor of static objects might +// run after the CUDA driver is unloaded. Hence, also release all memory +// related to CUDA vectors. +#ifdef DEAL_II_WITH_CUDA + GrowingVectorMemory< + LinearAlgebra::distributed::Vector>:: + release_unused_memory(); + GrowingVectorMemory< + LinearAlgebra::distributed::Vector>:: + release_unused_memory(); +#endif + #ifdef DEAL_II_WITH_P4EST // now end p4est and libsc // Note: p4est has no finalize function diff --git a/source/lac/CMakeLists.txt b/source/lac/CMakeLists.txt index 973837219e1b..ac29c1f6ed4d 100644 --- a/source/lac/CMakeLists.txt +++ b/source/lac/CMakeLists.txt @@ -60,6 +60,14 @@ SET(_separate_src sparse_matrix_inst2.cc ) +# Add CUDA wrapper files +IF(DEAL_II_WITH_CUDA) + SET(_separate_src + ${_separate_src} + vector_memory.cu + ) +ENDIF() + SET(_inst affine_constraints.inst.in block_sparse_matrix.inst.in diff --git a/source/lac/vector_memory.cc b/source/lac/vector_memory.cc index 3fa5affd9bd9..e760248a58ff 100644 --- a/source/lac/vector_memory.cc +++ b/source/lac/vector_memory.cc @@ -14,7 +14,6 @@ // --------------------------------------------------------------------- #include -#include #include #include #include @@ -31,45 +30,21 @@ DEAL_II_NAMESPACE_OPEN #include "vector_memory.inst" -#ifdef DEAL_II_WITH_CUDA -template class VectorMemory>; -template class VectorMemory>; -template class GrowingVectorMemory>; -template class GrowingVectorMemory>; -# ifdef DEAL_II_WITH_MPI -template class VectorMemory< - LinearAlgebra::distributed::Vector>; -template class VectorMemory< - LinearAlgebra::distributed::Vector>; -template class GrowingVectorMemory< - LinearAlgebra::distributed::Vector>; -template class GrowingVectorMemory< - LinearAlgebra::distributed::Vector>; -# endif -#endif - namespace internal { namespace GrowingVectorMemoryImplementation { +#ifdef DEAL_II_WITH_CUDA + void + release_all_unused_cuda_memory(); +#endif + void release_all_unused_memory() { #include "vector_memory_release.inst" - #ifdef DEAL_II_WITH_CUDA - dealii::GrowingVectorMemory>::release_unused_memory(); - dealii::GrowingVectorMemory>::release_unused_memory(); -# ifdef DEAL_II_WITH_MPI - dealii::GrowingVectorMemory< - dealii::LinearAlgebra::distributed::Vector>:: - release_unused_memory(); - dealii::GrowingVectorMemory< - dealii::LinearAlgebra::distributed::Vector>:: - release_unused_memory(); -# endif + release_all_unused_cuda_memory(); #endif } } // namespace GrowingVectorMemoryImplementation diff --git a/source/lac/vector_memory.cu b/source/lac/vector_memory.cu new file mode 100644 index 000000000000..147c6ac8c536 --- /dev/null +++ b/source/lac/vector_memory.cu @@ -0,0 +1,57 @@ +// --------------------------------------------------------------------- +// +// 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 +#include +#include + + +DEAL_II_NAMESPACE_OPEN + +template class VectorMemory>; +template class VectorMemory>; +template class GrowingVectorMemory>; +template class GrowingVectorMemory>; +template class VectorMemory< + LinearAlgebra::distributed::Vector>; +template class VectorMemory< + LinearAlgebra::distributed::Vector>; +template class GrowingVectorMemory< + LinearAlgebra::distributed::Vector>; +template class GrowingVectorMemory< + LinearAlgebra::distributed::Vector>; + +namespace internal +{ + namespace GrowingVectorMemoryImplementation + { + void + release_all_unused_cuda_memory() + { + dealii::GrowingVectorMemory>::release_unused_memory(); + dealii::GrowingVectorMemory>::release_unused_memory(); + dealii::GrowingVectorMemory< + dealii::LinearAlgebra::distributed::Vector>:: + release_unused_memory(); + dealii::GrowingVectorMemory< + dealii::LinearAlgebra::distributed::Vector>:: + release_unused_memory(); + } + } // namespace GrowingVectorMemoryImplementation +} // namespace internal + +DEAL_II_NAMESPACE_CLOSE diff --git a/tests/cuda/vector_memory_01.cu b/tests/cuda/vector_memory_01.cu new file mode 100644 index 000000000000..00e086f82722 --- /dev/null +++ b/tests/cuda/vector_memory_01.cu @@ -0,0 +1,76 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2007 - 2017 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. +// +// --------------------------------------------------------------------- + + +// Test that we can successfully fill a GrowingVectorMemory pool +// with LinearAlgebra::distributed::Vector objects. +// Partially copied from lac/vector_memory.cc + + +#include + +#include +#include + +#include "../tests.h" + + +using namespace dealii; + +template +void +test_stat() +{ + GrowingVectorMemory mem(1, true); + VectorType * v1 = mem.alloc(); + VectorType * v2 = mem.alloc(); + VectorType * v3 = mem.alloc(); + VectorType * v4 = mem.alloc(); + VectorType * v5 = mem.alloc(); + VectorType * v6 = mem.alloc(); + v1->reinit(5); + v2->reinit(5); + v3->reinit(5); + v4->reinit(5); + v5->reinit(5); + v6->reinit(5); + mem.free(v1); + mem.free(v2); + mem.free(v3); + mem.free(v4); + mem.free(v5); + mem.free(v6); + v1 = mem.alloc(); + mem.free(v1); + v1 = mem.alloc(); + mem.free(v1); + v1 = mem.alloc(); + mem.free(v1); + v1 = mem.alloc(); + mem.free(v1); +} + + +int +main(int argc, char *argv[]) +{ + initlog(); + Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1); + + test_stat>(); + test_stat>(); + + return 0; +} diff --git a/tests/cuda/vector_memory_01.output b/tests/cuda/vector_memory_01.output new file mode 100644 index 000000000000..408e05b837b4 --- /dev/null +++ b/tests/cuda/vector_memory_01.output @@ -0,0 +1,5 @@ + +DEAL::GrowingVectorMemory:Overall allocated vectors: 10 +DEAL::GrowingVectorMemory:Maximum allocated vectors: 6 +DEAL::GrowingVectorMemory:Overall allocated vectors: 10 +DEAL::GrowingVectorMemory:Maximum allocated vectors: 6 diff --git a/tests/cuda/vector_memory_02.cu b/tests/cuda/vector_memory_02.cu new file mode 100644 index 000000000000..8725653d55da --- /dev/null +++ b/tests/cuda/vector_memory_02.cu @@ -0,0 +1,60 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2007 - 2017 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. +// +// --------------------------------------------------------------------- + + +// Test that memory leaks are detected correctly for a GrowingVectorMemory pool +// with LinearAlgebra::distributed objects. +// Partially copied from lac/vector_memory.cc + + +#include + +#include +#include + +#include "../tests.h" + + +using namespace dealii; + +template +void +test_leak() +{ + GrowingVectorMemory mem; + VectorType * v = mem.alloc(); + v->reinit(5); +} + +int +main(int argc, char *argv[]) +{ + initlog(); + Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1); + deal_II_exceptions::disable_abort_on_exception(); + + try + { + test_leak< + LinearAlgebra::distributed::Vector>(); + test_leak>(); + } + catch (const StandardExceptions::ExcMemoryLeak &e) + { + deallog << "Exception: " << e.get_exc_name() << std::endl; + } + + return 0; +} diff --git a/tests/cuda/vector_memory_02.output b/tests/cuda/vector_memory_02.output new file mode 100644 index 000000000000..bdfb84b98ded --- /dev/null +++ b/tests/cuda/vector_memory_02.output @@ -0,0 +1,23 @@ + +DEAL::Exception: StandardExceptions::ExcMemoryLeak(current_alloc) +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + dealii::GrowingVectorMemory::~GrowingVectorMemory() [with VectorType = dealii::LinearAlgebra::distributed::Vector] +The violated condition was: + current_alloc == 0 +Additional information: + Destroying memory handler while 1 objects are still allocated. +-------------------------------------------------------- + +DEAL::Exception: StandardExceptions::ExcMemoryLeak(current_alloc) +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + dealii::GrowingVectorMemory::~GrowingVectorMemory() [with VectorType = dealii::LinearAlgebra::distributed::Vector] +The violated condition was: + current_alloc == 0 +Additional information: + Destroying memory handler while 1 objects are still allocated. +-------------------------------------------------------- + From 0e30348e98c2b0a34675cdbb2d57678d857d91ff Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Tue, 26 Mar 2019 17:04:28 +0100 Subject: [PATCH 334/507] Add documentation for initialising Trilinos AMG constant modes --- include/deal.II/lac/trilinos_precondition.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/deal.II/lac/trilinos_precondition.h b/include/deal.II/lac/trilinos_precondition.h index aba329ce8a6e..3b5ac1984a2a 100644 --- a/include/deal.II/lac/trilinos_precondition.h +++ b/include/deal.II/lac/trilinos_precondition.h @@ -1369,6 +1369,25 @@ namespace TrilinosWrappers /** * Constructor. By default, we pretend to work on elliptic problems with * linear finite elements on a scalar equation. + * + * Making use of the DoFTools::extract_constant_modes() function, the + * @p constant_modes vector can be initialized for a given field in the + * following manner: + * + * @code + * #include + * ... + * + * DoFHandlerType<...> dof_handler; + * FEValuesExtractors::Type... field_extractor; + * ... + * + * TrilinosWrappers::PreconditionAMG::AdditionalData data; + * DoFTools::extract_constant_modes( + * dof_handler, + * dof_handler.get_fe_collection().component_mask(field_extractor), + * data.constant_modes ); + * @endcode */ AdditionalData(const bool elliptic = true, const bool higher_order_elements = false, From f5ab9c7895c8930017b291ed331e36d8e84a6131 Mon Sep 17 00:00:00 2001 From: Logan Harbour Date: Tue, 26 Mar 2019 16:34:29 -0500 Subject: [PATCH 335/507] Additional doco for L2 integrators --- include/deal.II/integrators/l2.h | 48 ++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/include/deal.II/integrators/l2.h b/include/deal.II/integrators/l2.h index a2d2588c100a..0c49f0a3c6e1 100644 --- a/include/deal.II/integrators/l2.h +++ b/include/deal.II/integrators/l2.h @@ -50,6 +50,11 @@ namespace LocalIntegrators * integrals \f[ \int_F uv\,ds \quad \text{or} \quad \int_F \mathbf u\cdot * \mathbf v\,ds \f] * + * @param M The mass matrix matrix obtained as result. + * @param fe The FEValues object describing the local trial function + * space. #update_values and #update_JxW_values must be set. + * @param factor A constant that multiplies the mass matrix. + * * @author Guido Kanschat * @date 2008, 2009, 2010 */ @@ -97,8 +102,12 @@ namespace LocalIntegrators * integrals \f[ \int_F \omega(x) uv\,ds \quad \text{or} \quad \int_F * \omega(x) \mathbf u\cdot \mathbf v\,ds \f] * - * The size of the vector weights must be equal to the number of - * quadrature points in the finite element. + * @param M The weighted mass matrix matrix obtained as result. + * @param fe The FEValues object describing the local trial function + * space. #update_values and #update_JxW_values must be set. + * @param weights The weights, $\omega(x)$, evaluated at the quadrature + * points in the finite element (size must be equal to the number of + * quadrature points in the element). * * @author Guido Kanschat * @date 2014 @@ -146,6 +155,14 @@ namespace LocalIntegrators * * \f[ \int_Z fv\,dx \quad \text{or} \quad \int_F fv\,ds \f] * + * @param result The vector obtained as result. + * @param fe The FEValues object describing the local trial function + * space. #update_values and #update_JxW_values must be set. + * @param input The representation of $f$ evaluated at the quadrature + * points in the finite element (size must be equal to the number of + * quadrature points in the element). + * @param factor A constant that multiplies the result. + * * @author Guido Kanschat * @date 2008, 2009, 2010 */ @@ -171,6 +188,14 @@ namespace LocalIntegrators * hand side. \f[ \int_Z \mathbf f\cdot \mathbf v\,dx \quad \text{or} * \quad \int_F \mathbf f\cdot \mathbf v\,ds \f] * + * @param result The vector obtained as result. + * @param fe The FEValues object describing the local trial function + * space. #update_values and #update_JxW_values must be set. + * @param input The vector valued representation of $\mathbf f$ evaluated + * at the quadrature points in the finite element (size of each component + * must be equal to the number of quadrature points in the element). + * @param factor A constant that multiplies the result. + * * @author Guido Kanschat * @date 2008, 2009, 2010 */ @@ -203,6 +228,25 @@ namespace LocalIntegrators * Using appropriate weights, this term can be used to penalize violation * of conformity in H1. * + * Note that for the parameters that follow, the external matrix refers to + * the flux between cells, while the internal matrix refers to entries + * coupling inside the cell. + * + * @param M11 The internal matrix for the first cell obtained as result. + * @param M12 The external matrix for the first cell obtained as result. + * @param M12 The external matrix for the second cell obtained as result. + * @param M22 The internal matrix for the second cell obtained as result. + * @param fe1 The FEValues object describing the local trial function + * space for the first cell. #update_values and #update_JxW_values must be + * set. + * @param fe2 The FEValues object describing the local trial function + * space for the second cell. #update_values and #update_JxW_values must be + * set. + * @param factor1 A constant that multiplies the shape functions for the + * first cell. + * @param factor2 A constant that multiplies the shape functions for the + * second cell. + * * @author Guido Kanschat * @date 2008, 2009, 2010 */ From ca18f5aaccc84c7c09b39df8891a6922632be633 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 26 Mar 2019 22:10:05 -0400 Subject: [PATCH 336/507] Rename parallel::distributed::SolutionTransfer::prepare_serialization() --- doc/news/changes/minor/20190326Arndt | 5 +++ .../deal.II/distributed/solution_transfer.h | 32 +++++++++++++++---- source/distributed/solution_transfer.cc | 23 ++++++++++++- tests/mpi/p4est_save_02.cc | 2 +- tests/mpi/p4est_save_03.cc | 4 +-- tests/mpi/p4est_save_04.cc | 2 +- tests/mpi/p4est_save_06.cc | 2 +- 7 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 doc/news/changes/minor/20190326Arndt diff --git a/doc/news/changes/minor/20190326Arndt b/doc/news/changes/minor/20190326Arndt new file mode 100644 index 000000000000..8e9c7ef382d8 --- /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(). +Note on ghost elements In a parallel computation PETSc or * Trilinos vector may contain ghost elements or not. For reading in * information with prepare_for_coarsening_and_refinement() or - * prepare_serialization() you need to supply vectors with ghost elements, - * so that all locally_active elements can be read. On the other hand, - * ghosted vectors are generally not writable, so for calls to + * prepare_for_serialization() you need to supply vectors with ghost + * elements, so that all locally_active elements can be read. On the other + * hand, ghosted vectors are generally not writable, so for calls to * interpolate() or deserialize() you need to supply distributed vectors * without ghost elements. More precisely, during interpolation the * current algorithm writes into all locally active degrees of freedom. @@ -133,7 +133,7 @@ namespace parallel * @code * parallel::distributed::SolutionTransfer * sol_trans(dof_handler); - * sol_trans.prepare_serialization (vector); + * sol_trans.prepare_for_serialization (vector); * * triangulation.save(filename); * @endcode @@ -186,7 +186,7 @@ namespace parallel * sol_trans(hp_dof_handler); * * hp_dof_handler.prepare_for_serialization_of_active_fe_indices(); - * sol_trans.prepare_serialization(vector); + * sol_trans.prepare_for_serialization(vector); * * triangulation.save(filename); * @endcode @@ -292,24 +292,42 @@ namespace parallel void interpolate(VectorType &out); + /** + * Prepare the serialization of the given vector. The serialization is + * done by Triangulation::save(). The given vector needs all information + * on the locally active DoFs (it must be ghosted). See documentation of + * this class for more information. + */ + void + prepare_for_serialization(const VectorType &in); + + /** + * Same as the function above, only for a list of vectors. + */ + void + prepare_for_serialization(const std::vector &all_in); /** * Prepare the serialization of the given vector. The serialization is * done by Triangulation::save(). The given vector needs all information * on the locally active DoFs (it must be ghosted). See documentation of * this class for more information. + * + * @deprecated Use parallel::distributed::SolutionTransfer::prepare_for_serialization() instead. */ + DEAL_II_DEPRECATED void prepare_serialization(const VectorType &in); - /** * Same as the function above, only for a list of vectors. + * + * @deprecated Use parallel::distributed::SolutionTransfer::prepare_for_serialization() instead. */ + DEAL_II_DEPRECATED void prepare_serialization(const std::vector &all_in); - /** * Execute the deserialization of the given vector. This needs to be * done after calling Triangulation::load(). The given vector must be a diff --git a/source/distributed/solution_transfer.cc b/source/distributed/solution_transfer.cc index 4c4f5d9f26f1..0919d7c79804 100644 --- a/source/distributed/solution_transfer.cc +++ b/source/distributed/solution_transfer.cc @@ -109,13 +109,34 @@ namespace parallel + template + void + SolutionTransfer:: + prepare_for_serialization(const VectorType &in) + { + std::vector all_in(1, &in); + prepare_for_serialization(all_in); + } + + + + template + void + SolutionTransfer:: + prepare_for_serialization(const std::vector &all_in) + { + prepare_for_coarsening_and_refinement(all_in); + } + + + template void SolutionTransfer::prepare_serialization( const VectorType &in) { std::vector all_in(1, &in); - prepare_serialization(all_in); + prepare_for_serialization(all_in); } diff --git a/tests/mpi/p4est_save_02.cc b/tests/mpi/p4est_save_02.cc index 1ab383a4d77a..be0738f39f49 100644 --- a/tests/mpi/p4est_save_02.cc +++ b/tests/mpi/p4est_save_02.cc @@ -97,7 +97,7 @@ test() x.compress(VectorOperation::insert); solution = x; - soltrans.prepare_serialization(solution); + soltrans.prepare_for_serialization(solution); tr.save(filename.c_str()); diff --git a/tests/mpi/p4est_save_03.cc b/tests/mpi/p4est_save_03.cc index 9780e2dfaeac..4619f2ad7536 100644 --- a/tests/mpi/p4est_save_03.cc +++ b/tests/mpi/p4est_save_03.cc @@ -108,8 +108,8 @@ test() solution2 = x; - soltrans.prepare_serialization(solution); - soltrans2.prepare_serialization(solution2); + soltrans.prepare_for_serialization(solution); + soltrans2.prepare_for_serialization(solution2); tr.save(filename.c_str()); diff --git a/tests/mpi/p4est_save_04.cc b/tests/mpi/p4est_save_04.cc index c908edf67341..0526ce29c2a6 100644 --- a/tests/mpi/p4est_save_04.cc +++ b/tests/mpi/p4est_save_04.cc @@ -100,7 +100,7 @@ test() x.compress(VectorOperation::insert); rel_x = x; - soltrans.prepare_serialization(rel_x); + soltrans.prepare_for_serialization(rel_x); tr.save("file"); // tr.write_mesh_vtk("before"); diff --git a/tests/mpi/p4est_save_06.cc b/tests/mpi/p4est_save_06.cc index 453ed583896d..15025baeaefe 100644 --- a/tests/mpi/p4est_save_06.cc +++ b/tests/mpi/p4est_save_06.cc @@ -107,7 +107,7 @@ test() rel_x = x; dh.prepare_for_serialization_of_active_fe_indices(); - soltrans.prepare_serialization(rel_x); + soltrans.prepare_for_serialization(rel_x); tr.save("file"); deallog << "#cells: " << tr.n_global_active_cells() << std::endl From 347ccc84cec2a07720c1f124e2f6eb8483ee4bc6 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Wed, 27 Mar 2019 09:25:46 -0600 Subject: [PATCH 337/507] fix Trilinos sparsity test output --- ...n=9.with_trilinos=true.with_mpi=true.output | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/trilinos/n_nonzeros_02_parallel.with_p4est=true.mpirun=9.with_trilinos=true.with_mpi=true.output b/tests/trilinos/n_nonzeros_02_parallel.with_p4est=true.mpirun=9.with_trilinos=true.with_mpi=true.output index 6c072d8b3d0c..d0db2a6bd95d 100644 --- a/tests/trilinos/n_nonzeros_02_parallel.with_p4est=true.mpirun=9.with_trilinos=true.with_mpi=true.output +++ b/tests/trilinos/n_nonzeros_02_parallel.with_p4est=true.mpirun=9.with_trilinos=true.with_mpi=true.output @@ -1,26 +1,26 @@ -DEAL:0::0 +DEAL:0::8 -DEAL:1::0 +DEAL:1::8 -DEAL:2::0 +DEAL:2::8 -DEAL:3::0 +DEAL:3::8 -DEAL:4::0 +DEAL:4::8 -DEAL:5::0 +DEAL:5::8 -DEAL:6::0 +DEAL:6::8 -DEAL:7::0 +DEAL:7::8 -DEAL:8::0 +DEAL:8::8 From 51fb2c548ac73121ebe2743d0885a29cadb60bfd Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Wed, 27 Mar 2019 09:29:23 -0600 Subject: [PATCH 338/507] fix warning in ginkgo_solver.cc --- source/lac/ginkgo_solver.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/lac/ginkgo_solver.cc b/source/lac/ginkgo_solver.cc index b1e08892ee7d..59335c12da95 100644 --- a/source/lac/ginkgo_solver.cc +++ b/source/lac/ginkgo_solver.cc @@ -297,12 +297,12 @@ namespace GinkgoWrappers # define DECLARE_SOLVER_BASE(ValueType, IndexType) \ class SolverBase - GKO_DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_SOLVER_BASE); + GKO_DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_SOLVER_BASE) # undef DECLARE_SOLVER_BASE # define DECLARE_SOLVER_CG(ValueType, IndexType) \ class SolverCG - GKO_DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_SOLVER_CG); + GKO_DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_SOLVER_CG) # undef DECLARE_SOLVER_CG } // namespace GinkgoWrappers From 303ac9774a4280382ef6ba289af98f67617efdd8 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Wed, 27 Mar 2019 09:31:23 -0600 Subject: [PATCH 339/507] CI: fix left-over "pending" If the CI jenkins job ends up starting quicker than the .mark step, we are left with a "pending" github status. Fix this by setting it to green a second time. It is unlikely that the mark step is slower than the whole CI run... --- Jenkinsfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index c2b78f390a13..e3068a5a11c3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -183,6 +183,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' } } } From 6e01e776aadc465174f3e0781fca53874594ea9b Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Wed, 27 Mar 2019 14:00:58 -0600 Subject: [PATCH 340/507] extend text output and comments --- tests/trilinos/n_nonzeros_02_parallel.cc | 8 ++++++-- ...=true.mpirun=9.with_trilinos=true.with_mpi=true.output | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/trilinos/n_nonzeros_02_parallel.cc b/tests/trilinos/n_nonzeros_02_parallel.cc index b7ee1737ecce..463886c4330d 100644 --- a/tests/trilinos/n_nonzeros_02_parallel.cc +++ b/tests/trilinos/n_nonzeros_02_parallel.cc @@ -15,7 +15,8 @@ -// check n_nonzero_elements() for an empty matrix +// check n_nonzero_elements() for an empty matrix. We generate a few dummy +// non-zero entries. #include @@ -71,8 +72,11 @@ test() TrilinosWrappers::SparseMatrix A; A.reinit(sparsity); - // see how many nonzero elements it reports + // See how many nonzero elements it reports. Note that we have a + // nonlocal Trilinos graph for the off-processor entries and we need + // to enter a few dummy elements: deallog << A.n_nonzero_elements() << std::endl; + A.print(deallog.get_file_stream()); } diff --git a/tests/trilinos/n_nonzeros_02_parallel.with_p4est=true.mpirun=9.with_trilinos=true.with_mpi=true.output b/tests/trilinos/n_nonzeros_02_parallel.with_p4est=true.mpirun=9.with_trilinos=true.with_mpi=true.output index d0db2a6bd95d..de726b1b29bf 100644 --- a/tests/trilinos/n_nonzeros_02_parallel.with_p4est=true.mpirun=9.with_trilinos=true.with_mpi=true.output +++ b/tests/trilinos/n_nonzeros_02_parallel.with_p4est=true.mpirun=9.with_trilinos=true.with_mpi=true.output @@ -1,7 +1,13 @@ DEAL:0::8 +(2,2) 0.00000 +(9,9) 0.00000 +(10,10) 0.00000 DEAL:1::8 +(15,15) 0.00000 +(16,16) 0.00000 +(21,21) 0.00000 DEAL:2::8 @@ -11,9 +17,11 @@ DEAL:3::8 DEAL:4::8 +(46,46) 0.00000 DEAL:5::8 +(51,51) 0.00000 DEAL:6::8 From 4c14fdfc395fe24d83cbf449d8f74fd20dbfbcdb Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Wed, 27 Mar 2019 13:59:52 -0600 Subject: [PATCH 341/507] doc: fix small error --- include/deal.II/dofs/dof_handler.h | 3 ++- include/deal.II/hp/dof_handler.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/deal.II/dofs/dof_handler.h b/include/deal.II/dofs/dof_handler.h index d07ecf0738dd..b3a0b1c1fc1f 100644 --- a/include/deal.II/dofs/dof_handler.h +++ b/include/deal.II/dofs/dof_handler.h @@ -1056,7 +1056,8 @@ class DoFHandler : public Subscriptor * globally, i.e. what n_dofs() returns. * * Each element of the vector returned by this function equals the number of - * elements of the corresponding sets returned by global_dof_indices(). + * elements of the corresponding sets returned by + * locally_owned_dofs_per_processor(). * * If this is a sequential DoFHandler, then the vector has a single element * equal to n_dofs(). (Here, "sequential" means that either the whole program diff --git a/include/deal.II/hp/dof_handler.h b/include/deal.II/hp/dof_handler.h index a35a1f115f21..3bff98e0d14a 100644 --- a/include/deal.II/hp/dof_handler.h +++ b/include/deal.II/hp/dof_handler.h @@ -846,7 +846,8 @@ namespace hp * globally, i.e. what n_dofs() returns. * * Each element of the vector returned by this function equals the number - * of elements of the corresponding sets returned by global_dof_indices(). + * of elements of the corresponding sets returned by + * locally_owned_dofs_per_processor(). * * If this is a sequential DoFHandler, then the vector has a single element * equal to n_dofs(). (Here, "sequential" means that either the whole From 0f1a6e14a12d01bafa5f2cd57a4215c9d5087d9d Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Wed, 27 Mar 2019 14:06:01 -0600 Subject: [PATCH 342/507] rename macro --- source/lac/ginkgo_solver.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/lac/ginkgo_solver.cc b/source/lac/ginkgo_solver.cc index 59335c12da95..8223fc6a4d38 100644 --- a/source/lac/ginkgo_solver.cc +++ b/source/lac/ginkgo_solver.cc @@ -289,20 +289,20 @@ namespace GinkgoWrappers } // Explicit instantiations in GinkgoWrappers -# define GKO_DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(_macro) \ - template _macro(float, int32_t); \ - template _macro(double, int32_t); \ - template _macro(float, int64_t); \ +# define DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(_macro) \ + template _macro(float, int32_t); \ + template _macro(double, int32_t); \ + template _macro(float, int64_t); \ template _macro(double, int64_t); # define DECLARE_SOLVER_BASE(ValueType, IndexType) \ class SolverBase - GKO_DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_SOLVER_BASE) + DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_SOLVER_BASE) # undef DECLARE_SOLVER_BASE # define DECLARE_SOLVER_CG(ValueType, IndexType) \ class SolverCG - GKO_DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_SOLVER_CG) + DEALII_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_SOLVER_CG) # undef DECLARE_SOLVER_CG } // namespace GinkgoWrappers From 3c62f62c85e65799e04bddb879cdbc45e584362a Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 27 Mar 2019 19:39:39 -0400 Subject: [PATCH 343/507] Call the new functions instead of copying the implementation --- source/distributed/solution_transfer.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/distributed/solution_transfer.cc b/source/distributed/solution_transfer.cc index 0919d7c79804..26e0cb1a70dd 100644 --- a/source/distributed/solution_transfer.cc +++ b/source/distributed/solution_transfer.cc @@ -135,8 +135,7 @@ namespace parallel SolutionTransfer::prepare_serialization( const VectorType &in) { - std::vector all_in(1, &in); - prepare_for_serialization(all_in); + prepare_for_serialization(in); } @@ -146,7 +145,7 @@ namespace parallel SolutionTransfer::prepare_serialization( const std::vector &all_in) { - prepare_for_coarsening_and_refinement(all_in); + prepare_for_serialization(all_in); } From 1fdd88ed1ea5d70662343c1af9d19e2d680815f8 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Wed, 27 Mar 2019 12:45:33 +0100 Subject: [PATCH 344/507] Rename Solver class to SolverBase. This aligns with the name chosen for the equivalent class in the TrilinosWrappers and PetscWrappers namespaces. --- include/deal.II/lac/eigen.h | 8 ++--- include/deal.II/lac/solver.h | 41 ++++++++++++++-------- include/deal.II/lac/solver_bicgstab.h | 6 ++-- include/deal.II/lac/solver_cg.h | 6 ++-- include/deal.II/lac/solver_fire.h | 6 ++-- include/deal.II/lac/solver_gmres.h | 12 +++---- include/deal.II/lac/solver_minres.h | 6 ++-- include/deal.II/lac/solver_qmrs.h | 6 ++-- include/deal.II/lac/solver_relaxation.h | 4 +-- include/deal.II/lac/solver_richardson.h | 6 ++-- include/deal.II/optimization/solver_bfgs.h | 4 +-- source/lac/solver.inst.in | 2 +- 12 files changed, 60 insertions(+), 47 deletions(-) diff --git a/include/deal.II/lac/eigen.h b/include/deal.II/lac/eigen.h index ec1bc54888ae..7a70296d36a9 100644 --- a/include/deal.II/lac/eigen.h +++ b/include/deal.II/lac/eigen.h @@ -52,7 +52,7 @@ DEAL_II_NAMESPACE_OPEN * @author Guido Kanschat, 2000 */ template > -class EigenPower : private Solver +class EigenPower : private SolverBase { public: /** @@ -131,7 +131,7 @@ class EigenPower : private Solver * @author Guido Kanschat, 2000, 2003 */ template > -class EigenInverse : private Solver +class EigenInverse : private SolverBase { public: /** @@ -208,7 +208,7 @@ template EigenPower::EigenPower(SolverControl & cn, VectorMemory &mem, const AdditionalData & data) - : Solver(cn, mem) + : SolverBase(cn, mem) , additional_data(data) {} @@ -297,7 +297,7 @@ template EigenInverse::EigenInverse(SolverControl & cn, VectorMemory &mem, const AdditionalData & data) - : Solver(cn, mem) + : SolverBase(cn, mem) , additional_data(data) {} diff --git a/include/deal.II/lac/solver.h b/include/deal.II/lac/solver.h index a62ffbabbfe4..c26686af8e65 100644 --- a/include/deal.II/lac/solver.h +++ b/include/deal.II/lac/solver.h @@ -129,7 +129,7 @@ class Vector; * deal.II library for the built-in vector types, but must be explicitly added * for user-provided vector classes. Otherwise, the linker will complain that * it cannot find the constructors and destructors of GrowingVectorMemory that - * happen in the @p Solver class. + * happen in the @p SolverBase class. * * @code * // Definition and implementation of vector class @@ -185,7 +185,7 @@ class Vector; * *

    Observing the progress of linear solver iterations

    * - * The Solver class, being the base class for all of the iterative solvers + * The SolverBase class, being the base class for all of the iterative solvers * such as SolverCG, SolverGMRES, etc, provides the facilities by which actual * solver implementations determine whether the iteration is converged, not * yet converged, or has failed. Typically, this is done using an object of @@ -234,7 +234,7 @@ class Vector; * into this scheme: when a SolverControl object is passed to the constructor * of the current class, we simply connect the SolverControl::check() function * of that object as a slot to the signal we maintain here. In other words, - * since a Solver object is always constructed using a SolverControl object, + * since a SolverBase object is always constructed using a SolverControl object, * there is always at least one slot associated with the signal, namely the * one that determines convergence. * @@ -325,7 +325,7 @@ class Vector; * 2014 */ template > -class Solver : public Subscriptor +class SolverBase : public Subscriptor { public: /** @@ -342,8 +342,8 @@ class Solver : public Subscriptor * responsibility to guarantee that the lifetime of the two arguments is at * least as long as that of the solver object. */ - Solver(SolverControl & solver_control, - VectorMemory &vector_memory); + SolverBase(SolverControl & solver_control, + VectorMemory &vector_memory); /** * Constructor. Takes a control object which evaluates the conditions for @@ -355,7 +355,7 @@ class Solver : public Subscriptor * responsibility to guarantee that the lifetime of the argument is at least * as long as that of the solver object. */ - Solver(SolverControl &solver_control); + SolverBase(SolverControl &solver_control); /** * Connect a function object that will be called periodically within @@ -459,12 +459,24 @@ class Solver : public Subscriptor }; + +/** + * Type definition for the base class for iterative linear solvers. + * This class provides interfaces to a memory pool and the objects that + * determine whether a solver has converged. + * + * @deprecated Use SolverBase instead. + */ +template > +using Solver DEAL_II_DEPRECATED = SolverBase; + + /*-------------------------------- Inline functions ------------------------*/ template inline SolverControl::State -Solver::StateCombiner:: +SolverBase::StateCombiner:: operator()(const SolverControl::State state1, const SolverControl::State state2) const { @@ -481,8 +493,8 @@ operator()(const SolverControl::State state1, template template inline SolverControl::State -Solver::StateCombiner::operator()(const Iterator begin, - const Iterator end) const +SolverBase::StateCombiner::operator()(const Iterator begin, + const Iterator end) const { Assert(begin != end, ExcMessage("You can't combine iterator states if no state is given.")); @@ -499,8 +511,9 @@ Solver::StateCombiner::operator()(const Iterator begin, template -inline Solver::Solver(SolverControl & solver_control, - VectorMemory &vector_memory) +inline SolverBase::SolverBase( + SolverControl & solver_control, + VectorMemory &vector_memory) : memory(vector_memory) { // connect the solver control object to the signal. SolverControl::check @@ -516,7 +529,7 @@ inline Solver::Solver(SolverControl & solver_control, template -inline Solver::Solver(SolverControl &solver_control) +inline SolverBase::SolverBase(SolverControl &solver_control) : // use the static memory object this class owns memory(static_vector_memory) { @@ -534,7 +547,7 @@ inline Solver::Solver(SolverControl &solver_control) template inline boost::signals2::connection -Solver::connect( +SolverBase::connect( const std::function diff --git a/include/deal.II/lac/solver_bicgstab.h b/include/deal.II/lac/solver_bicgstab.h index 90d1d7d46830..5ce13b435d6a 100644 --- a/include/deal.II/lac/solver_bicgstab.h +++ b/include/deal.II/lac/solver_bicgstab.h @@ -121,7 +121,7 @@ namespace internal * */ template > -class SolverBicgstab : public Solver, +class SolverBicgstab : public SolverBase, protected internal::SolverBicgstabData { public: @@ -314,7 +314,7 @@ template SolverBicgstab::SolverBicgstab(SolverControl & cn, VectorMemory &mem, const AdditionalData & data) - : Solver(cn, mem) + : SolverBase(cn, mem) , Vx(nullptr) , Vb(nullptr) , additional_data(data) @@ -325,7 +325,7 @@ SolverBicgstab::SolverBicgstab(SolverControl & cn, template SolverBicgstab::SolverBicgstab(SolverControl & cn, const AdditionalData &data) - : Solver(cn) + : SolverBase(cn) , Vx(nullptr) , Vb(nullptr) , additional_data(data) diff --git a/include/deal.II/lac/solver_cg.h b/include/deal.II/lac/solver_cg.h index 9d1656ca8768..3dc4342adb37 100644 --- a/include/deal.II/lac/solver_cg.h +++ b/include/deal.II/lac/solver_cg.h @@ -93,7 +93,7 @@ class PreconditionIdentity; * @author W. Bangerth, G. Kanschat, R. Becker and F.-T. Suttmeier */ template > -class SolverCG : public Solver +class SolverCG : public SolverBase { public: /** @@ -242,7 +242,7 @@ template SolverCG::SolverCG(SolverControl & cn, VectorMemory &mem, const AdditionalData & data) - : Solver(cn, mem) + : SolverBase(cn, mem) , additional_data(data) {} @@ -250,7 +250,7 @@ SolverCG::SolverCG(SolverControl & cn, template SolverCG::SolverCG(SolverControl &cn, const AdditionalData &data) - : Solver(cn) + : SolverBase(cn) , additional_data(data) {} diff --git a/include/deal.II/lac/solver_fire.h b/include/deal.II/lac/solver_fire.h index b0fdf22bc795..a31e97e7a4c8 100644 --- a/include/deal.II/lac/solver_fire.h +++ b/include/deal.II/lac/solver_fire.h @@ -88,7 +88,7 @@ DEAL_II_NAMESPACE_OPEN * @author Vishal Boddu, Denis Davydov, 2017 */ template > -class SolverFIRE : public Solver +class SolverFIRE : public SolverBase { public: /** @@ -214,7 +214,7 @@ template SolverFIRE::SolverFIRE(SolverControl & solver_control, VectorMemory &vector_memory, const AdditionalData & data) - : Solver(solver_control, vector_memory) + : SolverBase(solver_control, vector_memory) , additional_data(data) {} @@ -223,7 +223,7 @@ SolverFIRE::SolverFIRE(SolverControl & solver_control, template SolverFIRE::SolverFIRE(SolverControl & solver_control, const AdditionalData &data) - : Solver(solver_control) + : SolverBase(solver_control) , additional_data(data) {} diff --git a/include/deal.II/lac/solver_gmres.h b/include/deal.II/lac/solver_gmres.h index 04f9fa48ae40..d5a7d6a76d73 100644 --- a/include/deal.II/lac/solver_gmres.h +++ b/include/deal.II/lac/solver_gmres.h @@ -175,7 +175,7 @@ namespace internal * @author Wolfgang Bangerth, Guido Kanschat, Ralf Hartmann. */ template > -class SolverGMRES : public Solver +class SolverGMRES : public SolverBase { public: /** @@ -457,7 +457,7 @@ class SolverGMRES : public Solver * @author Guido Kanschat, 2003 */ template > -class SolverFGMRES : public Solver +class SolverFGMRES : public SolverBase { public: /** @@ -621,7 +621,7 @@ template SolverGMRES::SolverGMRES(SolverControl & cn, VectorMemory &mem, const AdditionalData & data) - : Solver(cn, mem) + : SolverBase(cn, mem) , additional_data(data) {} @@ -630,7 +630,7 @@ SolverGMRES::SolverGMRES(SolverControl & cn, template SolverGMRES::SolverGMRES(SolverControl & cn, const AdditionalData &data) - : Solver(cn) + : SolverBase(cn) , additional_data(data) {} @@ -1182,7 +1182,7 @@ template SolverFGMRES::SolverFGMRES(SolverControl & cn, VectorMemory &mem, const AdditionalData & data) - : Solver(cn, mem) + : SolverBase(cn, mem) , additional_data(data) {} @@ -1191,7 +1191,7 @@ SolverFGMRES::SolverFGMRES(SolverControl & cn, template SolverFGMRES::SolverFGMRES(SolverControl & cn, const AdditionalData &data) - : Solver(cn) + : SolverBase(cn) , additional_data(data) {} diff --git a/include/deal.II/lac/solver_minres.h b/include/deal.II/lac/solver_minres.h index 845928b743bc..774f21bed4b9 100644 --- a/include/deal.II/lac/solver_minres.h +++ b/include/deal.II/lac/solver_minres.h @@ -69,7 +69,7 @@ DEAL_II_NAMESPACE_OPEN * @author Thomas Richter, 2000, Luca Heltai, 2006 */ template > -class SolverMinRes : public Solver +class SolverMinRes : public SolverBase { public: /** @@ -155,7 +155,7 @@ template SolverMinRes::SolverMinRes(SolverControl & cn, VectorMemory &mem, const AdditionalData &) - : Solver(cn, mem) + : SolverBase(cn, mem) , res2(numbers::signaling_nan()) {} @@ -164,7 +164,7 @@ SolverMinRes::SolverMinRes(SolverControl & cn, template SolverMinRes::SolverMinRes(SolverControl &cn, const AdditionalData &) - : Solver(cn) + : SolverBase(cn) , res2(numbers::signaling_nan()) {} diff --git a/include/deal.II/lac/solver_qmrs.h b/include/deal.II/lac/solver_qmrs.h index 824412cb1260..5e68e3d8e146 100644 --- a/include/deal.II/lac/solver_qmrs.h +++ b/include/deal.II/lac/solver_qmrs.h @@ -92,7 +92,7 @@ DEAL_II_NAMESPACE_OPEN * @author Guido Kanschat, 1999; Ingo Kligge 2017 */ template > -class SolverQMRS : public Solver +class SolverQMRS : public SolverBase { public: /** @@ -255,7 +255,7 @@ template SolverQMRS::SolverQMRS(SolverControl & cn, VectorMemory &mem, const AdditionalData & data) - : Solver(cn, mem) + : SolverBase(cn, mem) , additional_data(data) , step(0) {} @@ -263,7 +263,7 @@ SolverQMRS::SolverQMRS(SolverControl & cn, template SolverQMRS::SolverQMRS(SolverControl & cn, const AdditionalData &data) - : Solver(cn) + : SolverBase(cn) , additional_data(data) , step(0) {} diff --git a/include/deal.II/lac/solver_relaxation.h b/include/deal.II/lac/solver_relaxation.h index dfa17fa1f6d1..e7c7dab87186 100644 --- a/include/deal.II/lac/solver_relaxation.h +++ b/include/deal.II/lac/solver_relaxation.h @@ -56,7 +56,7 @@ DEAL_II_NAMESPACE_OPEN * @date 2010 */ template > -class SolverRelaxation : public Solver +class SolverRelaxation : public SolverBase { public: /** @@ -95,7 +95,7 @@ class SolverRelaxation : public Solver template SolverRelaxation::SolverRelaxation(SolverControl &cn, const AdditionalData &) - : Solver(cn) + : SolverBase(cn) {} diff --git a/include/deal.II/lac/solver_richardson.h b/include/deal.II/lac/solver_richardson.h index b2a59fc34916..417eff4b25ce 100644 --- a/include/deal.II/lac/solver_richardson.h +++ b/include/deal.II/lac/solver_richardson.h @@ -60,7 +60,7 @@ DEAL_II_NAMESPACE_OPEN * @author Ralf Hartmann */ template > -class SolverRichardson : public Solver +class SolverRichardson : public SolverBase { public: /** @@ -175,7 +175,7 @@ template SolverRichardson::SolverRichardson(SolverControl & cn, VectorMemory &mem, const AdditionalData & data) - : Solver(cn, mem) + : SolverBase(cn, mem) , additional_data(data) {} @@ -184,7 +184,7 @@ SolverRichardson::SolverRichardson(SolverControl & cn, template SolverRichardson::SolverRichardson(SolverControl & cn, const AdditionalData &data) - : Solver(cn) + : SolverBase(cn) , additional_data(data) {} diff --git a/include/deal.II/optimization/solver_bfgs.h b/include/deal.II/optimization/solver_bfgs.h index 5f3ed06779fd..aa23dab64d7b 100644 --- a/include/deal.II/optimization/solver_bfgs.h +++ b/include/deal.II/optimization/solver_bfgs.h @@ -53,7 +53,7 @@ DEAL_II_NAMESPACE_OPEN * @author Denis Davydov, 2018 */ template -class SolverBFGS : public Solver +class SolverBFGS : public SolverBase { public: /** @@ -195,7 +195,7 @@ SolverBFGS::AdditionalData::AdditionalData( template SolverBFGS::SolverBFGS(SolverControl & solver_control, const AdditionalData &data) - : Solver(solver_control) + : SolverBase(solver_control) , additional_data(data) {} diff --git a/source/lac/solver.inst.in b/source/lac/solver.inst.in index ada5bbf82062..7ce237dd364c 100644 --- a/source/lac/solver.inst.in +++ b/source/lac/solver.inst.in @@ -17,5 +17,5 @@ for (S : VECTOR_TYPES) { - template class Solver; + template class SolverBase; } From 9680c3081018ac9346c9bb4f671f913e3ae2e562 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Thu, 28 Mar 2019 09:00:42 -0600 Subject: [PATCH 345/507] Allow initialization of Vector with std::initializer_list. --- include/deal.II/lac/vector.h | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/include/deal.II/lac/vector.h b/include/deal.II/lac/vector.h index 5ba965853180..7372650b49cb 100644 --- a/include/deal.II/lac/vector.h +++ b/include/deal.II/lac/vector.h @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -164,14 +165,34 @@ class Vector : public Subscriptor Vector(Vector &&v) noexcept = default; /** - * Copy constructor taking a vector of another data type. This will fail if - * there is no conversion path from @p OtherNumber to @p Number. Note that - * you may lose accuracy when copying to a vector with data elements with + * Copy constructor taking a vector of another data type. + * + * This constructor will fail to compile if + * there is no conversion path from @p OtherNumber to @p Number. You may + * lose accuracy when copying to a vector with data elements with * less accuracy. */ template explicit Vector(const Vector &v); + /** + * Copy constructor taking an object of type `std::initializer_list`. This + * constructor can be used to initialize a vector using a brace-enclosed + * list of numbers, such as in the following example: + * @code + * Vector v({1,2,3}); + * @endcode + * This creates a vector of size 3, whose (double precision) elements have + * values 1.0, 2.0, and 3.0. + * + * This constructor will fail to compile if + * there is no conversion path from @p OtherNumber to @p Number. You may + * lose accuracy when copying to a vector with data elements with + * less accuracy. + */ + template + explicit Vector(const std::initializer_list &v); + #ifdef DEAL_II_WITH_PETSC /** * Another copy constructor: copy the values from a PETSc vector class. This @@ -1049,6 +1070,14 @@ inline Vector::Vector() +template +template +Vector::Vector(const std::initializer_list &v) + : Vector(v.begin(), v.end()) +{} + + + template template Vector::Vector(const InputIterator first, const InputIterator last) From f0b996c96f16402600fbde5cd31d2e3fbb27573a Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Thu, 28 Mar 2019 09:02:07 -0600 Subject: [PATCH 346/507] Add changelog. --- doc/news/changes/minor/20190328Bangerth | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 doc/news/changes/minor/20190328Bangerth 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) From 292c1c9bbf890280887e46d1dc944db1f8daacc0 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Thu, 28 Mar 2019 09:07:21 -0600 Subject: [PATCH 347/507] Add a test. --- tests/vector/vector_59.cc | 41 +++++++++++++++++++++++++++++++++++ tests/vector/vector_59.output | 3 +++ 2 files changed, 44 insertions(+) create mode 100644 tests/vector/vector_59.cc create mode 100644 tests/vector/vector_59.output diff --git a/tests/vector/vector_59.cc b/tests/vector/vector_59.cc new file mode 100644 index 000000000000..0f6042e463e1 --- /dev/null +++ b/tests/vector/vector_59.cc @@ -0,0 +1,41 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2004 - 2017 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. +// +// --------------------------------------------------------------------- + + + +// check Vector initialization with std::initializer_list objects + +#include + +#include "../tests.h" + + + +int +main() +{ + initlog(); + + Vector vd({1.0, 2.0, 3.0}); + for (const auto &x : vd) + deallog << x << ' '; + deallog << std::endl; + + + Vector vi({1, 2, 3}); + for (const auto &x : vi) + deallog << x << ' '; + deallog << std::endl; +} diff --git a/tests/vector/vector_59.output b/tests/vector/vector_59.output new file mode 100644 index 000000000000..e6f09856b21f --- /dev/null +++ b/tests/vector/vector_59.output @@ -0,0 +1,3 @@ + +DEAL::1.00000 2.00000 3.00000 +DEAL::1.00000 2.00000 3.00000 From cebc4fc676eb5136914d46f95b1e227269c066fe Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Thu, 28 Mar 2019 09:23:22 -0600 Subject: [PATCH 348/507] Fix a changelog entry. --- doc/news/changes/minor/20190326Arndt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/news/changes/minor/20190326Arndt b/doc/news/changes/minor/20190326Arndt index 8e9c7ef382d8..6d4bd85a7338 100644 --- a/doc/news/changes/minor/20190326Arndt +++ b/doc/news/changes/minor/20190326Arndt @@ -1,5 +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) From cb09939b184ba6bdb7f48cc54b9ee1f9d98d73da Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Sat, 30 Mar 2019 08:57:31 -0600 Subject: [PATCH 349/507] Use a range-based for loop. --- source/hp/dof_handler.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/hp/dof_handler.cc b/source/hp/dof_handler.cc index 307dd6015194..6bfa72ddee6a 100644 --- a/source/hp/dof_handler.cc +++ b/source/hp/dof_handler.cc @@ -1222,8 +1222,8 @@ namespace hp { // unsubscribe as a listener to refinement of the underlying // triangulation - for (unsigned int i = 0; i < tria_listeners.size(); ++i) - tria_listeners[i].disconnect(); + for (auto &connection : tria_listeners) + connection.disconnect(); tria_listeners.clear(); // ...and release allocated memory @@ -1514,8 +1514,8 @@ namespace hp { if (this->tria != &tria) { - for (unsigned int i = 0; i < tria_listeners.size(); ++i) - tria_listeners[i].disconnect(); + for (auto &connection : tria_listeners) + connection.disconnect(); tria_listeners.clear(); this->tria = &tria; From 7f12c2c2ae57a994a876ad8f16518f5ba054c27a Mon Sep 17 00:00:00 2001 From: David Wells Date: Sat, 30 Mar 2019 11:28:27 -0400 Subject: [PATCH 350/507] Fix a comment. There are no blocks in this object. --- include/deal.II/lac/vector.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/deal.II/lac/vector.h b/include/deal.II/lac/vector.h index 7372650b49cb..f8ff653eae86 100644 --- a/include/deal.II/lac/vector.h +++ b/include/deal.II/lac/vector.h @@ -353,10 +353,7 @@ class Vector : public Subscriptor swap(Vector &v); /** - * Set all components of the vector to the given number @p s. Simply pass - * this down to the individual block objects, but we still need to declare - * this function to make the example given in the discussion about making - * the constructor explicit work. + * Set all components of the vector to the given number @p s. * * Since the semantics of assigning a scalar to a vector are not immediately * clear, this operator should really only be used if you want to set the From 330bd8ca89086258ef78d0a30cdf22c925a9aebe Mon Sep 17 00:00:00 2001 From: David Wells Date: Sat, 30 Mar 2019 11:28:45 -0400 Subject: [PATCH 351/507] Clean up some headers and code samples. --- include/deal.II/lac/vector.h | 18 +++++++++--------- include/deal.II/lac/vector.templates.h | 1 + 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/deal.II/lac/vector.h b/include/deal.II/lac/vector.h index f8ff653eae86..ecddb7674b03 100644 --- a/include/deal.II/lac/vector.h +++ b/include/deal.II/lac/vector.h @@ -32,10 +32,10 @@ #include -#include -#include +#include #include -#include +#include +#include #include DEAL_II_NAMESPACE_OPEN @@ -642,7 +642,7 @@ class Vector : public Subscriptor * If the current vector is called @p v, then this function is the equivalent * to the code * @code - * for (unsigned int i=0; i #include +#include #include #include #include From c9539d49b6976654cd0c9c6c768bbdbda8bb2090 Mon Sep 17 00:00:00 2001 From: David Wells Date: Sat, 30 Mar 2019 11:39:27 -0400 Subject: [PATCH 352/507] Remove '__' from include guards. --- include/deal.II/differentiation/ad/ad_helpers.h | 2 +- include/deal.II/fe/fe_nedelec_sz.h | 4 ++-- include/deal.II/lac/cuda_kernels.templates.h | 4 ++-- include/deal.II/lac/trilinos_tpetra_vector.templates.h | 4 ++-- include/deal.II/matrix_free/cuda_hanging_nodes_internal.h | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index 507803a0dcf0..8fb914b9be5c 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -4119,4 +4119,4 @@ DEAL_II_NAMESPACE_CLOSE #endif // defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO) -#endif // dealii__adolc_helpers_h +#endif // dealii_differentiation_ad_ad_helpers_h diff --git a/include/deal.II/fe/fe_nedelec_sz.h b/include/deal.II/fe/fe_nedelec_sz.h index ba5dfbbe1d04..1d93d2e85799 100644 --- a/include/deal.II/fe/fe_nedelec_sz.h +++ b/include/deal.II/fe/fe_nedelec_sz.h @@ -13,8 +13,8 @@ // // --------------------------------------------------------------------- -#ifndef dealii__fe_nedelec_sz_h -#define dealii__fe_nedelec_sz_h +#ifndef dealii_fe_nedelec_sz_h +#define dealii_fe_nedelec_sz_h #include #include diff --git a/include/deal.II/lac/cuda_kernels.templates.h b/include/deal.II/lac/cuda_kernels.templates.h index d42e469329e1..2805692da598 100644 --- a/include/deal.II/lac/cuda_kernels.templates.h +++ b/include/deal.II/lac/cuda_kernels.templates.h @@ -13,8 +13,8 @@ // // --------------------------------------------------------------------- -#ifndef dealii__cuda_kernels_templates_h -#define dealii__cuda_kernels_templates_h +#ifndef dealii_cuda_kernels_templates_h +#define dealii_cuda_kernels_templates_h #include diff --git a/include/deal.II/lac/trilinos_tpetra_vector.templates.h b/include/deal.II/lac/trilinos_tpetra_vector.templates.h index b102775201e3..0a9ba5114115 100644 --- a/include/deal.II/lac/trilinos_tpetra_vector.templates.h +++ b/include/deal.II/lac/trilinos_tpetra_vector.templates.h @@ -13,8 +13,8 @@ // // --------------------------------------------------------------------- -#ifndef dealii__trilinos_tpetra_vector_templates_h -#define dealii__trilinos_tpetra_vector_templates_h +#ifndef dealii_trilinos_tpetra_vector_templates_h +#define dealii_trilinos_tpetra_vector_templates_h #include diff --git a/include/deal.II/matrix_free/cuda_hanging_nodes_internal.h b/include/deal.II/matrix_free/cuda_hanging_nodes_internal.h index d1ae2f745a34..8fcab1a6d219 100644 --- a/include/deal.II/matrix_free/cuda_hanging_nodes_internal.h +++ b/include/deal.II/matrix_free/cuda_hanging_nodes_internal.h @@ -13,8 +13,8 @@ // // --------------------------------------------------------------------- -#ifndef dealii__cuda_hanging_nodes_internal_h -#define dealii__cuda_hanging_nodes_internal_h +#ifndef dealii_cuda_hanging_nodes_internal_h +#define dealii_cuda_hanging_nodes_internal_h #include From 8d35766e0e2d5426a4a9be6e0695ea9082d29f52 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Sun, 31 Mar 2019 01:52:46 +0100 Subject: [PATCH 353/507] Update PETSc version compatibility --- doc/external-libs/petsc.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. From 3ba06905454cc6ad892f3210a5f45d804bb13cbd Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Sat, 30 Mar 2019 11:46:23 -0600 Subject: [PATCH 354/507] CI: archive detailed.log --- Jenkinsfile | 5 ++++- contrib/ci/Jenkinsfile.osx | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 81ad227897e4..48064a8afb4f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -101,6 +101,8 @@ pipeline 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 { @@ -120,7 +122,6 @@ pipeline sh '''#!/bin/bash export NP=`grep -c ^processor /proc/cpuinfo` export TEST_TIME_LIMIT=1200 - echo $NP mkdir -p /home/dealii/build cd /home/dealii/build cmake -G "Ninja" \ @@ -152,6 +153,8 @@ pipeline 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 { diff --git a/contrib/ci/Jenkinsfile.osx b/contrib/ci/Jenkinsfile.osx index b9c556d55d02..5ba9af45ec27 100644 --- a/contrib/ci/Jenkinsfile.osx +++ b/contrib/ci/Jenkinsfile.osx @@ -100,6 +100,10 @@ pipeline post { + always + { + archiveArtifacts artifacts: '$WORKSPACE/build/detailed.log', fingerprint: true + } failure { githubNotify context: 'OSX', description: 'build failed', status: 'FAILURE' From cd518ac0c81b75c248e39be671aacfaea80ad732 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Sat, 30 Mar 2019 21:26:21 -0600 Subject: [PATCH 355/507] fix path --- contrib/ci/Jenkinsfile.osx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ci/Jenkinsfile.osx b/contrib/ci/Jenkinsfile.osx index 5ba9af45ec27..c214ca0a8efa 100644 --- a/contrib/ci/Jenkinsfile.osx +++ b/contrib/ci/Jenkinsfile.osx @@ -102,7 +102,7 @@ pipeline { always { - archiveArtifacts artifacts: '$WORKSPACE/build/detailed.log', fingerprint: true + archiveArtifacts artifacts: 'build/detailed.log', fingerprint: true } failure { From ec8ee20122c05905267a98a25ea895fd54cff351 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Mon, 1 Apr 2019 08:56:15 -0600 Subject: [PATCH 356/507] several doxygen errors and warnings --- doc/doxygen/options.dox.in | 2 ++ examples/step-28/step-28.cc | 3 +- examples/step-43/step-43.cc | 3 +- examples/step-57/step-57.cc | 31 ++++++++++++------- include/deal.II/base/logstream.h | 2 ++ .../deal.II/differentiation/ad/ad_helpers.h | 2 +- include/deal.II/lac/lapack_full_matrix.h | 2 ++ include/deal.II/matrix_free/task_info.h | 5 --- include/deal.II/particles/particle.h | 3 +- 9 files changed, 31 insertions(+), 22 deletions(-) diff --git a/doc/doxygen/options.dox.in b/doc/doxygen/options.dox.in index 14fd142f2385..0bd1c34b8bcd 100644 --- a/doc/doxygen/options.dox.in +++ b/doc/doxygen/options.dox.in @@ -213,6 +213,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/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-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-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/include/deal.II/base/logstream.h b/include/deal.II/base/logstream.h index ee03ae5f672e..316e1b5ed98b 100644 --- a/include/deal.II/base/logstream.h +++ b/include/deal.II/base/logstream.h @@ -145,6 +145,8 @@ class LogStream : public Subscriptor /** * Enable output to a second stream o. * + * @param o Attach this output stream. + * * @param[in] print_job_id Whether or not the JobIdentifier for the current * process should be printed to the stream. * diff --git a/include/deal.II/differentiation/ad/ad_helpers.h b/include/deal.II/differentiation/ad/ad_helpers.h index 8fb914b9be5c..13844113c2c7 100644 --- a/include/deal.II/differentiation/ad/ad_helpers.h +++ b/include/deal.II/differentiation/ad/ad_helpers.h @@ -2383,7 +2383,7 @@ namespace Differentiation * the input FEValuesExtractors::SymmetricTensor @p extractor_symm_tensor. * If the @p ignore_symmetries is set true, then all * component of the tensor are considered to be independent. If set to - * code>false, then the set of returned indices will contain + * false, then the set of returned indices will contain * duplicate entries for components that are symmetric. */ template diff --git a/include/deal.II/lac/lapack_full_matrix.h b/include/deal.II/lac/lapack_full_matrix.h index 802a40c9d7e6..542ee4926b33 100644 --- a/include/deal.II/lac/lapack_full_matrix.h +++ b/include/deal.II/lac/lapack_full_matrix.h @@ -866,6 +866,8 @@ class LAPACKFullMatrix : public TransposeTable * * The parameters allow for a flexible setting of the output format: * + * @param out This specifies the stream to write to. + * * @param precision denotes the number of trailing digits. * * @param scientific is used to determine the number format, where diff --git a/include/deal.II/matrix_free/task_info.h b/include/deal.II/matrix_free/task_info.h index d7d973a22beb..86961db0c5ee 100644 --- a/include/deal.II/matrix_free/task_info.h +++ b/include/deal.II/matrix_free/task_info.h @@ -231,11 +231,6 @@ namespace internal * represented by a chunk of cells. The cell chunks are formed before * subdivision into partitions and colors. * - * @param cell_active_fe_index The active FE index corresponding to the - * individual indices in the list of all cell indices, in order to be - * able to not place cells with different indices into the same cell - * batch with vectorization. - * * @param connectivity (in/out) Determines whether cells `i` and `j` are * conflicting, expressed by an entry in position (i,j). * diff --git a/include/deal.II/particles/particle.h b/include/deal.II/particles/particle.h index df6ebd17418e..178e57959b59 100644 --- a/include/deal.II/particles/particle.h +++ b/include/deal.II/particles/particle.h @@ -147,7 +147,8 @@ namespace Particles * contains serialized data of the same length and type that is allocated * by @p property_pool. */ - Particle(const void *&begin_data, PropertyPool *const = nullptr); + Particle(const void *& begin_data, + PropertyPool *const property_pool = nullptr); /** * Move constructor for Particle, creates a particle from an existing From 3a1f07a685b04e58ad66a70d37fc748d05eb3b71 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 2 Apr 2019 05:22:36 +0200 Subject: [PATCH 357/507] Unify intrinsics headers --- include/deal.II/base/vectorization.h | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/include/deal.II/base/vectorization.h b/include/deal.II/base/vectorization.h index 1b8c47005c3c..39b374b23ff0 100644 --- a/include/deal.II/base/vectorization.h +++ b/include/deal.II/base/vectorization.h @@ -51,15 +51,9 @@ "Mismatch in vectorization capabilities: AVX-512F was detected during configuration of deal.II and switched on, but it is apparently not available for the file you are trying to compile at the moment. Check compilation flags controlling the instruction set, such as -march=native." #endif -#if DEAL_II_COMPILER_VECTORIZATION_LEVEL >= 2 && \ - (defined(__AVX__) || defined(__AVX512F__)) // AVX, AVX-512 -# include -#elif DEAL_II_COMPILER_VECTORIZATION_LEVEL == 1 && defined(__SSE2__) // SSE2 -# include -#endif - - -#if DEAL_II_COMPILER_VECTORIZATION_LEVEL >= 1 && defined(__ALTIVEC__) +#if defined(_MSC_VER) +# include +#elif defined(__ALTIVEC__) # include // altivec.h defines vector, pixel, bool, but we do not use them, so undefine @@ -67,7 +61,8 @@ # undef vector # undef pixel # undef bool - +#else +# include #endif DEAL_II_NAMESPACE_OPEN From fb6d449bdfac47f9fc8eca0b34be94f0d5aa32d6 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Tue, 2 Apr 2019 16:11:44 +0200 Subject: [PATCH 358/507] set LAPACK_INCLUDE_DIRS and LAPACK_USER_INCLUDE_DIRS --- cmake/modules/FindLAPACK.cmake | 5 +++++ 1 file changed, 5 insertions(+) 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 From 16e66fd8c42842e5bd8a275ed54a480d2b76befc Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Wed, 20 Mar 2019 15:19:41 +0100 Subject: [PATCH 359/507] Add SymEngine macros to config.h --- include/deal.II/base/config.h.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/deal.II/base/config.h.in b/include/deal.II/base/config.h.in index 0a229133db69..0ba349af2709 100644 --- a/include/deal.II/base/config.h.in +++ b/include/deal.II/base/config.h.in @@ -61,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 @@ -177,6 +178,9 @@ /* 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 From 534cfa1c2f777ec0a48f8e1d8a3e7338c85589eb Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sat, 30 Mar 2019 11:18:46 +0100 Subject: [PATCH 360/507] Add traits for SD numbers --- include/deal.II/differentiation/sd.h | 46 +++++++++ .../sd/symengine_number_traits.h | 95 +++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 include/deal.II/differentiation/sd.h create mode 100644 include/deal.II/differentiation/sd/symengine_number_traits.h diff --git a/include/deal.II/differentiation/sd.h b/include/deal.II/differentiation/sd.h new file mode 100644 index 000000000000..f2707cbfc601 --- /dev/null +++ b/include/deal.II/differentiation/sd.h @@ -0,0 +1,46 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_differentiation_sd_h +#define dealii_differentiation_sd_h + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include +# include +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + /** + * Wrappers for symbolic differentiation libraries. Currently there is support + * for the following libraries: + * - SymEngine + * + * @ingroup auto_symb_diff + */ + namespace SD + {} +} // namespace Differentiation + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE + +#endif // dealii_differentiation_sd_h diff --git a/include/deal.II/differentiation/sd/symengine_number_traits.h b/include/deal.II/differentiation/sd/symengine_number_traits.h new file mode 100644 index 000000000000..295584a9bb04 --- /dev/null +++ b/include/deal.II/differentiation/sd/symengine_number_traits.h @@ -0,0 +1,95 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_differentiation_sd_symengine_number_traits_h +#define dealii_differentiation_sd_symengine_number_traits_h + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include + +# include + + +DEAL_II_NAMESPACE_OPEN + + +namespace Differentiation +{ + namespace SD + { + /** + * A struct to indicate whether a given @p NumberType is a supported + * symbolically differentiable number or not. By default, numbers are not + * considered to have the necessary characteristics to fulfill this + * condition. + * + * @author Jean-Paul Pelteret, 2019 + */ + template + struct is_sd_number : std::false_type + {}; + + + /** + * A struct to indicate whether a given @p NumberType is a supported + * SymEngine number or not. By default, numbers are not + * considered to have the necessary characteristics to fulfill this + * condition. + * + * @author Jean-Paul Pelteret, 2019 + */ + template + struct is_symengine_number : std::false_type + {}; + + + /*--- SymEngine Expression class ---*/ + + + /** + * A struct to indicate whether a given @p NumberType is a supported + * symbolically differentiable number or not. + * This is a specialization for the SymEngine Expression class. + * + * @author Jean-Paul Pelteret, 2019 + */ + template <> + struct is_symengine_number : std::true_type + {}; + + + /** + * A struct to indicate whether a given @p NumberType is a supported + * symbolically differentiable number or not. + * This is a specialization for the SymEngine Expression class. + * + * @author Jean-Paul Pelteret, 2019 + */ + template <> + struct is_sd_number : std::true_type + {}; + + } // namespace SD +} // namespace Differentiation + + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE + +#endif // dealii_differentiation_sd_symengine_number_traits_h From 9386bc34a4c2b7f1821d070b3f8136eb8ac861ac Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sat, 30 Mar 2019 11:19:55 +0100 Subject: [PATCH 361/507] Add basis for SymEngine (SD) wrappers - Types - Expression class - Utilities --- .../changes/major/20190329Jean-PaulPelteret | 16 + .../sd/symengine_number_types.h | 1302 +++++++++++++++++ .../differentiation/sd/symengine_types.h | 81 + .../differentiation/sd/symengine_utilities.h | 62 + source/differentiation/CMakeLists.txt | 3 +- source/differentiation/sd/CMakeLists.txt | 32 + .../sd/symengine_number_types.cc | 541 +++++++ source/differentiation/sd/symengine_types.cc | 55 + .../differentiation/sd/symengine_utilities.cc | 63 + 9 files changed, 2154 insertions(+), 1 deletion(-) create mode 100644 doc/news/changes/major/20190329Jean-PaulPelteret create mode 100644 include/deal.II/differentiation/sd/symengine_number_types.h create mode 100644 include/deal.II/differentiation/sd/symengine_types.h create mode 100644 include/deal.II/differentiation/sd/symengine_utilities.h create mode 100644 source/differentiation/sd/CMakeLists.txt create mode 100644 source/differentiation/sd/symengine_number_types.cc create mode 100644 source/differentiation/sd/symengine_types.cc create mode 100644 source/differentiation/sd/symengine_utilities.cc diff --git a/doc/news/changes/major/20190329Jean-PaulPelteret b/doc/news/changes/major/20190329Jean-PaulPelteret new file mode 100644 index 000000000000..d5f571d8fab3 --- /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/include/deal.II/differentiation/sd/symengine_number_types.h b/include/deal.II/differentiation/sd/symengine_number_types.h new file mode 100644 index 000000000000..b3a487dcb2c6 --- /dev/null +++ b/include/deal.II/differentiation/sd/symengine_number_types.h @@ -0,0 +1,1302 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_differentiation_sd_symengine_number_types_h +#define dealii_differentiation_sd_symengine_number_types_h + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +// Low level +# include +# include +# include +# include + +// Number types +# include +# include +# include +# include + +// Number operations +# include +# include +# include +# include + +// Evaluation +# include +# include +# include + +// Differentiation +# include + +# include +# include + +# include + +# include +# include +# include +# include +# include +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + namespace SE = ::SymEngine; + + /** + * @addtogroup Exceptions + * @{ + */ + + /** + * An exception to indicate that the string sent to the SymEngine + * parser is not valid. + */ + DeclException1( + ExcSymEngineParserError, + std::string, + << "The string '" << arg1 + << "' could not be parsed successfully. Are you sure that (1) it " + << "consists of legitimate operations and syntax, and (2) you've " + << "previously declared all symbolic variables that are present " + << "in the expression?"); + + //@} + + /** + * A class to wrap SymEngine expressions. + * + * With this number type, SymEngine numbers can be used to perform scalar + * and tensor mathematics in deal.II. It (or the SymEngine::Expression + * class, of which it stores an instance) therefore forms the basis of + * symbolic computation via SymEngine in deal.II. With it one can + * perform symbolic differentiation and subsequent substitution with both + * scalars and deal.II's native Tensor and SymmetricTensor types. + * + * The symbolic features that this class supports includes: + * - expression parsing, + * - comparison operations, + * - logical operations, + * - math operations, + * - conditional expression construction, + * - differentiation, + * - substitution (partial and complete), and + * - serialization. + * + * A simple example of how this class may be used is as follows: + * @code + * // Constructing a symbolic expression: + * // This is a symbol, which we will treat as an argument to a symbolic + * // function. + * const Expression x("x"); + * const Expression y("y"); + * // This is a symbolic expression, which is an expression constructed + * // from individual symbols. + * const Expression f = (x + y)*(x + y); + * + * // Value substitution + * types::substitution_map substitution_map; + * substitution_map[x] = Expression(1); + * substitution_map[y] = Expression(2.5); + * const double evaluated_f = + * f.substitute_and_evaluate(substitution_map); + * // We could also have performed substitution of each individual + * // argument, if we wanted to. This means that one can partially + * // substitute an expression at any time. + * @endcode + * + * A more intricate example of conditional evaluation is as follows: + * @code + * // Construct symbolic expressions + * const Expression x("x"); + * const Expression y("y"); + * const Expression f_plus = (x + y)*(x + y); + * // Parsing expressions from a string is also possible. Its arguments + * // must have been previously declared through (and in scope). + * const Expression f_minus ("(x-y)*(x-y)", true); + * + * // Constructing a conditional expression + * const SD_number_t f((x > Expression(0.0)), f_plus, f_minus); + * + * // Value substitution + * types::substitution_map substitution_map; + * substitution_map[x] = Expression(1); + * substitution_map[y] = Expression(2.5); + * const double evaluated_f = + * f.substitute_and_evaluate(substitution_map); + * // Since the substituted value for x was greater than zero, we expect + * // that the returned result now in evaluated_f was evaluated from + * // the function f_plus. + * @endcode + * + * Lastly, here is an example using symbolic differentiation: + * @code + * // Construct symbolic expressions + * const Expression x("x"); + * const Expression f("x**2", true); + * + * // Now perform differentiation. Specifically, we differentiate the + * // function "f" with respect to the symbolic variable "x". + * // The result should be the expression "2*x". + * const Expression df_dx = f.differentiate(x); + * + * // Value substitution + * types::substitution_map substitution_map; + * substitution_map[x] = Expression(10.0); + * const double evaluated_df_dx = + * evaluated_df_dx.substitute_and_evaluate(substitution_map); + * // We can expect the above to evaluate to "2*10" which is, + * // of course, the numeric value 20. + * @endcode + * + * @author Jean-Paul Pelteret, 2019 + */ + class Expression + { + public: + /** + * @name Constructors + */ + //@{ + + /** + * Default constructor. + */ + Expression(); + + /** + * Constructor for boolean types. + * + * @note This constructor is marked as explicit so that there are no + * potential ambiguities related to implicit conversions in either user + * code or math functions that are loaded into the standard namespace. + */ + explicit Expression(const bool &value); + + /** + * Constructor for arithmetic number types. + * + * @note This constructor is marked as explicit so that there are no + * potential ambiguities related to implicit conversions in either user + * code or math functions that are loaded into the standard namespace. + */ + template ::value>::type> + explicit Expression(const NumberType &value); + + /** + * Constructor for complex numbers templated on arithmetic number types. + * + * @note This constructor is marked as explicit so that there are no + * potential ambiguities related to implicit conversions in either user + * code or math functions that are loaded into the standard namespace. + */ + template ::value>::type> + explicit Expression(const std::complex &value); + + /** + * Constructor for integer types. + */ + Expression(const SE::integer_class &value); + + /** + * Constructor for rational types. + * + * It is expected that both the @p numerator and @p denominator + * be integral types. + */ + template ::value>::type> + Expression(const NumberType &numerator, const NumberType &denominator); + + /** + * Constructor for rational types. + */ + Expression(const SE::rational_class &value); + + /** + * Constructor for a piecewise defined function. + * + * The generated expression may be interpreted as the result of the + * teniary operator, i.e. + * (condition ? expression_if_true : expression_if_false). + * + * The @p condition can be any expression that renders an expression that + * is convertible to a SymEngine::Boolean operator. This includes: + * - the logical operators of the deal.II Expression class + * - SymEngine::boolean() + * - SymEngine::contains() + * - SymEngine::Eq() + * - SymEngine::Ne() + * - SymEngine::Ge() + * - SymEngine::Gt() + * - SymEngine::Le() + * - SymEngine::Lt() + * - SymEngine::logical_and() + * - SymEngine::logical_nand() + * - SymEngine::logical_or() + * - SymEngine::logical_not() + * - SymEngine::logical_nor() + * - SymEngine::logical_xor() + * - SymEngine::logical_xnor() + * - ... + * + * An example of this constructor's use is as follows: + * @code + * const Expression x("x"); + * const Expression y("y"); + * + * // Construct a conditional expression using the symbolic variables. + * const Expression f ((x < Expression(0.0)), x+y, x-y); + * @endcode + */ + Expression(const Expression &condition, + const Expression &expression_if_true, + const Expression &expression_if_false); + + /** + * Constructor for a piecewise defined function. + * + * The generated expression may be interpreted as the result of the + * set of nested if-elseif-else statements, i.e. (in pseudo-code) + * @code + * if (condition_expression[0].first == true) + * return condition_expression[0].second; + * else if (condition_expression[1].first == true) + * return condition_expression[1].second; + * else if (...) + * return ...; + * else + * return expression_otherwise; + * @endcode + * if the input vector has more than 2 elements. + * + * This variant takes the piecewise evaluated conditions and its results + * as the first argument, and the default return value as the second + * argument. + */ + Expression(const std::vector> + & condition_expression, + const Expression &expression_otherwise); + + /** + * Constructor for a piecewise defined function. + * + * The generated expression may be interpreted as the result of the + * set of nested if-elseif statements, i.e. (in pseudo-code) + * @code + * if (condition_expression[0].first == true) + * return condition_expression[0].second; + * else if (condition_expression[1].first == true) + * return condition_expression[1].second; + * else if (...) + * return ...; + * @endcode + * if the input vector has more than 2 elements. + * + * This variant takes only the piecewise evaluated conditions and its + * results. If none of the conditions are met upon evaluation then the + * returned result will be NaN. + */ + Expression(const std::vector> + &condition_expression); + + + /** + * Constructor for symbolic types. + * + * This constructor initializes a symbolic type with a character array + * representing its symbolic value. + */ + Expression(const char *symbol); + + /** + * Constructor for symbolic types. + * + * This constructor initializes a symbolic type with a string + * representing its symbolic value. + * If the @p parse_as_expression flag is false, then the + * @p symb_expr (potentially composed of mulitple characters) will be + * interpreted as a single symbol. + * If the @p parse_as_expression flag is true, then the + * @p symb_expr will be parsed as a symbolic expression (potentially + * composed of multiple symbols, constants, etc.). + */ + Expression(const std::string &symb_expr, + const bool parse_as_expression = false); + + /** + * Constructor for function symbol types. + * + * This constructor initializes a function symbol with a string + * representing its symbolic name. + */ + Expression(const std::string & symbol_func, + const types::symbol_vector &arguments); + + /** + * Copy constructor. + */ + Expression(const Expression &rhs) = default; + + /** + * Copy constructor. + * + * @note This constructor is marked as explicit to prevent any ambiguities + * from implicit conversion when both the deal.II and SymEngine namespaces + * are imported. + */ + explicit Expression(const SE::Expression &rhs); + + /** + * Copy constructor. + * + * This allows us to create our class straight from the results of + * SymEngine operations. This is especially important for operations like + * "diff", because the returned result is not primitive, but rather a set + * of compound operations. + */ + Expression(const SE::RCP &rhs); + + /** + * Move constructor. + */ + Expression(Expression &&rhs) = default; + + /** + * Move constructor. + * + * This allows us to create our class straight from the results of + * SymEngine operations. This is especially important for operations like + * "diff", because the returned result is not primitive, but rather a set + * of compound operations. + */ + Expression(SE::RCP &&rhs); + + /** + * Destructor. + */ + virtual ~Expression() = default; + + //@} + + /** + * Utilities + */ + //@{ + + /** + * Parse an expression from a string representing a symbolic @p expression. + * This overwrites any existing value or expression that this object + * represents. + */ + Expression & + parse(const std::string &expression); + + /** + * Print the value stored by this object. + * + * Since the stored value could be one of a number of types, we leave + * SymEngine to cast and output the correct representation of the data. + */ + std::ostream & + print(std::ostream &stream) const; + + /** + * Save the value stored by this object to the @p stream. + * + * Each expression will be saved on a new line of the @p stream. + */ + void + save(std::ostream &stream) const; + + /** + * Load the value stored in the @p stream into this object. + * + * It is expected that each expression appears on its own on single + * line of @p stream. + * + * @note When loading a symbolic expression, it is imperative that + * you first create or load all of the symbolic variables used in + * the saved expression. + */ + void + load(std::istream &stream); + + /** + * Write and read the data of this object from a stream for the purpose + * of serialization. + * + * This effecively saves or loads the value stored into/out of the + * @p archive with the given @p version number into this object. + * If deserializing data, then the previous contents of this object + * are thrown away. + * + * @note When deserializing a symbolic expression, it is imperative that + * you first create or deserialize all of the symbolic variables used in + * the serialized expression. + */ + template + void + serialize(Archive &archive, const unsigned int version); + + //@} + + /** + * @name Values + */ + //@{ + + /** + * Return the value or expression that this class instance represents. + */ + const SE::Expression & + get_expression() const; + + /** + * Return the primitive SymEngine data type that stores the value or + * expression represented by this object. + */ + const SE::Basic & + get_value() const; + + /** + * Return the pointer to the primitive SymEngine data type that stores + * the value or expression represented by this object. + */ + const SE::RCP & + get_RCP() const; + + //@} + + /** + * @name Math and relational operators with (potentially) symbolic types + */ + //@{ + + /** + * Assignment operator. + * + * Sets the data of this object's @p expression equal + * to that of the @p rhs object. + */ + Expression & + operator=(const Expression &rhs); + + /** + * Assignment operator. + * + * Sets the data of this object's @p expression equal + * to that of the @p rhs object. + */ + Expression & + operator=(Expression &&rhs); + + /** + * Addition assignment. + * + * The @p rhs @p expression is added in-place to that of + * this object's @p expression. + */ + Expression & + operator+=(const Expression &rhs); + + /** + * Subtraction assignment. + * + * The @p rhs @p expression is subtracted in-place from that of + * this object's @p expression. + */ + Expression & + operator-=(const Expression &rhs); + + /** + * Multiplication assignment. + * + * This object's @p expression is multiplied in-place by that of + * the @p rhs @p expression. + */ + Expression & + operator*=(const Expression &rhs); + + /** + * Division assignment. + * + * This object's @p expression is divided in-place by that of + * the @p rhs @p expression. + */ + Expression & + operator/=(const Expression &rhs); + + //@} + + /** + * @name Math and relational operators with numeric types + */ + //@{ + + /** + * Assignment operator. + * + * Set the data of this object's @p expression equal + * to the numerical value of the @p rhs. + */ + template + Expression & + operator=(const NumberType &rhs); + + /** + * Negation operator. + * + * Return a the result of pre-multipying this object's @p expression + * by -1. + * + * @note This operation is not performed in-place. + */ + Expression + operator-() const; + + /** + * Addition assignment. + * + * The numerical value of the @p rhs is added in-place to that of + * this object's @p expression. + */ + template + Expression & + operator+=(const NumberType &rhs); + + /** + * Subtraction assignment. + * + * The numerical value of the @p rhs is subtracted in-place from that of + * this object's @p expression. + */ + template + Expression & + operator-=(const NumberType &rhs); + + /** + * Multiplication assignment. + * + * This object's @p expression is multiplied in-place by that of + * the numerical value of the @p rhs. + */ + template + Expression & + operator*=(const NumberType &rhs); + + /** + * Division assignment. + * + * This object's @p expression is divided in-place by that of + * the numerical value of the @p rhs. + */ + template + Expression & + operator/=(const NumberType &rhs); + + //@} + + /** + * @name Differentiation + */ + //@{ + + /** + * Return the derivative of this object's @p expression + * with respect to the given @p symbol. + */ + Expression + differentiate(const Expression &symbol) const; + + /** + * Return the derivative of this object's @p expression + * with respect to the given @p symbol. + */ + Expression + differentiate(const SE::RCP &symbol) const; + + /** + * Return the derivative of this object's @p expression + * with respect to the potential @p symbol. + */ + Expression + differentiate(const SE::RCP &symbol) const; + + //@} + + /** + * @name Dictionary-based substitution + */ + //@{ + + /** + * Perform substitution of all symbols found in this object's @p expression + * that match a key in the @p substitution_values map. + * + * @note The replacement value (the entry in the @p substitution_values + * that is paired with a key) need not necessarily be numerical, but may + * also be another symbolic type. + * + * @note With dictionary substitution, partial substitution is allowed + * (i.e. an incomplete substitution map can be used and the return type + * can be symbolic). + */ + Expression + substitute(const types::substitution_map &substitution_values) const; + + /** + * Perform substitution of all symbols found in this object's @p expression + * that match the @p symbol. Each @p symbol will be substituted with + * the given @p value. + * + * @note With dictionary substitution, partial substitution is allowed + * (i.e. an incomplete substitution map can be used and the return type + * can be symbolic). + */ + Expression + substitute(const Expression &symbol, const Expression &value) const; + + /** + * Perform substitution of all symbols found in this object's @p expression + * that match the @p symbol. Each @p symbol will be substituted with + * the given @p value. + * + * @note With dictionary substitution, partial substitution is allowed + * (i.e. an incomplete substitution map can be used and the return type + * can be symbolic). + */ + template + Expression + substitute(const Expression &symbol, const NumberType &value) const; + + /** + * Full substitution and evaluation. This creates a Expression by + * symbol substitution and then immediately computes its numerical value. + * + * @note All symbols must be resolved by the substitution map in order + * for this function to return successfully. + */ + template + ReturnType + substitute_and_evaluate( + const types::substitution_map &substitution_values) const; + + //@} + + /** + * @name Conversion operators + */ + //@{ + + /** + * Conversion operator for real integer or floating point values, and + * complex integer or floating point values. + * + * @note This function is marked explicit so that the conversion must be + * performed using a static_cast. In normal use, one would have expected + * (Expression)*(double) --> (Expression) + * If this function were not marked as explicit, then we could potentially + * have + * (Expression)*(double) --> (double) + * So, to get out a value on needs to do the following: + * + * + * const NumberType val = static_cast(Expression); + * + * + * or, probably less desirably, + * + * + * const NumberType val = NumberType(Expression); + * + * + * @note If the underlying number is a custom type (i.e. encapsulated by a + * NumberWrapper), then it is necessary to derive a new class from + * Expression and define a specialized conversion operator + * that calls an Evaluator that is specialized for this custom number + * type. This could be achieved with an overriding conversion function + * in the base class, for example: + * + * + * class MyNumber : public Expression + * { + * ... + * template + * explicit operator ResultType() const + * { + * if (this->get_value()->get_type_code() == SE::NUMBER_WRAPPER) + * { + * // Implement custom evaluation function + * const ResultType result = ...; + * return result; + * } + * else + * // Call base class conversion operator + * return Expression::operator ResultType(); + * } + * } + * + */ + template + explicit operator ResultType() const; + + /** + * Conversion operator that returns the value or expression that this + * class instance represents. + */ + explicit operator const SE::Expression &() const; + + /** + * Conversion operator that returns a SymEngine reference counted pointer + * to the fundamental type. + */ + operator const SE::RCP &() const; + + //@} + + protected: + /** + * Return the value or expression that this class instance represents. + */ + SE::Expression & + get_expression(); + + private: + /** + * The value or expression that this instance of this class is to + * represent. + */ + SE::Expression expression; + }; + + /** + * @name Type traits + */ + //@{ + + /** + * A struct to indicate whether a given @p NumberType is a supported + * symbolically differentiable number or not. + * This is a specialization for the deal.II Expression class. + * + * @author Jean-Paul Pelteret, 2019 + */ + template <> + struct is_symengine_number : std::true_type + {}; + + + /** + * A struct to indicate whether a given @p NumberType is a supported + * SymEngine number or not. + * This is a specialization for the deal.II Expression class. + * + * @author Jean-Paul Pelteret, 2019 + */ + template <> + struct is_sd_number : std::true_type + {}; + + //@} + + /** + * @name Bitwise operators + */ + //@{ + + /** + * Bitwise left shift operator. + * + * This is used to output the @p expression to the input @p stream. + */ + std::ostream & + operator<<(std::ostream &stream, const Expression &expression); + + /** + * Bitwise right shift operator. + * + * This is used to read in an @p expression from the input @p stream. + */ + std::istream & + operator>>(std::istream &stream, Expression &expression); + + //@} + + /** + * @name Comparison operators + */ + //@{ + + /** + * Equality operator. + * + * Return whether the @p lhs is equal to the @p rhs. + */ + Expression + operator==(const Expression &lhs, const Expression &rhs); + + /** + * Non-equality operator. + * + * Return whether the @p lhs is not equal to the @p rhs. + */ + Expression + operator!=(const Expression &lhs, const Expression &rhs); + + /** + * Less than operator. + * + * Return whether the @p lhs is less than the @p rhs. + */ + Expression + operator<(const Expression &lhs, const Expression &rhs); + + /** + * Greater than operator. + * + * Return whether the @p lhs is greater than the @p rhs. + */ + Expression + operator>(const Expression &lhs, const Expression &rhs); + + /** + * Less than or equals operator. + * + * Return whether the @p lhs is less than, or equal to, the @p rhs. + */ + Expression + operator<=(const Expression &lhs, const Expression &rhs); + + /** + * Greater than or equals operator. + * + * Return whether the @p lhs is greater than, or equal to, the @p rhs. + */ + Expression + operator>=(const Expression &lhs, const Expression &rhs); + + //@} + + /** + * @name Logical operators + */ + //@{ + + /** + * Logical not operator. + * + * @note This operator can only be applied on boolean and conditional + * expressions. + */ + Expression operator!(const Expression &expression); + + /** + * Logical and operator. + * + * @note This operator can only be applied on boolean and conditional + * expressions. + */ + Expression operator&(const Expression &lhs, const Expression &rhs); + + /** + * Logical inclusive or operator. + * + * @note This operator can only be applied on boolean and conditional + * expressions. + */ + Expression + operator|(const Expression &lhs, const Expression &rhs); + + /** + * Logical exclusive or (xor) operator. + * + * @note This operator can only be applied on boolean and conditional + * expressions. + */ + Expression + operator^(const Expression &lhs, const Expression &rhs); + + /** + * And operator. + * + * @note This operator can only be applied on boolean and conditional + * expressions. + * This operator is a convenience wrapper for the logical and operator. + */ + Expression + operator&&(const Expression &lhs, const Expression &rhs); + + /** + * Inclusive or operator. + * + * @note This operator can only be applied on boolean and conditional + * expressions. + * This operator is a convenience wrapper for the logical or operator. + */ + Expression + operator||(const Expression &lhs, const Expression &rhs); + + //@} + + /** + * @name Mathematical operators + */ + //@{ + + /** + * Addition operator. + * + * Return the result of adding the @p rhs to the @p lhs. + */ + Expression + operator+(Expression lhs, const Expression &rhs); + + /** + * Subtraction operator. + * + * Return the result of subtracting the @p rhs from the @p lhs. + */ + Expression + operator-(Expression lhs, const Expression &rhs); + + /** + * Multiplication operator. + * + * Return the result of multiplying the @p lhs by the @p rhs. + */ + Expression operator*(Expression lhs, const Expression &rhs); + + /** + * Division operator. + * + * Return the result of dividing the @p lhs by the @p rhs. + */ + Expression + operator/(Expression lhs, const Expression &rhs); + + /** + * General addition operator. + * + * Return the result of adding the @p rhs to the @p lhs. + * The @p lhs type may be any supported number type, and the result + * is promoted to a Expression. The type conversion makes writing + * scalar expressions using Expression more natural. + */ + template ::value>::type> + inline Expression + operator+(const NumberType &lhs, const Expression &rhs) + { + return Expression(lhs) + rhs; + } + + /** + * General addition operator. + * + * Return the result of adding the @p rhs to the @p lhs. + * The @p rhs type may be any supported number type, and the result + * is promoted to a Expression. The type conversion makes writing + * scalar expressions using Expression more natural. + */ + template ::value>::type> + inline Expression + operator+(const Expression &lhs, const NumberType &rhs) + { + return lhs + Expression(rhs); + } + + /** + * General subtraction operator. + * + * Return the result of subtracting the @p rhs from the @p lhs. + * The @p lhs type may be any supported number type, and the result + * is promoted to a Expression. The type conversion makes writing + * scalar expressions using Expression more natural. + */ + template ::value>::type> + inline Expression + operator-(const NumberType &lhs, const Expression &rhs) + { + return Expression(lhs) - rhs; + } + + /** + * General subtraction operator. + * + * Return the result of subtracting the @p rhs from the @p lhs. + * The @p rhs type may be any supported number type, and the result + * is promoted to a Expression. The type conversion makes writing + * scalar expressions using Expression more natural. + */ + template ::value>::type> + inline Expression + operator-(const Expression &lhs, const NumberType &rhs) + { + return lhs - Expression(rhs); + } + + /** + * General multiplication operator. + * + * Return the result of multiplying the @p lhs by the @p rhs. + * The @p lhs type may be any supported number type, and the result + * is promoted to a Expression. The type conversion makes writing + * scalar expressions using Expression more natural. + */ + template ::value>::type> + inline Expression operator*(const NumberType &lhs, const Expression &rhs) + { + return Expression(lhs) * rhs; + } + + /** + * General multiplication operator. + * + * Return the result of multiplying the @p lhs by the @p rhs. + * The @p rhs type may be any supported number type, and the result + * is promoted to a Expression. The type conversion makes writing + * scalar expressions using Expression more natural. + */ + template ::value>::type> + inline Expression operator*(const Expression &lhs, const NumberType &rhs) + { + return lhs * Expression(rhs); + } + + /** + * General division operator. + * + * Return the result of dividing the @p lhs by the @p rhs. + * The @p lhs type may be any supported number type, and the result + * is promoted to a Expression. The type conversion makes writing + * scalar expressions using Expression more natural. + */ + template ::value>::type> + inline Expression + operator/(const NumberType &lhs, const Expression &rhs) + { + return Expression(lhs) / rhs; + } + + /** + * General division operator. + * + * Return the result of dividing the @p lhs by the @p rhs. + * The @p lhs type may be any supported number type, and the result + * is promoted to a Expression. The type conversion makes writing + * scalar expressions using Expression more natural. + */ + template ::value>::type> + inline Expression + operator/(const Expression &lhs, const NumberType &rhs) + { + return lhs / Expression(rhs); + } + + //@} + + } // namespace SD +} // namespace Differentiation + + +/* ---------------------- inline and template functions -------------------- */ + + +# ifndef DOXYGEN + + +namespace Differentiation +{ + namespace SD + { + template + Expression::Expression(const NumberType &value) + : expression(value) + {} + + + template + Expression::Expression(const std::complex &value) + : expression(value) + {} + + + template + Expression::Expression(const NumberType &numerator, + const NumberType &denominator) + : expression(SE::Rational::from_two_ints(*SE::integer(numerator), + *SE::integer(denominator))) + {} + + + template + void + Expression::serialize(Archive &ar, const unsigned int /*version*/) + { + // This is a bit tricky... The SymEngine expression class is not + // serializable, and we're not sure if we're writing out or + // reading in here. So what we'll do is try to synchronise the + // current data with the stream, predicting if we're likely trying + // to write out data. We do this by checking if we're currently working + // with an object that has a trivial state. If not, then we're likely + // to output this object's contents. + const Expression default_constructed; + const bool likely_writing_out = + (get_RCP()->__eq__(*default_constructed.get_RCP()) == false); + + std::stringstream sstream; + std::string expr = default_constructed.get_RCP()->__str__(); + + // Output + if (likely_writing_out) + { + sstream << *this; + expr = sstream.str(); + } + + // Serialise + ar &expr; + + // Input + if (!likely_writing_out) + { + sstream.clear(); + sstream << expr; + sstream >> *this; + + parse(expr); + } + } + + + template + Expression + Expression::substitute(const Expression &symbol, + const NumberType &value) const + { + Assert(SE::is_a(symbol.get_value()), + ExcMessage( + "Substitution with a number that does not represent a symbol.")); + + types::substitution_map sub_vals; + sub_vals[symbol] = Expression(value); + return substitute(sub_vals); + } + + + template + ReturnType + Expression::substitute_and_evaluate( + const types::substitution_map &substitution_values) const + { + return static_cast(substitute(substitution_values)); + } + + + template + Expression & + Expression::operator=(const NumberType &rhs) + { + *this = Expression(rhs); + return *this; + } + + + template + Expression & + Expression::operator+=(const NumberType &rhs) + { + *this = Expression(SE::add(get_RCP(), Expression(rhs).get_RCP())); + return *this; + } + + + template + Expression & + Expression::operator-=(const NumberType &rhs) + { + *this = Expression(SE::sub(get_RCP(), Expression(rhs).get_RCP())); + return *this; + } + + + template + Expression & + Expression::operator*=(const NumberType &rhs) + { + *this = Expression(SE::mul(get_RCP(), Expression(rhs).get_RCP())); + return *this; + } + + + template + Expression & + Expression::operator/=(const NumberType &rhs) + { + *this = Expression(SE::div(get_RCP(), Expression(rhs).get_RCP())); + return *this; + } + + + template + Expression::operator ResultType() const + { + return static_cast(get_expression()); + } + + } // namespace SD +} // namespace Differentiation + + +DEAL_II_NAMESPACE_CLOSE + + +# endif // DOXYGEN + +#endif // DEAL_II_WITH_SYMENGINE + +#endif // dealii_differentiation_sd_symengine_number_types_h diff --git a/include/deal.II/differentiation/sd/symengine_types.h b/include/deal.II/differentiation/sd/symengine_types.h new file mode 100644 index 000000000000..1f493c007c53 --- /dev/null +++ b/include/deal.II/differentiation/sd/symengine_types.h @@ -0,0 +1,81 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_differentiation_sd_symengine_types_h +#define dealii_differentiation_sd_symengine_types_h + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + // Forward declarations + class Expression; + + + namespace types + { + namespace internal + { + /** + * A comparator for Expressions used as keys in maps. + */ + struct ExpressionKeyLess + { + bool + operator()(const SD::Expression &lhs, + const SD::Expression &rhs) const; + }; + } // namespace internal + + /** + * Type definition for a value substitution map. + * + * This serves the same purpose as a + * SymEngine::map_basic_basic, which is equivalent to a + * std::map, SE::RCP>. + */ + using substitution_map = + std::map; + + /** + * Type definition for a vector of symbols. + * + * This serves the same purpose as a SymEngine::vec_basic, + * which is equivalent to a std::vector> + */ + using symbol_vector = std::vector; + + } // namespace types + + } // namespace SD +} // namespace Differentiation + + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE + +#endif // dealii_differentiation_sd_symengine_types_h diff --git a/include/deal.II/differentiation/sd/symengine_utilities.h b/include/deal.II/differentiation/sd/symengine_utilities.h new file mode 100644 index 000000000000..e9f64c57162d --- /dev/null +++ b/include/deal.II/differentiation/sd/symengine_utilities.h @@ -0,0 +1,62 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_differentiation_sd_symengine_utilities_h +#define dealii_differentiation_sd_symengine_utilities_h + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include + +# include +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + namespace SE = ::SymEngine; + + namespace Utilities + { + /** + * Convert a map of Expressions to its SymEngine counterpart. + */ + SE::map_basic_basic + convert_expression_map_to_basic_map( + const SD::types::substitution_map &substitution_map); + + /** + * Convert a vector of Expressions to its SymEngine counterpart. + */ + SE::vec_basic + convert_expression_vector_to_basic_vector( + const SD::types::symbol_vector &symbol_vector); + + } // namespace Utilities + + } // namespace SD +} // namespace Differentiation + + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE + +#endif // dealii_differentiation_sd_symengine_utilities_h diff --git a/source/differentiation/CMakeLists.txt b/source/differentiation/CMakeLists.txt index 28015cc9d5a7..3d27c72a33e4 100644 --- a/source/differentiation/CMakeLists.txt +++ b/source/differentiation/CMakeLists.txt @@ -1,6 +1,6 @@ ## --------------------------------------------------------------------- ## -## Copyright (C) 2017 by the deal.II authors +## Copyright (C) 2017-2019 by the deal.II authors ## ## This file is part of the deal.II library. ## @@ -14,3 +14,4 @@ ## --------------------------------------------------------------------- ADD_SUBDIRECTORY(ad) +ADD_SUBDIRECTORY(sd) diff --git a/source/differentiation/sd/CMakeLists.txt b/source/differentiation/sd/CMakeLists.txt new file mode 100644 index 000000000000..f6730585d816 --- /dev/null +++ b/source/differentiation/sd/CMakeLists.txt @@ -0,0 +1,32 @@ +## --------------------------------------------------------------------- +## +## Copyright (C) 2017 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. +## +## --------------------------------------------------------------------- + +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) + +SET(_src + symengine_number_types.cc + symengine_types.cc + symengine_utilities.cc + ) + +SET(_inst + ) + +FILE(GLOB _header + ${CMAKE_SOURCE_DIR}/include/deal.II/differentiation/sd/*.h + ) + +DEAL_II_ADD_LIBRARY(obj_differentiation_sd OBJECT ${_src} ${_header} ${_inst}) +EXPAND_INSTANTIATIONS(obj_differentiation_sd "${_inst}") diff --git a/source/differentiation/sd/symengine_number_types.cc b/source/differentiation/sd/symengine_number_types.cc new file mode 100644 index 000000000000..fce494713b54 --- /dev/null +++ b/source/differentiation/sd/symengine_number_types.cc @@ -0,0 +1,541 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include + +# include +# include +# include + +# include +# include +# include +# include +# include +# include +# include + +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + namespace SE = ::SymEngine; + + + /* ---------------------------- Constructors -------------------------- */ + + + Expression::Expression() + : expression() + {} + + + Expression::Expression(const bool &value) + : expression(SE::boolean(value)) + {} + + + Expression::Expression(const SE::integer_class &value) + : expression(value) + {} + + + Expression::Expression(const SE::rational_class &value) + : expression(value) + {} + + + Expression::Expression(const Expression &condition, + const Expression &expression_if_true, + const Expression &expression_if_false) + { + Assert(SE::is_a_Boolean(condition.get_value()), + ExcMessage( + "The conditional expression must return a boolean type.")); + + const SE::RCP condition_rcp = + SE::rcp_static_cast(condition.get_RCP()); + expression = + SE::piecewise({{expression_if_true.get_RCP(), condition_rcp}, + {expression_if_false.get_RCP(), SE::boolTrue}}); + } + + + Expression::Expression(const std::vector> + & condition_expression, + const Expression &expression_otherwise) + { + SE::PiecewiseVec piecewise_function; + piecewise_function.reserve(condition_expression.size() + 1); + + // Add tested conditional entries + for (const auto &entry : condition_expression) + { + Assert(SE::is_a_Boolean(entry.first.get_value()), + ExcMessage( + "The conditional expression must return a boolean type.")); + piecewise_function.push_back( + {entry.second.get_RCP(), + SE::rcp_static_cast(entry.first.get_RCP())}); + } + + // Add default value + piecewise_function.push_back( + {expression_otherwise.get_RCP(), SE::boolTrue}); + + // Initialize + expression = SE::piecewise(std::move(piecewise_function)); + } + + + Expression::Expression(const std::vector> + &condition_expression) + { + // Use the other constructor with a fatal termination point + // ensuring that an error is thrown if none of the conditions + // are met. + *this = Expression(condition_expression, + Expression(numbers::signaling_nan())); + } + + + Expression::Expression(const char *symbol) + : expression(SE::symbol(symbol)) + {} + + + Expression::Expression(const std::string &str, + const bool parse_as_expression) + { + try + { + expression = (parse_as_expression ? + SE::parse(str) // The string is a symbolic "name" + : + SE::rcp_static_cast(SE::symbol( + str))); // The string is a symbolic "expression" + } + catch (...) + { + AssertThrow(false, ExcSymEngineParserError(str)); + } + } + + + Expression::Expression(const std::string & symbol_func, + const types::symbol_vector &arguments) + : expression(SE::function_symbol( + symbol_func, + Utilities::convert_expression_vector_to_basic_vector(arguments))) + {} + + + Expression::Expression(const SE::Expression &rhs) + : expression(rhs) + {} + + + Expression::Expression(const SE::RCP &rhs) + : expression(rhs) + {} + + + Expression::Expression(SE::RCP &&rhs) + : expression(rhs) + {} + + + /* ------------------------------ Utilities ---------------------------- */ + + + Expression & + Expression::parse(const std::string &expression) + { + *this = Expression(expression, true /*parse_as_expression*/); + return *this; + } + + + std::ostream & + Expression::print(std::ostream &os) const + { + os << *this; + return os; + } + + + void + Expression::save(std::ostream &os) const + { + // We write each expression on a new line. + // Note: SymEngine outputs a non-terminating string + os << *this; + os << std::endl; + } + + + void + Expression::load(std::istream &is) + { + // Need to make sure that we read the entire line in, + // and then subsequently parse it. + std::string expr; + std::getline(is, expr); + Assert(!is.bad(), ExcIO()); + parse(expr); + } + + + /* ------------------------------- Values ----------------------------- */ + + + const SE::Expression & + Expression::get_expression() const + { + return expression; + } + + + SE::Expression & + Expression::get_expression() + { + return expression; + } + + + const SE::Basic & + Expression::get_value() const + { + return *get_RCP(); + } + + + const SE::RCP & + Expression::get_RCP() const + { + return get_expression().get_basic(); + } + + + /* --------------------------- Differentiation ------------------------- */ + + + Expression + Expression::differentiate(const SE::RCP &symbol) const + { + return Expression(SE::diff(get_RCP(), symbol)); + } + + + Expression + Expression::differentiate(const SE::RCP &symbol) const + { + // Potential symbol + return Expression(SE::sdiff(get_RCP(), symbol)); + } + + + Expression + Expression::differentiate(const Expression &symbol) const + { + return differentiate(symbol.get_RCP()); + } + + + /* ------------- Conversion operators ------------------------- */ + + + Expression::operator const SE::Expression &() const + { + return get_expression(); + } + + + Expression::operator const SE::RCP &() const + { + return get_expression().get_basic(); + } + + + /* ------------- Dictionary-based substitution ------------------------- */ + + + Expression + Expression::substitute( + const types::substitution_map &substitution_values) const + { + return Expression(get_expression().subs( + Utilities::convert_expression_map_to_basic_map(substitution_values))); + } + + + Expression + Expression::substitute(const Expression &symbol, + const Expression &value) const + { + Assert(SE::is_a(symbol.get_value()), + ExcMessage( + "Substitution with a number that does not represent a symbol.")); + + types::substitution_map sub_vals; + sub_vals[symbol] = value; + return substitute(sub_vals); + } + + + /* -------------------- Math and relational operators ------------------ */ + + + Expression & + Expression::operator=(const Expression &rhs) + { + if (this != &rhs) + this->expression = rhs.get_expression(); + + return *this; + } + + + Expression & + Expression::operator=(Expression &&rhs) + { + if (this != &rhs) + this->expression = std::move(rhs.expression); + + return *this; + } + + + Expression + Expression::operator-() const + { + return Expression(-get_expression()); + } + + + Expression & + Expression::operator+=(const Expression &rhs) + { + this->expression += rhs.get_expression(); + return *this; + } + + + Expression & + Expression::operator-=(const Expression &rhs) + { + this->expression -= rhs.get_expression(); + return *this; + } + + + Expression & + Expression::operator*=(const Expression &rhs) + { + this->expression *= rhs.get_expression(); + return *this; + } + + + Expression & + Expression::operator/=(const Expression &rhs) + { + this->expression /= rhs.get_expression(); + return *this; + } + + + std::ostream & + operator<<(std::ostream &stream, const Expression &expr) + { + stream << expr.get_expression(); + return stream; + } + + + std::istream & + operator>>(std::istream &stream, Expression &expr) + { + std::string str; + stream >> str; + expr.parse(str); + return stream; + } + + + Expression + operator==(const Expression &lhs, const Expression &rhs) + { + return Expression(SE::Eq(lhs.get_RCP(), rhs.get_RCP())); + } + + + Expression + operator!=(const Expression &lhs, const Expression &rhs) + { + return Expression(SE::Ne(lhs.get_RCP(), rhs.get_RCP())); + } + + + Expression + operator<(const Expression &lhs, const Expression &rhs) + { + return Expression(SE::Lt(lhs.get_RCP(), rhs.get_RCP())); + } + + + Expression + operator>(const Expression &lhs, const Expression &rhs) + { + return Expression(SE::Gt(lhs.get_RCP(), rhs.get_RCP())); + } + + + Expression + operator<=(const Expression &lhs, const Expression &rhs) + { + return Expression(SE::Le(lhs.get_RCP(), rhs.get_RCP())); + } + + + Expression + operator>=(const Expression &lhs, const Expression &rhs) + { + return Expression(SE::Ge(lhs.get_RCP(), rhs.get_RCP())); + } + + + Expression operator!(const Expression &expression) + { + Assert(SE::is_a_Boolean(expression.get_value()), + ExcMessage("The expression must return a boolean type.")); + + const SE::RCP expression_rcp = + SE::rcp_static_cast(expression.get_RCP()); + + return Expression(SE::logical_not(expression_rcp)); + } + + + Expression operator&(const Expression &lhs, const Expression &rhs) + { + Assert(SE::is_a_Boolean(lhs.get_value()), + ExcMessage("The lhs expression must return a boolean type.")); + Assert(SE::is_a_Boolean(rhs.get_value()), + ExcMessage("The rhs expression must return a boolean type.")); + + const SE::RCP lhs_rcp = + SE::rcp_static_cast(lhs.get_RCP()); + const SE::RCP rhs_rcp = + SE::rcp_static_cast(rhs.get_RCP()); + + return Expression(SE::logical_and({lhs_rcp, rhs_rcp})); + } + + + Expression + operator|(const Expression &lhs, const Expression &rhs) + { + Assert(SE::is_a_Boolean(lhs.get_value()), + ExcMessage("The lhs expression must return a boolean type.")); + Assert(SE::is_a_Boolean(rhs.get_value()), + ExcMessage("The rhs expression must return a boolean type.")); + + const SE::RCP lhs_rcp = + SE::rcp_static_cast(lhs.get_RCP()); + const SE::RCP rhs_rcp = + SE::rcp_static_cast(rhs.get_RCP()); + + return Expression(SE::logical_or({lhs_rcp, rhs_rcp})); + } + + + Expression + operator^(const Expression &lhs, const Expression &rhs) + { + Assert(SE::is_a_Boolean(lhs.get_value()), + ExcMessage("The lhs expression must return a boolean type.")); + Assert(SE::is_a_Boolean(rhs.get_value()), + ExcMessage("The rhs expression must return a boolean type.")); + + const SE::RCP lhs_rcp = + SE::rcp_static_cast(lhs.get_RCP()); + const SE::RCP rhs_rcp = + SE::rcp_static_cast(rhs.get_RCP()); + + return Expression(SE::logical_xor({lhs_rcp, rhs_rcp})); + } + + + Expression + operator&&(const Expression &lhs, const Expression &rhs) + { + return lhs & rhs; + } + + + Expression + operator||(const Expression &lhs, const Expression &rhs) + { + return lhs | rhs; + } + + + Expression + operator+(Expression lhs, const Expression &rhs) + { + lhs += rhs; + return lhs; + } + + + Expression + operator-(Expression lhs, const Expression &rhs) + { + lhs -= rhs; + return lhs; + } + + + Expression operator*(Expression lhs, const Expression &rhs) + { + lhs *= rhs; + return lhs; + } + + + Expression + operator/(Expression lhs, const Expression &rhs) + { + lhs /= rhs; + return lhs; + } + + + } // namespace SD +} // namespace Differentiation + + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE diff --git a/source/differentiation/sd/symengine_types.cc b/source/differentiation/sd/symengine_types.cc new file mode 100644 index 000000000000..4c628ae23845 --- /dev/null +++ b/source/differentiation/sd/symengine_types.cc @@ -0,0 +1,55 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include +# include + +# include +# include + + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + namespace SE = ::SymEngine; + + namespace types + { + namespace internal + { + bool + ExpressionKeyLess::operator()(const SD::Expression &lhs, + const SD::Expression &rhs) const + { + return SE::RCPBasicKeyLess()(lhs.get_RCP(), rhs.get_RCP()); + } + } // namespace internal + + } // namespace types + + } // namespace SD +} // namespace Differentiation + + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE diff --git a/source/differentiation/sd/symengine_utilities.cc b/source/differentiation/sd/symengine_utilities.cc new file mode 100644 index 000000000000..9697316831f8 --- /dev/null +++ b/source/differentiation/sd/symengine_utilities.cc @@ -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. +// +// --------------------------------------------------------------------- + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + namespace SE = ::SymEngine; + + namespace Utilities + { + SE::map_basic_basic + convert_expression_map_to_basic_map( + const SD::types::substitution_map &substitution_map) + { + SE::map_basic_basic sub_map; + for (const auto &entry : substitution_map) + sub_map[entry.first.get_RCP()] = entry.second.get_RCP(); + return sub_map; + } + + + SE::vec_basic + convert_expression_vector_to_basic_vector( + const SD::types::symbol_vector &symbol_vector) + { + SE::vec_basic symb_vec; + symb_vec.reserve(symbol_vector.size()); + for (const auto &entry : symbol_vector) + symb_vec.push_back(entry.get_RCP()); + return symb_vec; + } + + } // namespace Utilities + + } // namespace SD +} // namespace Differentiation + + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE From a9082f47c2c04ade424cacca685fbb2569fb50b7 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sat, 30 Mar 2019 11:20:34 +0100 Subject: [PATCH 362/507] Add test for SD::Expression class --- tests/symengine/symengine_number_type_01.cc | 1142 +++++++++++++++++ .../symengine/symengine_number_type_01.output | 17 + 2 files changed, 1159 insertions(+) create mode 100644 tests/symengine/symengine_number_type_01.cc create mode 100644 tests/symengine/symengine_number_type_01.output diff --git a/tests/symengine/symengine_number_type_01.cc b/tests/symengine/symengine_number_type_01.cc new file mode 100644 index 000000000000..4b26361e1f57 --- /dev/null +++ b/tests/symengine/symengine_number_type_01.cc @@ -0,0 +1,1142 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Check that the wrapper for symengine expressions works as expected + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../serialization/serialization.h" +#include "../tests.h" + +using namespace dealii; +namespace SD = Differentiation::SD; +namespace SE = ::SymEngine; + + +// Overload the comparison function in serialization.h +template <> +bool +compare(const SD::Expression &t1, const SD::Expression &t2) +{ + // Could also do the following if it ever becomes necessary: + // (t1.get_value().__cmp__(t2.get_value()) == 0) + return t1.get_expression() == t2.get_expression(); +} + + +int +main() +{ + initlog(); + + using SD_number_t = SD::Expression; + + deallog << "Constructors" << std::endl; + { + std::cout << "Constructor: Boolean" << std::endl; + { + const SD_number_t se_bool_true(true); + const SD_number_t se_bool_false(false); + Assert(SE::eq(se_bool_true.get_value(), *SE::boolTrue), + ExcMessage("Problem with constructor")); + Assert(SE::eq(se_bool_false.get_value(), *SE::boolFalse), + ExcMessage("Problem with constructor")); + } + + std::cout << "Constructor: Integer" << std::endl; + { + const int x = -1; + const SD_number_t se_number(x); + Assert(SE::eq(se_number.get_value(), *SE::integer(x)), + ExcMessage("Problem with constructor")); + } + + std::cout << "Constructor: Unsigned integer" << std::endl; + { + const unsigned int x = 2; + const SD_number_t se_number(x); + Assert(SE::eq(se_number.get_value(), *SE::integer(x)), + ExcMessage("Problem with constructor")); + } + + std::cout << "Constructor: Rational" << std::endl; + { + const unsigned int x = 2; + const unsigned int y = 3; + const SD_number_t se_number(x, y); + Assert(SE::eq(se_number.get_value(), *SE::rational(x, y)), + ExcMessage("Problem with constructor")); + } + + std::cout << "Constructor: Double" << std::endl; + { + const double x = 2.5; + const SD_number_t se_number(x); + Assert(SE::eq(se_number.get_value(), *SE::real_double(x)), + ExcMessage("Problem with constructor")); + } + + std::cout << "Constructor: Complex double" << std::endl; + { + const std::complex x(2.5, 1.5); + const SD_number_t se_number(x); + Assert(SE::eq(se_number.get_value(), *SE::complex_double(x)), + ExcMessage("Problem with constructor")); + } + + std::cout << "Constructor: Float" << std::endl; + { + const float x = 2.5; + const SD_number_t se_number(x); + Assert(SE::eq(se_number.get_value(), *SE::real_double(x)), + ExcMessage("Problem with constructor")); + } + + std::cout << "Constructor: Complex float" << std::endl; + { + const std::complex x(2.5, 1.5); + const SD_number_t se_number(x); + Assert(SE::eq(se_number.get_value(), *SE::complex_double(x)), + ExcMessage("Problem with constructor")); + } + + std::cout << "Constructor: Symbol" << std::endl; + { + const std::string f = "f"; + const bool parse_as_expression = false; + const SD_number_t se_number(f, parse_as_expression); + Assert(SE::eq(se_number.get_value(), *SE::symbol(f)), + ExcMessage("Problem with constructor")); + } + + std::cout << "Constructor: Symbol" << std::endl; + { + const std::string f = "func"; + const SD_number_t se_number(f.c_str()); + Assert(SE::eq(se_number.get_value(), *SE::symbol(f)), + ExcMessage("Problem with constructor")); + } + + std::cout << "Constructor: Symbol" << std::endl; + { + const std::string f = "func"; + const bool parse_as_expression = false; + const SD_number_t se_number(f, parse_as_expression); + Assert(SE::eq(se_number.get_value(), *SE::symbol(f)), + ExcMessage("Problem with constructor")); + } + + std::cout << "Constructor: Symbolic expression" << std::endl; + { + const std::string f = "x + y"; + const bool parse_as_expression = true; + const SD_number_t se_number(f, parse_as_expression); + Assert(SE::eq(se_number.get_value(), *SE::parse(f)), + ExcMessage("Problem with constructor")); + } + + std::cout << "Copy constructor" << std::endl; + { + const double x = 2.5; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(se_number_1); + Assert(SE::eq(se_number_2.get_value(), *SE::real_double(x)), + ExcMessage("Problem with constructor")); + } + } + + deallog << "Utility functions" << std::endl; + { + std::cout << "Parse" << std::endl; + { + const double x = 2.5; + SD_number_t se_number(x); + const std::string f = "x + y"; + se_number.parse(f); + Assert(SE::eq(se_number.get_value(), *SE::parse(f)), + ExcMessage("Problem with utility function: Parse")); + } + + std::cout << "Save/load" << std::endl; + { + // Output + const SD_number_t se_number_x_out("x"); + const SD_number_t se_number_y_out("y"); + const SD_number_t se_number_f_out("x + y + 2.5", + true /*parse_as_expression*/); + { + std::ofstream o_str("save_load.txt"); + Assert(o_str.is_open(), ExcInternalError()); + se_number_x_out.save(o_str); + se_number_y_out.save(o_str); + se_number_f_out.save(o_str); + o_str.close(); + } + + // Input + SD_number_t se_number_x_in; + SD_number_t se_number_y_in; + SD_number_t se_number_f_in; + { + std::ifstream i_str("save_load.txt"); + Assert(i_str.is_open(), ExcInternalError()); + se_number_x_in.load(i_str); + se_number_y_in.load(i_str); + se_number_f_in.load(i_str); + } + + Assert(static_cast(se_number_x_in == se_number_x_out), + ExcMessage("Problem with utility function: Save/load")); + Assert(static_cast(se_number_y_in == se_number_y_out), + ExcMessage("Problem with utility function: Save/load")); + Assert(static_cast(se_number_f_in == se_number_f_out), + ExcMessage("Problem with utility function: Save/load")); + } + + deallog.push("Serialization"); + std::cout << "Serialization" << std::endl; + { + const SD_number_t se_number_x_out("x"); + const SD_number_t se_number_y_out("y"); + const SD_number_t se_number_f_out("x + y + 2.5", + true /*parse_as_expression*/); + + // From serialization.h + SD_number_t se_number_x_in; + SD_number_t se_number_y_in; + SD_number_t se_number_f_in; + verify(se_number_x_out, se_number_x_in); + verify(se_number_y_out, se_number_y_in); + verify(se_number_f_out, se_number_f_in); + + Assert(static_cast(se_number_x_in == se_number_x_out), + ExcMessage("Problem with utility function: Serialization")); + Assert(static_cast(se_number_y_in == se_number_y_out), + ExcMessage("Problem with utility function: Serialization")); + Assert(static_cast(se_number_f_in == se_number_f_out), + ExcMessage("Problem with utility function: Serialization")); + } + deallog.pop(); + } + + deallog << "Comparison operators" << std::endl; + { + std::cout << "Equality (true)" << std::endl; + { + const int x = 2; + const int y = 2; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 == se_number_2) == true, + ExcMessage("Problem with comparison operator")); + } + + std::cout << "Equality (false)" << std::endl; + { + const int x = 2; + const int y = 3; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 == se_number_2) == false, + ExcMessage("Problem with comparison operator")); + } + + std::cout << "Non-equality (true)" << std::endl; + { + const int x = 2; + const int y = 3; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 != se_number_2) == true, + ExcMessage("Problem with comparison operator")); + } + + std::cout << "Non-equality (false)" << std::endl; + { + const int x = 2; + const int y = 2; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 != se_number_2) == false, + ExcMessage("Problem with comparison operator")); + } + + std::cout << "Less-than operator (true)" << std::endl; + { + const int x = 2; + const int y = 3; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 < se_number_2) == true, + ExcMessage("Problem with comparison operator")); + } + + std::cout << "Less-than operator (false)" << std::endl; + { + const int x = 3; + const int y = 2; + const int z = 3; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + const SD_number_t se_number_3(z); + Assert(static_cast(se_number_1 < se_number_2) == false, + ExcMessage("Problem with comparison operator")); + Assert(static_cast(se_number_1 < se_number_3) == false, + ExcMessage("Problem with comparison operator")); + } + + std::cout << "Less-than-or-equals operator (true)" << std::endl; + { + const int x = 2; + const int y = 3; + const int z = 2; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + const SD_number_t se_number_3(z); + Assert(static_cast(se_number_1 <= se_number_2) == true, + ExcMessage("Problem with comparison operator")); + Assert(static_cast(se_number_1 <= se_number_3) == true, + ExcMessage("Problem with comparison operator")); + } + + std::cout << "Less-than-or-equals operator (false)" << std::endl; + { + const int x = 3; + const int y = 2; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 <= se_number_2) == false, + ExcMessage("Problem with comparison operator")); + } + + std::cout << "Greater-than operator (true)" << std::endl; + { + const int x = 3; + const int y = 2; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 > se_number_2) == true, + ExcMessage("Problem with comparison operator")); + } + + std::cout << "Greater-than operator (false)" << std::endl; + { + const int x = 2; + const int y = 3; + const int z = 2; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + const SD_number_t se_number_3(z); + Assert(static_cast(se_number_1 > se_number_2) == false, + ExcMessage("Problem with comparison operator")); + Assert(static_cast(se_number_1 > se_number_3) == false, + ExcMessage("Problem with comparison operator")); + } + + std::cout << "Greater-than-or-equals operator (true)" << std::endl; + { + const int x = 3; + const int y = 2; + const int z = 3; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + const SD_number_t se_number_3(z); + Assert(static_cast(se_number_1 >= se_number_2) == true, + ExcMessage("Problem with comparison operator")); + Assert(static_cast(se_number_1 >= se_number_3) == true, + ExcMessage("Problem with comparison operator")); + } + + std::cout << "Greater-than-or-equals operator (false)" << std::endl; + { + const int x = 2; + const int y = 3; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 >= se_number_2) == false, + ExcMessage("Problem with comparison operator")); + } + } + + deallog << "Logical operators" << std::endl; + { + std::cout << "Logical not" << std::endl; + { + const bool x = true; + const SD_number_t se_number(x); + Assert(static_cast(!se_number) == (!x), + ExcMessage("Problem with logical operator")); + Assert(static_cast(!!se_number) == (!!x), + ExcMessage("Problem with logical operator")); + } + + std::cout << "Logical and" << std::endl; + { + auto test_logical_op = [](const bool x, const bool y) { + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 & se_number_2) == (x & y), + ExcMessage("Problem with logical operator")); + }; + + test_logical_op(true, true); + test_logical_op(true, false); + test_logical_op(false, true); + test_logical_op(false, false); + } + + std::cout << "Logical inclusive or" << std::endl; + { + auto test_logical_op = [](const bool x, const bool y) { + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 | se_number_2) == (x | y), + ExcMessage("Problem with logical operator")); + }; + + test_logical_op(true, true); + test_logical_op(true, false); + test_logical_op(false, true); + test_logical_op(false, false); + } + + std::cout << "Logical xor" << std::endl; + { + auto test_logical_op = [](const bool x, const bool y) { + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 ^ se_number_2) == (x ^ y), + ExcMessage("Problem with logical operator")); + }; + + test_logical_op(true, true); + test_logical_op(true, false); + test_logical_op(false, true); + test_logical_op(false, false); + } + + std::cout << "And" << std::endl; + { + auto test_logical_op = [](const bool x, const bool y) { + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 && se_number_2) == (x && y), + ExcMessage("Problem with logical operator")); + }; + + test_logical_op(true, true); + test_logical_op(true, false); + test_logical_op(false, true); + test_logical_op(false, false); + } + + std::cout << "Inclusive or" << std::endl; + { + auto test_logical_op = [](const bool x, const bool y) { + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + Assert(static_cast(se_number_1 || se_number_2) == (x || y), + ExcMessage("Problem with logical operator")); + }; + + test_logical_op(true, true); + test_logical_op(true, false); + test_logical_op(false, true); + test_logical_op(false, false); + } + } + + deallog << "Assignment operators" << std::endl; + { + std::cout << "Assignment operator (SD_number_t)" << std::endl; + { + const int x = 1; + const int y = 2; + SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + se_number_1 = se_number_2; + Assert(SE::eq(se_number_1.get_value(), *SE::integer(y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Assignment operator (arithmetic type)" << std::endl; + { + const int x = 1; + const double y = 2; + SD_number_t se_number(x); + se_number = y; + Assert(SE::eq(se_number.get_value(), *SE::real_double(y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Addition assignment (SD_number_t)" << std::endl; + { + const int x = 1; + const int y = 2; + SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + se_number_1 += se_number_2; + Assert(SE::eq(se_number_1.get_value(), *SE::integer(x + y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Addition assignment (arithmetic type; same type)" + << std::endl; + { + const int x = 1; + const int y = 2; + SD_number_t se_number(x); + se_number += y; + Assert(SE::eq(se_number.get_value(), *SE::integer(x + y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Addition assignment (arithmetic type; different type)" + << std::endl; + { + const int x = 1; + const double y = 2; + SD_number_t se_number(x); + se_number += y; + Assert(SE::eq(se_number.get_value(), *SE::real_double(x + y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Subtraction assignment (SD_number_t)" << std::endl; + { + const int x = 1; + const int y = 2; + SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + se_number_1 -= se_number_2; + Assert(SE::eq(se_number_1.get_value(), *SE::integer(x - y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Subtraction assignment (arithmetic type; same type)" + << std::endl; + { + const int x = 1; + const int y = 2; + SD_number_t se_number(x); + se_number -= y; + Assert(SE::eq(se_number.get_value(), *SE::integer(x - y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Subtraction assignment (arithmetic type; different type)" + << std::endl; + { + const int x = 1; + const double y = 2; + SD_number_t se_number(x); + se_number -= y; + Assert(SE::eq(se_number.get_value(), *SE::real_double(x - y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Multiplication assignment (SD_number_t)" << std::endl; + { + const int x = 2; + const int y = 3; + SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + se_number_1 *= se_number_2; + Assert(SE::eq(se_number_1.get_value(), *SE::integer(x * y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Multiplication assignment (arithmetic type; same type)" + << std::endl; + { + const int x = 2; + const int y = 3; + SD_number_t se_number(x); + se_number *= y; + Assert(SE::eq(se_number.get_value(), *SE::integer(x * y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Multiplication assignment (arithmetic type; different type)" + << std::endl; + { + const int x = 2; + const double y = 3; + SD_number_t se_number(x); + se_number *= y; + Assert(SE::eq(se_number.get_value(), *SE::real_double(x * y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Division assignment (SD_number_t)" << std::endl; + { + const int x = 8; + const int y = 2; + SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + se_number_1 /= se_number_2; + Assert(SE::eq(se_number_1.get_value(), *SE::integer(x / y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Division assignment (arithmetic type; same type)" + << std::endl; + { + const int x = 8; + const int y = 2; + SD_number_t se_number(x); + se_number /= y; + Assert(SE::eq(se_number.get_value(), *SE::integer(x / y)), + ExcMessage("Problem with assignment operator")); + } + + std::cout << "Division assignment (arithmetic type; different type)" + << std::endl; + { + const int x = 8; + const double y = 2; + SD_number_t se_number(x); + se_number /= y; + Assert(SE::eq(se_number.get_value(), *SE::real_double(x / y)), + ExcMessage("Problem with assignment operator")); + } + } + + deallog << "Math operators" << std::endl; + { + std::cout << "Addition" << std::endl; + { + const int x = 1; + const int y = 2; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + const SD_number_t se_number_3 = se_number_1 + se_number_2; + Assert(SE::eq(se_number_3.get_value(), *SE::integer(x + y)), + ExcMessage("Problem with math operator")); + } + + std::cout << "Subtraction" << std::endl; + { + const int x = 1; + const int y = 2; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + const SD_number_t se_number_3 = se_number_1 - se_number_2; + Assert(SE::eq(se_number_3.get_value(), *SE::integer(x - y)), + ExcMessage("Problem with math operator")); + } + + std::cout << "Multiplication" << std::endl; + { + const int x = 2; + const int y = 3; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + const SD_number_t se_number_3 = se_number_1 * se_number_2; + Assert(SE::eq(se_number_3.get_value(), *SE::integer(x * y)), + ExcMessage("Problem with math operator")); + } + + std::cout << "Division" << std::endl; + { + const int x = 8; + const int y = 2; + const SD_number_t se_number_1(x); + const SD_number_t se_number_2(y); + const SD_number_t se_number_3 = se_number_1 / se_number_2; + Assert(SE::eq(se_number_3.get_value(), *SE::integer(x / y)), + ExcMessage("Problem with math operator")); + } + } + + deallog << "Differentiation" << std::endl; + { + std::cout << "Basic differentiation (SD_number_t)" << std::endl; + { + const SD_number_t x("x"); + SD_number_t f(1.0); + f *= x; + f *= x; // f = x^2 + const SD_number_t df_dx = f.differentiate(x); + Assert(static_cast(df_dx == (2.0 * x)), + ExcMessage("Problem with differentiaton")); + } + + std::cout << "Basic differentiation (Symbol)" << std::endl; + { + const auto symb_x = SE::symbol("x"); + const SD_number_t x(symb_x); + SD_number_t f(1.0); + f *= x; + f *= x; // f = x^2 + const SD_number_t df_dx = f.differentiate(symb_x); + Assert(static_cast(df_dx == SD_number_t(2.0 * x)), + ExcMessage("Problem with differentiaton")); + } + + std::cout << "Basic differentiation (Basic representing a symbolic type)" + << std::endl; + { + const auto symb_x_plus_y = SE::add(SE::symbol("x"), SE::symbol("y")); + const SD_number_t x_plus_y(symb_x_plus_y); + SD_number_t f(1.0); + f *= x_plus_y; + f *= x_plus_y; // f = (x+y)^2 + const SD_number_t df_dxpy = f.differentiate(symb_x_plus_y); + Assert(static_cast(df_dxpy == (2.0 * SD_number_t(symb_x_plus_y))), + ExcMessage("Problem with differentiaton")); + } + } + + deallog << "Substitution" << std::endl; + { + std::cout << "Basic substitution" << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t f = x_plus_y * x_plus_y; + Assert(static_cast(f == SD_number_t("(x + y)**2", true)), + ExcMessage("Problem with substitution")); + + const double x_val = 1.0; + const SD_number_t f_sub_x = f.substitute(x, SD_number_t(x_val)); + Assert(static_cast(f_sub_x == SD_number_t("(1.0 + y)**2", true)), + ExcMessage("Problem with substitution")); + + const double y_val = 2.0; + const SD_number_t f_sub_xy = f_sub_x.substitute(y, SD_number_t(y_val)); + Assert(static_cast(f_sub_xy) == + (x_val * x_val + 2.0 * x_val * y_val + y_val * y_val), + ExcMessage("Problem with substitution")); + } + + std::cout << "Templated-deduced substitution" << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t f = x_plus_y * x_plus_y; + Assert(static_cast(f == SD_number_t("(x + y)**2", true)), + ExcMessage("Problem with substitution")); + + const double x_val = 1.0; + const SD_number_t f_sub_x = f.substitute(x, x_val); + Assert(static_cast(f_sub_x == SD_number_t("(1.0 + y)**2", true)), + ExcMessage("Problem with substitution")); + + const double y_val = 2.0; + const SD_number_t f_sub_xy = f_sub_x.substitute(y, y_val); + Assert(static_cast(f_sub_xy) == + (x_val * x_val + 2.0 * x_val * y_val + y_val * y_val), + ExcMessage("Problem with substitution")); + } + + std::cout << "Map substitution" << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t f = x_plus_y * x_plus_y; + + const double x_val = 1.0; + const double y_val = 2.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const SD_number_t f_sub_xy = f.substitute(sub_map); + Assert(static_cast(f_sub_xy) == + (x_val * x_val + 2.0 * x_val * y_val + y_val * y_val), + ExcMessage("Problem with substitution")); + } + } + + deallog << "Evaluation" << std::endl; + { + std::cout << "Substitution with evaluation (integer)" << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t f = x_plus_y * x_plus_y; + + const int x_val = 1; + const int y_val = 2; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const int f_val = f.substitute_and_evaluate(sub_map); + Assert(f_val == (x_val * x_val + 2 * x_val * y_val + y_val * y_val), + ExcMessage("Problem with evaluation")); + } + + std::cout << "Substitution with evaluation (double)" << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t f = x_plus_y * x_plus_y; + + const double x_val = 1.0; + const double y_val = 2.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const double f_val = f.substitute_and_evaluate(sub_map); + Assert(f_val == (x_val * x_val + 2.0 * x_val * y_val + y_val * y_val), + ExcMessage("Problem with evaluation")); + } + + std::cout << "Substitution with evaluation (float)" << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t f = x_plus_y * x_plus_y; + + const float x_val = 1.0; + const float y_val = 2.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const float f_val = f.substitute_and_evaluate(sub_map); + Assert(f_val == (x_val * x_val + 2.0f * x_val * y_val + y_val * y_val), + ExcMessage("Problem with evaluation")); + } + + std::cout << "Substitution with evaluation (complex double)" << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t f = x_plus_y * x_plus_y; + + const std::complex x_val(1.0, 3.0); + const std::complex y_val(2.0, -2.0); + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const std::complex f_val = + f.substitute_and_evaluate>(sub_map); + Assert(std::abs(f_val - (x_val * x_val + 2.0 * x_val * y_val + + y_val * y_val)) < 1e-12, + ExcMessage("Problem with evaluation")); + } + + std::cout << "Substitution with evaluation (complex float)" << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t f = x_plus_y * x_plus_y; + + const std::complex x_val(1.0, 3.0); + const std::complex y_val(2.0, -2.0); + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const std::complex f_val = + f.substitute_and_evaluate>(sub_map); + Assert(std::abs(f_val - (x_val * x_val + 2.0f * x_val * y_val + + y_val * y_val)) < 1e-12, + ExcMessage("Problem with evaluation")); + } + + std::cout << "Substitution with evaluation (mixed arithmetic types)" + << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t f = x_plus_y * x_plus_y; + + const int x_val = 1; + const int y_val = 2; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const double f_val = f.substitute_and_evaluate(sub_map); + Assert(f_val == static_cast(x_val * x_val + 2.0f * x_val * y_val + + y_val * y_val), + ExcMessage("Problem with evaluation")); + } + + std::cout << "Substitution with evaluation (mixed complex types)" + << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t f = x_plus_y * x_plus_y; + + const std::complex x_val(1.0, 3.0); + const std::complex y_val(2.0, -2.0); + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const std::complex f_val = + f.substitute_and_evaluate>(sub_map); + Assert(std::abs(f_val - static_cast>( + x_val * x_val + 2.0f * x_val * y_val + + y_val * y_val)) < 1e-12, + ExcMessage("Problem with evaluation")); + } + + std::cout << "Substitution with evaluation (single piecewise function)" + << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t x_minus_y = x - y; + const SD_number_t f_plus = x_plus_y * x_plus_y; + const SD_number_t f_minus = x_minus_y * x_minus_y; + const SD_number_t f((x > SD_number_t(0.0)), f_plus, f_minus); + + // Condition is met + { + const double x_val = 1.0; + const double y_val = 2.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const SD_number_t f_subs = f.substitute(sub_map); + const double f_val = static_cast(f_subs); + Assert(f_val == (x_val * x_val + 2.0 * x_val * y_val + y_val * y_val), + ExcMessage( + "Problem with evaluation of single piecewise function")); + } + + // Condition is not met + { + const double x_val = -1.0; + const double y_val = 2.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const double f_val = f.substitute_and_evaluate(sub_map); + Assert(f_val == (x_val * x_val - 2.0 * x_val * y_val + y_val * y_val), + ExcMessage( + "Problem with evaluation of single piecewise function")); + } + } + + std::cout << "Substitution with evaluation (double piecewise function)" + << std::endl; + { + const SD_number_t x("x"); + const SD_number_t y("y"); + const SD_number_t x_plus_y = x + y; + const SD_number_t x_minus_y = x - y; + const SD_number_t f_plus = x_plus_y * x_plus_y; + const SD_number_t f_plus_plus = 2.0 * x_plus_y * x_plus_y; + const SD_number_t f_minus = x_minus_y * x_minus_y; + const SD_number_t f((x > SD_number_t(0.0)), + SD_number_t(x > SD_number_t(2.0), + f_plus_plus, + f_plus), + f_minus); + + // Outer condition is met, inner condition is met + { + const double x_val = 3.0; + const double y_val = 2.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const SD_number_t f_subs = f.substitute(sub_map); + const double f_val = static_cast(f_subs); + Assert(f_val == (2.0 * x_val * x_val + 4.0 * x_val * y_val + + 2.0 * y_val * y_val), + ExcMessage( + "Problem with evaluation of double piecewise function")); + } + + // Outer condition is met, inner condition is not met + { + const double x_val = 1.0; + const double y_val = 2.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const SD_number_t f_subs = f.substitute(sub_map); + const double f_val = static_cast(f_subs); + Assert(f_val == (x_val * x_val + 2.0 * x_val * y_val + y_val * y_val), + ExcMessage( + "Problem with evaluation of double piecewise function")); + } + + // Condition is not met + { + const double x_val = -1.0; + const double y_val = 2.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + sub_map[y] = SD_number_t(y_val); + const double f_val = f.substitute_and_evaluate(sub_map); + Assert(f_val == (x_val * x_val - 2.0 * x_val * y_val + y_val * y_val), + ExcMessage( + "Problem with evaluation of double piecewise function")); + } + } + + std::cout << "Substitution with evaluation (if-else_if-else type function)" + << std::endl; + { + const SD_number_t x("x"); + const SD_number_t f_1 = x; + const SD_number_t f_2 = 2 * x; + const SD_number_t f_3 = 3 * x; + const SD_number_t f_4 = 4 * x; + const SD_number_t f({{(x > SD_number_t(4.0)), f_1}, + {(x > SD_number_t(2.0)), f_2}, + {(x > SD_number_t(0.0)), f_3}}, + f_4); + + // Condition "if" is met + { + const double x_val = 5.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + const SD_number_t f_subs = f.substitute(sub_map); + const double f_val = static_cast(f_subs); + Assert( + f_val == x_val, + ExcMessage( + "Problem with evaluation of 'if' branch of terminated piecewise function")); + } + + // Condition "else if (1)" is met + { + const double x_val = 3.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + const SD_number_t f_subs = f.substitute(sub_map); + const double f_val = static_cast(f_subs); + Assert( + f_val == (2 * x_val), + ExcMessage( + "Problem with evaluation of 'else if (1)' branch of terminated piecewise function")); + } + + // Condition "else if (2)" is met + { + const double x_val = 1.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + const SD_number_t f_subs = f.substitute(sub_map); + const double f_val = static_cast(f_subs); + Assert( + f_val == (3 * x_val), + ExcMessage( + "Problem with evaluation of 'else if (2)' branch of terminated piecewise function")); + } + + // Condition "else" is met + { + const double x_val = -1.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + const SD_number_t f_subs = f.substitute(sub_map); + const double f_val = static_cast(f_subs); + Assert( + f_val == (4 * x_val), + ExcMessage( + "Problem with evaluation of 'else' branch of terminated piecewise function")); + } + } + + std::cout << "Substitution with evaluation (if-else_if type function)" + << std::endl; + { + const SD_number_t x("x"); + const SD_number_t f_1 = x; + const SD_number_t f_2 = 2 * x; + const SD_number_t f_3 = 3 * x; + const SD_number_t f({{(x > SD_number_t(4.0)), f_1}, + {(x > SD_number_t(2.0)), f_2}, + {(x > SD_number_t(0.0)), f_3}}); + + // Condition "if" is met + { + const double x_val = 5.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + const SD_number_t f_subs = f.substitute(sub_map); + const double f_val = static_cast(f_subs); + Assert( + f_val == x_val, + ExcMessage( + "Problem with evaluation of 'if' branch of non-terminated piecewise function")); + } + + // Condition "else if (1)" is met + { + const double x_val = 3.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + const SD_number_t f_subs = f.substitute(sub_map); + const double f_val = static_cast(f_subs); + Assert( + f_val == (2 * x_val), + ExcMessage( + "Problem with evaluation of 'else if (1)' branch of non-terminated piecewise function")); + } + + // Condition "else if (2)" is met + { + const double x_val = 1.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + const SD_number_t f_subs = f.substitute(sub_map); + const double f_val = static_cast(f_subs); + Assert( + f_val == (3 * x_val), + ExcMessage( + "Problem with evaluation of 'else if (2)' branch of non-terminated piecewise function")); + } + + // No condition is met + { + const double x_val = -1.0; + SD::types::substitution_map sub_map; + sub_map[x] = SD_number_t(x_val); + const SD_number_t f_subs = f.substitute(sub_map); + const double f_val = static_cast(f_subs); + Assert( + numbers::is_nan(f_val) == true, + ExcMessage( + "Problem with evaluation of 'else' branch of non-terminated piecewise function")); + } + } + } + + deallog << "OK" << std::endl; +} diff --git a/tests/symengine/symengine_number_type_01.output b/tests/symengine/symengine_number_type_01.output new file mode 100644 index 000000000000..94923abb187e --- /dev/null +++ b/tests/symengine/symengine_number_type_01.output @@ -0,0 +1,17 @@ + +DEAL::Constructors +DEAL::Utility functions +DEAL:Serialization::0 0 1 x + +DEAL:Serialization::0 0 1 y + +DEAL:Serialization::0 0 11 2.5 + x + y + +DEAL::Comparison operators +DEAL::Logical operators +DEAL::Assignment operators +DEAL::Math operators +DEAL::Differentiation +DEAL::Substitution +DEAL::Evaluation +DEAL::OK From c5217c15fa235e5d2ecabee4f6c5a35959f1e704 Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Tue, 2 Apr 2019 21:56:32 +0200 Subject: [PATCH 363/507] add default constructor for ArrayView and a reinit() method --- doc/news/changes/minor/20190402DenisDavydov | 3 ++ include/deal.II/base/array_view.h | 49 +++++++++++++++++- tests/base/array_view_14.cc | 55 +++++++++++++++++++++ tests/base/array_view_14.output | 2 + 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 doc/news/changes/minor/20190402DenisDavydov create mode 100644 tests/base/array_view_14.cc create mode 100644 tests/base/array_view_14.output 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/include/deal.II/base/array_view.h b/include/deal.II/base/array_view.h index 130e693f4bef..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> diff --git a/tests/base/array_view_14.cc b/tests/base/array_view_14.cc new file mode 100644 index 000000000000..2e026c0a872e --- /dev/null +++ b/tests/base/array_view_14.cc @@ -0,0 +1,55 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// test for class ArrayView +// same as array_view_01.cc but uses default constructor and reinit() + +#include + +#include "../tests.h" + + +void +test() +{ + std::vector v(10); + + ArrayView a; + a.reinit(&v[4], 3); // writable view + a[2] = 42; + + Assert(a[2] == 42, ExcInternalError()); + Assert(v[6] == 42, ExcInternalError()); + + ArrayView a2; + a2.reinit(&v[4], 3); // readable view + Assert(a2[2] == 42, ExcInternalError()); + + ArrayView a3(a); // readable view, converted from 'a' + Assert(a3[2] == 42, ExcInternalError()); + + deallog << "OK" << std::endl; +} + + + +int +main() +{ + initlog(); + + test(); +} diff --git a/tests/base/array_view_14.output b/tests/base/array_view_14.output new file mode 100644 index 000000000000..0fd8fc12f0b4 --- /dev/null +++ b/tests/base/array_view_14.output @@ -0,0 +1,2 @@ + +DEAL::OK From 6c685776132ed8153981a91567113f3e0db0c79e Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 3 Apr 2019 05:04:16 +0200 Subject: [PATCH 364/507] Test SCALAPACK with -Werror --- tests/scalapack/scalapack_06.cc | 2 +- tests/scalapack/scalapack_06a.cc | 2 +- tests/scalapack/scalapack_06b.cc | 2 +- tests/scalapack/scalapack_06c.cc | 2 +- tests/scalapack/scalapack_12_a.cc | 6 ++++-- tests/scalapack/scalapack_12_b.cc | 6 ++++-- tests/scalapack/scalapack_12_c.cc | 6 ++++-- tests/scalapack/scalapack_12_d.cc | 6 ++++-- tests/scalapack/scalapack_13_a.cc | 6 ++++-- tests/scalapack/scalapack_13_b.cc | 6 ++++-- tests/scalapack/scalapack_14_a.cc | 6 ++++-- tests/scalapack/scalapack_14_b.cc | 6 ++++-- tests/scalapack/scalapack_15.cc | 2 +- tests/scalapack/scalapack_15_a.cc | 2 +- 14 files changed, 38 insertions(+), 22 deletions(-) diff --git a/tests/scalapack/scalapack_06.cc b/tests/scalapack/scalapack_06.cc index 78aee5295475..1c6a434b71f1 100644 --- a/tests/scalapack/scalapack_06.cc +++ b/tests/scalapack/scalapack_06.cc @@ -104,7 +104,7 @@ test(const unsigned int size, &*work.begin(), &lwork, &info); - lwork = work[0]; + lwork = static_cast(work[0]); work.resize(lwork); syev(&jobz, &uplo, diff --git a/tests/scalapack/scalapack_06a.cc b/tests/scalapack/scalapack_06a.cc index 39cf9f63f60d..7584d7041c94 100644 --- a/tests/scalapack/scalapack_06a.cc +++ b/tests/scalapack/scalapack_06a.cc @@ -100,7 +100,7 @@ test(const unsigned int size, &*work.begin(), &lwork, &info); - lwork = work[0]; + lwork = static_cast(work[0]); work.resize(lwork); syev(&jobz, &uplo, diff --git a/tests/scalapack/scalapack_06b.cc b/tests/scalapack/scalapack_06b.cc index 707aecfeeba7..4d02c8399f4e 100644 --- a/tests/scalapack/scalapack_06b.cc +++ b/tests/scalapack/scalapack_06b.cc @@ -105,7 +105,7 @@ test(const unsigned int size, &*work.begin(), &lwork, &info); - lwork = work[0]; + lwork = static_cast(work[0]); work.resize(lwork); syev(&jobz, &uplo, diff --git a/tests/scalapack/scalapack_06c.cc b/tests/scalapack/scalapack_06c.cc index 37a376c74c89..d7c59d22fdda 100644 --- a/tests/scalapack/scalapack_06c.cc +++ b/tests/scalapack/scalapack_06c.cc @@ -100,7 +100,7 @@ test(const unsigned int size, &*work.begin(), &lwork, &info); - lwork = work[0]; + lwork = static_cast(work[0]); work.resize(lwork); syev(&jobz, &uplo, diff --git a/tests/scalapack/scalapack_12_a.cc b/tests/scalapack/scalapack_12_a.cc index 8955491b6ef4..b89b755b45d2 100644 --- a/tests/scalapack/scalapack_12_a.cc +++ b/tests/scalapack/scalapack_12_a.cc @@ -44,8 +44,10 @@ test() std::cout << std::setprecision(10); ConditionalOStream pcout(std::cout, (this_mpi_process == 0)); - const unsigned int proc_rows = std::floor(std::sqrt(n_mpi_processes)); - const unsigned int proc_columns = std::floor(n_mpi_processes / proc_rows); + const auto proc_rows = + static_cast(std::floor(std::sqrt(n_mpi_processes))); + const auto proc_columns = + static_cast(std::floor(n_mpi_processes / proc_rows)); // create 2d process grid std::shared_ptr grid = std::make_shared(mpi_communicator, diff --git a/tests/scalapack/scalapack_12_b.cc b/tests/scalapack/scalapack_12_b.cc index 0f4cdb466cd7..be7843782aa2 100644 --- a/tests/scalapack/scalapack_12_b.cc +++ b/tests/scalapack/scalapack_12_b.cc @@ -45,8 +45,10 @@ test() std::cout << std::setprecision(10); ConditionalOStream pcout(std::cout, (this_mpi_process == 0)); - const unsigned int proc_rows = std::floor(std::sqrt(n_mpi_processes)); - const unsigned int proc_columns = std::floor(n_mpi_processes / proc_rows); + const auto proc_rows = + static_cast(std::floor(std::sqrt(n_mpi_processes))); + const auto proc_columns = + static_cast(std::floor(n_mpi_processes / proc_rows)); // create 2d process grid std::shared_ptr grid = std::make_shared(mpi_communicator, diff --git a/tests/scalapack/scalapack_12_c.cc b/tests/scalapack/scalapack_12_c.cc index 498a7ffc3817..71a6c7ed4938 100644 --- a/tests/scalapack/scalapack_12_c.cc +++ b/tests/scalapack/scalapack_12_c.cc @@ -45,8 +45,10 @@ test() std::cout << std::setprecision(10); ConditionalOStream pcout(std::cout, (this_mpi_process == 0)); - const unsigned int proc_rows = std::floor(std::sqrt(n_mpi_processes)); - const unsigned int proc_columns = std::floor(n_mpi_processes / proc_rows); + const auto proc_rows = + static_cast(std::floor(std::sqrt(n_mpi_processes))); + const auto proc_columns = + static_cast(std::floor(n_mpi_processes / proc_rows)); // create 2d process grid std::shared_ptr grid = std::make_shared(mpi_communicator, diff --git a/tests/scalapack/scalapack_12_d.cc b/tests/scalapack/scalapack_12_d.cc index 2f4f8e6d0866..81202354e588 100644 --- a/tests/scalapack/scalapack_12_d.cc +++ b/tests/scalapack/scalapack_12_d.cc @@ -45,8 +45,10 @@ test() std::cout << std::setprecision(10); ConditionalOStream pcout(std::cout, (this_mpi_process == 0)); - const unsigned int proc_rows = std::floor(std::sqrt(n_mpi_processes)); - const unsigned int proc_columns = std::floor(n_mpi_processes / proc_rows); + const auto proc_rows = + static_cast(std::floor(std::sqrt(n_mpi_processes))); + const auto proc_columns = + static_cast(std::floor(n_mpi_processes / proc_rows)); // create 2d process grid std::shared_ptr grid = std::make_shared(mpi_communicator, diff --git a/tests/scalapack/scalapack_13_a.cc b/tests/scalapack/scalapack_13_a.cc index e3d55299bad4..81c73d4809c1 100644 --- a/tests/scalapack/scalapack_13_a.cc +++ b/tests/scalapack/scalapack_13_a.cc @@ -44,8 +44,10 @@ test(const unsigned int block_size_i, const unsigned int block_size_j) std::cout << std::setprecision(10); ConditionalOStream pcout(std::cout, (this_mpi_process == 0)); - const unsigned int proc_rows = std::floor(std::sqrt(n_mpi_processes)); - const unsigned int proc_columns = std::floor(n_mpi_processes / proc_rows); + const auto proc_rows = + static_cast(std::floor(std::sqrt(n_mpi_processes))); + const auto proc_columns = + static_cast(std::floor(n_mpi_processes / proc_rows)); // create 2d process grid std::shared_ptr grid = std::make_shared(mpi_communicator, diff --git a/tests/scalapack/scalapack_13_b.cc b/tests/scalapack/scalapack_13_b.cc index 20fd3bd4bcf4..5334bdbc7a02 100644 --- a/tests/scalapack/scalapack_13_b.cc +++ b/tests/scalapack/scalapack_13_b.cc @@ -44,8 +44,10 @@ test(const unsigned int block_size_i, const unsigned int block_size_j) std::cout << std::setprecision(10); ConditionalOStream pcout(std::cout, (this_mpi_process == 0)); - const unsigned int proc_rows = std::floor(std::sqrt(n_mpi_processes)); - const unsigned int proc_columns = std::floor(n_mpi_processes / proc_rows); + const auto proc_rows = + static_cast(std::floor(std::sqrt(n_mpi_processes))); + const auto proc_columns = + static_cast(std::floor(n_mpi_processes / proc_rows)); // create 2d process grid std::shared_ptr grid = std::make_shared(mpi_communicator, diff --git a/tests/scalapack/scalapack_14_a.cc b/tests/scalapack/scalapack_14_a.cc index 81324ccf313e..c34e3e1ebdd4 100644 --- a/tests/scalapack/scalapack_14_a.cc +++ b/tests/scalapack/scalapack_14_a.cc @@ -45,8 +45,10 @@ test(const unsigned int block_size_i, const unsigned int block_size_j) std::cout << std::setprecision(10); ConditionalOStream pcout(std::cout, (this_mpi_process == 0)); - const unsigned int proc_rows = std::floor(std::sqrt(n_mpi_processes)); - const unsigned int proc_columns = std::floor(n_mpi_processes / proc_rows); + const auto proc_rows = + static_cast(std::floor(std::sqrt(n_mpi_processes))); + const auto proc_columns = + static_cast(std::floor(n_mpi_processes / proc_rows)); // create 2d process grid const std::vector sizes = {{400, 500}}; std::shared_ptr grid = diff --git a/tests/scalapack/scalapack_14_b.cc b/tests/scalapack/scalapack_14_b.cc index e32f5c653824..d79e17996aef 100644 --- a/tests/scalapack/scalapack_14_b.cc +++ b/tests/scalapack/scalapack_14_b.cc @@ -45,8 +45,10 @@ test(const unsigned int block_size_i, const unsigned int block_size_j) std::cout << std::setprecision(10); ConditionalOStream pcout(std::cout, (this_mpi_process == 0)); - const unsigned int proc_rows = std::floor(std::sqrt(n_mpi_processes)); - const unsigned int proc_columns = std::floor(n_mpi_processes / proc_rows); + const auto proc_rows = + static_cast(std::floor(std::sqrt(n_mpi_processes))); + const auto proc_columns = + static_cast(std::floor(n_mpi_processes / proc_rows)); // create 2d process grid const std::vector sizes = {{400, 500}}; std::shared_ptr grid = diff --git a/tests/scalapack/scalapack_15.cc b/tests/scalapack/scalapack_15.cc index e29fc69cbbe1..1dd40e682b49 100644 --- a/tests/scalapack/scalapack_15.cc +++ b/tests/scalapack/scalapack_15.cc @@ -128,7 +128,7 @@ test(const unsigned int size, &liwork, &info); - lwork = work[0]; + lwork = static_cast(work[0]); work.resize(lwork); liwork = iwork[0]; iwork.resize(liwork); diff --git a/tests/scalapack/scalapack_15_a.cc b/tests/scalapack/scalapack_15_a.cc index 59bc9368c882..515be289b390 100644 --- a/tests/scalapack/scalapack_15_a.cc +++ b/tests/scalapack/scalapack_15_a.cc @@ -128,7 +128,7 @@ test(const unsigned int size, &liwork, &info); - lwork = work[0]; + lwork = static_cast(work[0]); work.resize(lwork); liwork = iwork[0]; iwork.resize(liwork); From 5905b90cb7d31d28e077b363b697a3a93f637843 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Wed, 3 Apr 2019 08:53:59 -0600 Subject: [PATCH 365/507] fix hdf in serial - fix compilation - fix warnings about unused variables - move some variables around (smaller scope) --- source/base/hdf5.cc | 57 +++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/source/base/hdf5.cc b/source/base/hdf5.cc index d32555839966..75e45497230b 100644 --- a/source/base/hdf5.cc +++ b/source/base/hdf5.cc @@ -264,22 +264,25 @@ namespace HDF5 void set_plist(hid_t &plist, const bool mpi) { - herr_t ret; - if (mpi) { +# ifdef DEAL_II_WITH_MPI + herr_t ret; plist = H5Pcreate(H5P_DATASET_XFER); Assert(plist >= 0, ExcInternalError()); ret = H5Pset_dxpl_mpio(plist, H5FD_MPIO_COLLECTIVE); Assert(ret >= 0, ExcInternalError()); +# else + AssertThrow(false, ExcNotImplemented()); +# endif } else { plist = H5P_DEFAULT; } - // This avoids the unused warning - (void)ret; + (void)plist; + (void)mpi; } @@ -297,10 +300,10 @@ namespace HDF5 const bool mpi, const bool query_io_mode) { - herr_t ret; - if (mpi) { +# ifdef DEAL_II_WITH_MPI + herr_t ret; if (query_io_mode) { ret = H5Pget_mpio_actual_io_mode(plist, &io_mode); @@ -313,9 +316,17 @@ namespace HDF5 } ret = H5Pclose(plist); Assert(ret >= 0, ExcInternalError()); +# else + AssertThrow(false, ExcNotImplemented()); +# endif } - (void)ret; + (void)plist; + (void)io_mode; + (void)local_no_collective_cause; + (void)global_no_collective_cause; + (void)mpi; + (void)query_io_mode; } @@ -1377,7 +1388,15 @@ namespace HDF5 File::File(const std::string &name, const FileAccessMode mode) - : File(name, mode, false, MPI_COMM_NULL) + : File(name, + mode, + false, +# ifdef DEAL_II_WITH_MPI + MPI_COMM_NULL +# else + 0 +# endif + ) {} @@ -1404,22 +1423,25 @@ namespace HDF5 delete pointer; }); - hid_t plist; - herr_t ret; - const MPI_Info info = MPI_INFO_NULL; + hid_t plist; + herr_t ret; if (mpi) { -# ifndef DEAL_II_WITH_MPI - AssertThrow(false, ExcMessage("MPI support is disabled.")); -# endif // DEAL_II_WITH_MPI -# ifndef H5_HAVE_PARALLEL - AssertThrow(false, ExcMessage("HDF5 parallel support is disabled.")); -# endif // H5_HAVE_PARALLEL +# ifdef DEAL_II_WITH_MPI +# ifdef H5_HAVE_PARALLEL + const MPI_Info info = MPI_INFO_NULL; + plist = H5Pcreate(H5P_FILE_ACCESS); Assert(plist >= 0, ExcMessage("Error at H5Pcreate")); ret = H5Pset_fapl_mpio(plist, mpi_communicator, info); Assert(ret >= 0, ExcMessage("Error at H5Pset_fapl_mpio")); +# else + AssertThrow(false, ExcMessage("HDF5 parallel support is disabled.")); +# endif // H5_HAVE_PARALLEL +# else + AssertThrow(false, ExcMessage("MPI support is disabled.")); +# endif // DEAL_II_WITH_MPI } else { @@ -1450,6 +1472,7 @@ namespace HDF5 } (void)ret; + (void)mpi_communicator; } From 4a047ca75b358adc9d24b273044c8a81964401f2 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Wed, 3 Apr 2019 12:28:30 -0400 Subject: [PATCH 366/507] Fix space in error message --- include/deal.II/lac/sparse_direct.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/deal.II/lac/sparse_direct.h b/include/deal.II/lac/sparse_direct.h index aa6dfc92a957..7a15d120d7d8 100644 --- a/include/deal.II/lac/sparse_direct.h +++ b/include/deal.II/lac/sparse_direct.h @@ -310,7 +310,7 @@ class SparseDirectUMFPACK : public Subscriptor "single zero eigenvalue and its rank is therefore " "deficient by one." "\n\n" - "The other common situation is that you run out of memory." + "The other common situation is that you run out of memory. " "On a typical laptop or desktop, it should easily be possible " "to solve problems with 100,000 unknowns in 2d. If you are " "solving problems with many more unknowns than that, in " From 306eecc6d1348c150d90b5106b87dc50022b7124 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Mon, 1 Apr 2019 21:59:29 +0200 Subject: [PATCH 367/507] Add a class to perform GeneralDataStorage --- .../minor/20190402LucaHeltaiJean-PaulPelteret | 5 + .../deal.II/algorithms/general_data_storage.h | 473 ++++++++++++++++++ source/algorithms/CMakeLists.txt | 1 + source/algorithms/general_data_storage.cc | 61 +++ tests/algorithms/general_data_storage_01.cc | 228 +++++++++ .../general_data_storage_01.debug.output | 74 +++ .../general_data_storage_01.release.output | 24 + 7 files changed, 866 insertions(+) create mode 100644 doc/news/changes/minor/20190402LucaHeltaiJean-PaulPelteret create mode 100644 include/deal.II/algorithms/general_data_storage.h create mode 100644 source/algorithms/general_data_storage.cc create mode 100644 tests/algorithms/general_data_storage_01.cc create mode 100644 tests/algorithms/general_data_storage_01.debug.output create mode 100644 tests/algorithms/general_data_storage_01.release.output 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/include/deal.II/algorithms/general_data_storage.h b/include/deal.II/algorithms/general_data_storage.h new file mode 100644 index 000000000000..ed2905776161 --- /dev/null +++ b/include/deal.II/algorithms/general_data_storage.h @@ -0,0 +1,473 @@ +// --------------------------------------------------------------------- +// +// 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. + * + * After this function is called, all copied data owned by this class will + * go out of scope. Furthermore, all scoping requirements for data referenced + * by this class instance will be lifted. + * + * 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 concious 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, 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, Args &&... arguments); + + /** + * 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; + + /** + * Find out if we store an 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, + Args &... arguments) +{ + if (!stores_object_with_name(name)) + add_unique_copy(name, Type(arguments...)); + + return get_object_with_name(name); +} + + +template +Type & +GeneralDataStorage::get_or_add_object_with_name(const std::string &name, + Args &&... arguments) +{ + if (!stores_object_with_name(name)) + add_unique_copy(name, Type(std::forward(arguments)...)); + + return get_object_with_name(name); +} + + +#endif // DOXYGEN + + +DEAL_II_NAMESPACE_CLOSE + +#endif // dealii_algorithms_general_data_storage_h diff --git a/source/algorithms/CMakeLists.txt b/source/algorithms/CMakeLists.txt index 2eb6e268dbcc..030b6f36cd3a 100644 --- a/source/algorithms/CMakeLists.txt +++ b/source/algorithms/CMakeLists.txt @@ -16,6 +16,7 @@ INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) SET(_src + general_data_storage.cc operator.cc timestep_control.cc ) diff --git a/source/algorithms/general_data_storage.cc b/source/algorithms/general_data_storage.cc new file mode 100644 index 000000000000..85ff371299bf --- /dev/null +++ b/source/algorithms/general_data_storage.cc @@ -0,0 +1,61 @@ +// --------------------------------------------------------------------- +// +// 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 + + +DEAL_II_NAMESPACE_OPEN + + +std::size_t +GeneralDataStorage::size() const +{ + return any_data.size(); +} + + +void +GeneralDataStorage::merge(const GeneralDataStorage &other) +{ + any_data.insert(other.any_data.begin(), other.any_data.end()); +} + + +void +GeneralDataStorage::reset() +{ + any_data.clear(); +} + + +bool +GeneralDataStorage::stores_object_with_name(const std::string &name) const +{ + return any_data.find(name) != any_data.end(); +} + + +void +GeneralDataStorage::remove_object_with_name(const std::string &name) +{ + const auto it = any_data.find(name); + if (it != any_data.end()) + any_data.erase(it); +} + + + +DEAL_II_NAMESPACE_CLOSE diff --git a/tests/algorithms/general_data_storage_01.cc b/tests/algorithms/general_data_storage_01.cc new file mode 100644 index 000000000000..fc421e7895af --- /dev/null +++ b/tests/algorithms/general_data_storage_01.cc @@ -0,0 +1,228 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Test the core functionality of the GeneralDataStorage class + + +#include + +#include + +#include "../tests.h" + +int +main() +{ + initlog(); + + GeneralDataStorage data; + + deallog << "Add by copy" << std::endl; + { + data.reset(); + + // Create new data instance + const double val_1 = 1.0; + data.add_unique_copy("value", val_1); + const double &val_2 = data.get_object_with_name("value"); + Assert(data.stores_object_with_name("value"), ExcInternalError()); + Assert(val_2 == val_1, ExcInternalError()); + Assert(&val_2 != &val_1, ExcInternalError()); + + // Allowed overwrite of existing data + const double val_3 = 2.0; + data.add_or_overwrite_copy("value", val_3); + const double &val_4 = data.get_object_with_name("value"); + Assert(data.stores_object_with_name("value"), ExcInternalError()); + Assert(val_4 == val_3, ExcInternalError()); + Assert(&val_4 != &val_3, ExcInternalError()); + + // Create new data instance using alternative function + const double val_5 = 3.0; + data.add_or_overwrite_copy("value_2", val_5); + const double &val_6 = data.get_object_with_name("value_2"); + Assert(data.stores_object_with_name("value_2"), ExcInternalError()); + Assert(val_6 == val_5, ExcInternalError()); + Assert(&val_6 != &val_5, ExcInternalError()); + + deallog << "Size: " << data.size() << std::endl; + } + + deallog << "Add by reference" << std::endl; + { + data.reset(); + + // Create new data instance + const double val_1 = 1.0; + data.add_unique_reference("value", val_1); + const double &val_2 = data.get_object_with_name("value"); + Assert(data.stores_object_with_name("value"), ExcInternalError()); + Assert(val_2 == val_1, ExcInternalError()); + Assert(&val_2 == &val_1, ExcInternalError()); + + // Allowed overwrite of existing data + const double val_3 = 2.0; + data.add_or_overwrite_reference("value", val_3); + const double &val_4 = data.get_object_with_name("value"); + Assert(data.stores_object_with_name("value"), ExcInternalError()); + Assert(val_4 == val_3, ExcInternalError()); + Assert(&val_4 == &val_3, ExcInternalError()); + + // Create new data instance using alternative function + const double val_5 = 3.0; + data.add_or_overwrite_reference("value_2", val_5); + const double &val_6 = data.get_object_with_name("value_2"); + Assert(data.stores_object_with_name("value_2"), ExcInternalError()); + Assert(val_6 == val_5, ExcInternalError()); + Assert(&val_6 == &val_5, ExcInternalError()); + + deallog << "Size: " << data.size() << std::endl; + } + + deallog << "Add or construct" << std::endl; + { + data.reset(); + + using Type = std::pair; + + // Create new data instance + const Type &val_1 = + data.get_or_add_object_with_name("value", 1.0, 2.0); + Assert(data.stores_object_with_name("value"), ExcInternalError()); + Assert(val_1 == Type({1.0, 2.0}), ExcInternalError()); + + // Should not overwrite existing data + const Type &val_2 = + data.get_or_add_object_with_name("value", Type(3.0, 4.0)); + Assert(data.stores_object_with_name("value"), ExcInternalError()); + Assert(val_2 == Type({1.0, 2.0}), ExcInternalError()); + + deallog << "Size: " << data.size() << std::endl; + } + + deallog << "Merge" << std::endl; + { + data.reset(); + + const double val_1 = 1.0; + data.add_unique_copy("value", val_1); + + GeneralDataStorage data_2; + data_2.add_unique_copy("value", 2.0); // Duplicate + data_2.add_unique_copy("value_2", 3.0); + + deallog << "Data pre-merge:" << std::endl; + data.print_info(deallog); + deallog << "Size: " << data.size() << std::endl; + deallog << "Data 2 pre-merge:" << std::endl; + data_2.print_info(deallog); + deallog << "Size: " << data_2.size() << std::endl; + + data.merge(data_2); + + deallog << "Data post-merge:" << std::endl; + data.print_info(deallog); + deallog << "Size: " << data.size() << std::endl; + } + + + deal_II_exceptions::disable_abort_on_exception(); + + deallog << "Try to overwrite existing entry: Copy" << std::endl; + { + data.reset(); + + const double val_1 = 1.0; + data.add_unique_copy("value", val_1); + + try + { + const double val_2 = 1.0; + data.add_unique_copy("value", val_2); + } + catch (const GeneralDataStorage::ExcNameHasBeenFound &exc) + { + deallog << exc.what() << std::endl; + } + } + + deallog << "Try to overwrite existing entry: Reference" << std::endl; + { + data.reset(); + + const double val_1 = 1.0; + data.add_unique_reference("value", val_1); + + try + { + const double val_2 = 2.0; + data.add_unique_reference("value", val_2); + } + catch (const GeneralDataStorage::ExcNameHasBeenFound &exc) + { + deallog << exc.what() << std::endl; + } + } + + deallog << "Fetch non-existing entry" << std::endl; + { + data.reset(); + + try + { + data.get_object_with_name("value"); + } + catch (const GeneralDataStorage::ExcNameNotFound &exc) + { + deallog << exc.what() << std::endl; + } + } + + deallog << "Access removed entry (reference)" << std::endl; + { + data.reset(); + + const double val_1 = 1.0; + data.add_unique_reference("value", val_1); + data.remove_object_with_name("value"); + + try + { + data.get_object_with_name("value"); + } + catch (const GeneralDataStorage::ExcNameNotFound &exc) + { + deallog << exc.what() << std::endl; + } + } + + deallog << "Access removed entry (copy)" << std::endl; + { + data.reset(); + + data.add_unique_copy("value", 1.0); + data.remove_object_with_name("value"); + + try + { + data.get_object_with_name("value"); + } + catch (const GeneralDataStorage::ExcNameNotFound &exc) + { + deallog << exc.what() << std::endl; + } + } +} diff --git a/tests/algorithms/general_data_storage_01.debug.output b/tests/algorithms/general_data_storage_01.debug.output new file mode 100644 index 000000000000..4583c5e2160f --- /dev/null +++ b/tests/algorithms/general_data_storage_01.debug.output @@ -0,0 +1,74 @@ + +DEAL::Add by copy +DEAL::Size: 2 +DEAL::Add by reference +DEAL::Size: 2 +DEAL::Add or construct +DEAL::Size: 1 +DEAL::Merge +DEAL::Data pre-merge: +DEAL::value double +DEAL::Size: 1 +DEAL::Data 2 pre-merge: +DEAL::value double +DEAL::value_2 double +DEAL::Size: 2 +DEAL::Data post-merge: +DEAL::value double +DEAL::value_2 double +DEAL::Size: 2 +DEAL::Try to overwrite existing entry: Copy +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + void dealii::GeneralDataStorage::add_unique_copy(const std::string &, const Type &) [Type = double] +The violated condition was: + !stores_object_with_name(name) +Additional information: + An entry with the name value already exists. +-------------------------------------------------------- + +DEAL::Try to overwrite existing entry: Reference +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + void dealii::GeneralDataStorage::add_unique_reference(const std::string &, Type &) [Type = const double] +The violated condition was: + !stores_object_with_name(name) +Additional information: + An entry with the name value already exists. +-------------------------------------------------------- + +DEAL::Fetch non-existing entry +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + Type &dealii::GeneralDataStorage::get_object_with_name(const std::string &) [Type = double] +The violated condition was: + stores_object_with_name(name) +Additional information: + No entry with the name value exists. +-------------------------------------------------------- + +DEAL::Access removed entry (reference) +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + Type &dealii::GeneralDataStorage::get_object_with_name(const std::string &) [Type = double] +The violated condition was: + stores_object_with_name(name) +Additional information: + No entry with the name value exists. +-------------------------------------------------------- + +DEAL::Access removed entry (copy) +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + Type &dealii::GeneralDataStorage::get_object_with_name(const std::string &) [Type = double] +The violated condition was: + stores_object_with_name(name) +Additional information: + No entry with the name value exists. +-------------------------------------------------------- + diff --git a/tests/algorithms/general_data_storage_01.release.output b/tests/algorithms/general_data_storage_01.release.output new file mode 100644 index 000000000000..b10d09135f90 --- /dev/null +++ b/tests/algorithms/general_data_storage_01.release.output @@ -0,0 +1,24 @@ + +DEAL::Add by copy +DEAL::Size: 2 +DEAL::Add by reference +DEAL::Size: 2 +DEAL::Add or construct +DEAL::Size: 1 +DEAL::Merge +DEAL::Data pre-merge: +DEAL::value double +DEAL::Size: 1 +DEAL::Data 2 pre-merge: +DEAL::value double +DEAL::value_2 double +DEAL::Size: 2 +DEAL::Data post-merge: +DEAL::value double +DEAL::value_2 double +DEAL::Size: 2 +DEAL::Try to overwrite existing entry: Copy +DEAL::Try to overwrite existing entry: Reference +DEAL::Fetch non-existing entry +DEAL::Access removed entry (reference) +DEAL::Access removed entry (copy) From 04673e5ccbd82ddff5de541814f3a7bb6ef84af9 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 4 Apr 2019 07:58:49 +0200 Subject: [PATCH 368/507] Fix a typo in a changelog entry --- doc/news/changes/major/20190329Jean-PaulPelteret | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/news/changes/major/20190329Jean-PaulPelteret b/doc/news/changes/major/20190329Jean-PaulPelteret index d5f571d8fab3..50d4c4b64022 100644 --- a/doc/news/changes/major/20190329Jean-PaulPelteret +++ b/doc/news/changes/major/20190329Jean-PaulPelteret @@ -1,4 +1,4 @@ -New: A new class Differentiation::SD::Expression has been added. which allows +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: From 62ed359ab6aac96bb5aee6109e6f35dd6b37fa80 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Fri, 22 Feb 2019 17:23:55 -0700 Subject: [PATCH 369/507] Edit the introduction of step-61. --- examples/step-61/doc/intro.dox | 402 ++++++++++++++++++++++----------- 1 file changed, 273 insertions(+), 129 deletions(-) diff --git a/examples/step-61/doc/intro.dox b/examples/step-61/doc/intro.dox index 5cc7c2120e3c..6d3ed92ed819 100644 --- a/examples/step-61/doc/intro.dox +++ b/examples/step-61/doc/intro.dox @@ -102,7 +102,7 @@ formulation of the problem, for all test functions $q$, where @f{equation*} \mathcal{A}\left(p,q\right) - := \int_\Omega \mathbf{K} \nabla p \cdot \nabla q \;\mathrm{d}x, + := \int_\Omega \left(\mathbf{K} \nabla p\right) \cdot \nabla q \;\mathrm{d}x, @f} and @f{equation*} @@ -139,186 +139,330 @@ that is only defined in cell interiors. Consequently, for all discrete test functions $q_h$, where @f{equation*} \mathcal{A}_h\left(p_h,q_h\right) - := \sum_{T \in \mathcal{T}_h} - \int_T \mathbf{K} \nabla_{w,d} p_h \cdot \nabla_{w,d} q_h \;\mathrm{d}x, + := \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_{T \in \mathcal{T}_h} \int_T f \, q_h^\circ \;\mathrm{d}x + := \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 - $ \nabla_{w,d} p_h $ that is defined for our peculiarly defined approximation $p_h$. -We use FE_DGQ as the interior polynomial space, -FE_FaceQ as the face polynomial space, and Raviart-Thomas elements for the velocity -$\mathbf{u} = -{\mathbf{K}} \nabla_{w,d} p$. +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. -

    Assembling the linear system

    +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".) -First, we solve for the pressure. -We collect two local spaces together in one FESystem, -the first component in this finite element system denotes -the space for interior pressure, and the second denotes -the space for face pressure. -For the interior component, we use the polynomial space FE_DGQ. -For the face component, we use FE_FaceQ. - -We use shape functions defined on spaces FE_DGQ and FE_FaceQ to -approximate pressures, i.e., $p_h = \sum a_i \phi_i,$ -where $\phi_i$ are shape functions of FESystem. -We construct the local system by using discrete weak gradients of -shape functions of FE_DGQ and FE_FaceQ. -The discrete weak gradients of shape functions $\nabla_{w,d} \phi$ are defined as -$\nabla_{w,d} \phi = \sum_{i=1}^m c_i \mathbf{w}_i,$ -where $\mathbf{w}_i$ is the basis function of $RT(k)$. - -Using integration by parts, we have a small linear system -on each element $T$, + +

    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*} -\int_{T} \left(\nabla_{w,d} \phi \right) \cdot \mathbf{w} \mathrm{d}x= -\int_{T^\partial} \phi^{\partial} \left(\mathbf{w} \cdot \mathbf{n}\right) \mathrm{d}x- -\int_{T^\circ} \phi^{\circ} \left(\nabla \cdot \mathbf{w}\right) \mathrm{d}x, -\quad \forall \mathbf{w} \in RT_{[k]}(E), +\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*} -\sum_{i=1}^m c_i \int_T \mathbf{w}_i \cdot \mathbf{w}_j \mathrm{d}x = -\int_{T^{\partial}} \phi_i^{\partial} -\left(\mathbf{w}_j \cdot \mathbf{n} \right) \mathrm{d}x - -\int_{T^{\circ}} \phi_i^{\circ} \left (\nabla \cdot \mathbf{w}_j \right)\mathrm{d}x, +\nabla_{w,d} \varphi_j|_K + = \sum_k C_{jk}^K \mathbf v_k|_K @f} -which can be simplified to be -@f{equation*} -\mathbf{C}_{E}\mathbf{M}_{E} = \mathbf{F}_{E}, +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} -where $\mathbf{C}_E$ is the matrix with unknown coefficients $c$, -$\mathbf{M}_E$ is the Gram matrix -$\left[ \int_T \mathbf{w}_i \cdot \mathbf{w}_j \right] \mathrm{d}x$, -$\mathbf{F}_E$ is the matrix of right hand side, -$\mathbf{w}$ and $\phi_i^{\circ}$ are in FEValues, -$\phi_i^{\partial}$ is in FEFaceValues. -Then we solve for $\mathbf{C}_E = \mathbf{F}_E \mathbf{M}_E^{-1}$. -Now, discrete weak gradients of shape functions are written as -linear combinations of basis functions of the $RT$ space. -In our code, we name $\mathbf{C}_E$ as cell_matrix_C, -$\mathbf{M}_E$ as cell_matrix_rt, -$\mathbf{F}_E$ as cell_matrix_F. - -The components of the local cell matrices $\mathbf{A}$ are -@f{equation*} -\mathbf{A}_{ij} = -\int_{T} \mathbf{K} \nabla_{w,d} \phi_i \cdot \nabla_{w,d} \phi_j \mathrm{d}x. +(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} -From previous steps, we know $\nabla_{w,d} \phi_i = \sum_{k=1}^m c_{ik} \mathbf{w}_k,$ -and $\nabla_{w,d} \phi_j = \sum_{l=1}^m c_{jl} \mathbf{w}_l.$ -Then combining the coefficients we have calculated, components of $\mathbf{A}$ are calculated as -@f{equation*} -\int_T \sum_{k,l = 1}^{m}c_{ik} c_{jl} \left(\mathbf{K} \mathbf{w}_i \cdot \mathbf{w}_j\right) \mathrm{d}x -= \sum_{k,l = 1}^{m}c_{ik} c_{jl} \int_{T} \mathbf{K} \mathbf{w}_i \cdot \mathbf{w}_j \mathrm{d}x. +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. -Next, we use ConstraintMatrix::distribute_local_to_global to -distribute contributions from local matrices $\mathbf{A}$ to the system matrix. -In the scheme -$\mathcal{A}_h\left(p_h,q \right) = \mathcal{F} \left( q \right),$ -we have system matrix and system right hand side, -we can solve for the coefficients of the system matrix. -The solution vector of the scheme represents the pressure values in interiors and on faces. +

    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 $L_2$-errors

    -After we have calculated the numerical pressure $p$, -we use discrete weak gradients of $p$ to calculate the velocity on each element. +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". -On each element the gradient of the numerical pressure $\nabla p$ can be -approximated by discrete weak gradients $ \nabla_{w,d}\phi_i$, so +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 = \sum_{i} a_i \nabla_{w,d}\phi_i. +\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} -The numerical velocity $ \mathbf{u}_h = -\mathbf{K} \nabla_{w,d}p_h$ can be written as -@f{equation*} -\mathbf{u}_h = -\mathbf{K} \nabla_{w,d} p = --\sum_{i} \sum_{j} a_ic_{ij}\mathbf{K}\mathbf{w}_j, +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_{ij}$ is the coefficient of Gram matrix, -$\mathbf{w}_j$ is the basis function of the $RT$ space. -$\mathbf{K} \mathbf{w}_j$ may not be in the $RT$ space. -So we need $L_2$-projection to project it back to the $RT$ space. +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{w}_j \right) = -\sum_{k} d_{jk}\mathbf{w}_k$. +$ \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{Kw}_j \right),\mathbf{w}_k \right)_E = -\left( \mathbf{Kw}_j,\mathbf{w}_k \right)_E.$ -So the numerical velocity becomes +$\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=0}^{4} \sum_{j=1}^{4}a_ib_{ij}\mathbf{Q}_h \left( \mathbf{K}\mathbf{w}_j \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}$, +and we have the following system to solve for the coefficients $d_{jk}$: @f{equation*} - \left[ - \begin{matrix} - \left(\mathbf{w}_i,\mathbf{w}_j \right) - \end{matrix} - \right] - \left[ - \begin{matrix} + \sum_j + \left(\mathbf{v}_i,\mathbf{v}_j\right) d_{jk} - \end{matrix} - \right] = - \left[ - \begin{matrix} - \left( \mathbf{Kw}_j,\mathbf{w}_k \right) - \end{matrix} - \right]. + \left( \mathbf{Kv}_j,\mathbf{v}_k \right). @f} +In the implementation below, the matrix with elements $ - \left[ - \begin{matrix} d_{jk} - \end{matrix} - \right] $ -is named cell_matrix_D, +is called cell_matrix_D, +whereas the matrix with elements $ -\left[ - \begin{matrix} - \left( \mathbf{Kw}_j,\mathbf{w}_k \right) - \end{matrix} - \right] + \left( \mathbf{Kv}_j,\mathbf{v}_k \right) $ -is named cell_matrix_E. +is called cell_matrix_E. Then the elementwise velocity is @f{equation*} -\mathbf{u}_h = -\sum_{i} \sum_{j}a_ic_{ij}\sum_{k}d_{jk}\mathbf{w}_k = -\sum_{k}- \left(\sum_{j} \sum_{i} a_ic_{ij}d_{jk} \right)\mathbf{w}_k, +\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} a_ic_{ij}d_{jk}$ is named +where $-\sum_{j} \sum_{i} P_ic_{ij}d_{jk}$ is called beta in the code. -We calculate the $L_2$-errors of pressure, velocity and flux -by the following formulas, +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{eqnarray*} \|p-p_h^\circ\|^2 - = \sum_{T \in \mathcal{T}_h} \|p-p_h^\circ\|_{L^2(E)}^2, \\ + = \sum_{K \in \mathbb{T}} \|p-p_h^\circ\|_{L_2(K)}^2, \\ \|\mathbf{u}-\mathbf{u}_h\|^2 - = \sum_{T \in \mathcal{T}_h} \|\mathbf{u}-\mathbf{u}_h\|_{L^2(E)^2}^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_{T \in \mathcal{T}_h} \sum_{\gamma \subset T^\partial} - \frac{|T|}{|\gamma|} \|\mathbf{u} \cdot \mathbf{n} - \mathbf{u}_h \cdot \mathbf{n}\|_{L^2(\gamma)}^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 $| T |$ is the area of the element, +where $| K |$ is the area of the element, $\gamma$ are faces of the element, -$\mathbf{n}$ are unit normal vectors of each face. +$\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. -We will extract interior pressure solutions of each cell -from the global solution and calculate the $L_2$ error -by using function VectorTools::integrate_difference. +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. From f0c54937dbde209b95ad4dced0c903a088a563b5 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Thu, 4 Apr 2019 14:34:40 -0600 Subject: [PATCH 370/507] Fix a misspelled word. --- include/deal.II/multigrid/mg_matrix.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/deal.II/multigrid/mg_matrix.h b/include/deal.II/multigrid/mg_matrix.h index 2463e3ca39b9..59fcf3a9c446 100644 --- a/include/deal.II/multigrid/mg_matrix.h +++ b/include/deal.II/multigrid/mg_matrix.h @@ -35,8 +35,8 @@ namespace mg { /** * Multilevel matrix. This matrix stores an MGLevelObject of - * LinearOpetors. It implements the interface defined in MGMatrixBase, so - * that it can be used as a matrix in Multigrid. + * LinearOperator objects. It implements the interface defined in + * MGMatrixBase, so that it can be used as a matrix in Multigrid. * * @author Guido Kanschat * @date 2002, 2010 From 90a81c9e4ada48a0a34cf28d464141f75ce186c9 Mon Sep 17 00:00:00 2001 From: David Wells Date: Fri, 5 Apr 2019 17:07:43 -0400 Subject: [PATCH 371/507] Silence an unused variable warning. --- source/base/hdf5.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/base/hdf5.cc b/source/base/hdf5.cc index 75e45497230b..bd13d4adeb76 100644 --- a/source/base/hdf5.cc +++ b/source/base/hdf5.cc @@ -267,10 +267,10 @@ namespace HDF5 if (mpi) { # ifdef DEAL_II_WITH_MPI - herr_t ret; plist = H5Pcreate(H5P_DATASET_XFER); Assert(plist >= 0, ExcInternalError()); - ret = H5Pset_dxpl_mpio(plist, H5FD_MPIO_COLLECTIVE); + const herr_t ret = H5Pset_dxpl_mpio(plist, H5FD_MPIO_COLLECTIVE); + (void)ret; Assert(ret >= 0, ExcInternalError()); # else AssertThrow(false, ExcNotImplemented()); @@ -304,6 +304,7 @@ namespace HDF5 { # ifdef DEAL_II_WITH_MPI herr_t ret; + (void)ret; if (query_io_mode) { ret = H5Pget_mpio_actual_io_mode(plist, &io_mode); From 88d865167aaceba18ffeee838085c780eee40502 Mon Sep 17 00:00:00 2001 From: tcclevenger Date: Tue, 19 Feb 2019 16:15:20 -0700 Subject: [PATCH 372/507] add step-63.cc (no doc) --- examples/step-63/block_jacobi.prm | 14 + examples/step-63/block_sor.prm | 14 + examples/step-63/jacobi.prm | 14 + examples/step-63/sor.prm | 15 + examples/step-63/step-63.cc | 1082 ++++++++++++++++++++++++++++- 5 files changed, 1135 insertions(+), 4 deletions(-) create mode 100644 examples/step-63/block_jacobi.prm create mode 100644 examples/step-63/block_sor.prm create mode 100644 examples/step-63/jacobi.prm create mode 100644 examples/step-63/sor.prm diff --git a/examples/step-63/block_jacobi.prm b/examples/step-63/block_jacobi.prm new file mode 100644 index 000000000000..a8dc7f556696 --- /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|random|downstream|upstream +set dof renumbering = downstream + +# With streamline diffusion: true|false +set with sd = 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..f5991834c4a5 --- /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: none|random|downstream|upstream +set dof renumbering = downstream + +# With streamline diffusion: true|false +set with sd = true + +# Output: true|false +set output = false diff --git a/examples/step-63/jacobi.prm b/examples/step-63/jacobi.prm new file mode 100644 index 000000000000..d6a55ff53b93 --- /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|random|downstream|upstream +set dof renumbering = downstream + +# With streamline diffusion: true|false +set with sd = true + +# Output: true|false +set output = false diff --git a/examples/step-63/sor.prm b/examples/step-63/sor.prm new file mode 100644 index 000000000000..47ab13c3d5b3 --- /dev/null +++ b/examples/step-63/sor.prm @@ -0,0 +1,15 @@ +# Finite Element degree +set fe degree = 1 + +# Smoother Type: sor|jacobi|block sor|block jacobi +set smoother type = sor + +# Dof renumbering: no|random|downstream|upstream +set dof renumbering = downstream + + +# With streamline diffusion: true|false +set with sd = true + +# Output: true|false +set output = false diff --git a/examples/step-63/step-63.cc b/examples/step-63/step-63.cc index 2534596dc665..dcfcd1fa54ec 100644 --- a/examples/step-63/step-63.cc +++ b/examples/step-63/step-63.cc @@ -19,16 +19,1091 @@ // @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 -int main() + +#include +#include + + + +namespace Step100 +{ + 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 + { + unsigned int level; + unsigned int dofs_per_cell; + + FullMatrix cell_matrix; + Vector cell_rhs; + std::vector local_dof_indices; + }; + + + struct Settings + { + bool try_parse(const std::string &prm_filename); + + unsigned int fe_degree; + std::string smoother_type; + std::string dof_renum; + bool with_sd; + bool output; + }; + + + bool Settings::try_parse(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|random|downstream|upstream"), + "Dof renumbering: none|random|downstream|upstream"); + prm.declare_entry("with sd", + "true", + Patterns::Bool(), + "With streamline diffusion: true|false"); + prm.declare_entry("output", + "true", + Patterns::Bool(), + "Generate graphical output: true|false"); + + try + { + prm.parse_input(prm_filename); + } + catch (const dealii::PathSearch::ExcFileNotFound &) + { + if (prm_filename.size() > 0) + std::cerr << "ERRROR: could not open the .prm file '" << prm_filename + << "'" << std::endl; + else + std::cerr << "Usage: please pass a .prm file as the first argument" + << std::endl; + + prm.print_parameters(std::cout, ParameterHandler::Text); + return false; + } + this->fe_degree = prm.get_integer("fe degree"); + this->smoother_type = prm.get("smoother type"); + this->dof_renum = prm.get("dof renumbering"); + this->with_sd = prm.get_bool("with sd"); + this->output = prm.get_bool("output"); + + return true; + } + + + + namespace + { + template + struct CompareDownstream + { + /** + * Constructor. + */ + CompareDownstream(const Tensor<1, dim> &dir) + : dir(dir) + {} + /** + * Return true if c1 less c2. + */ + bool operator()(const Iterator &c1, const Iterator &c2) const + { + const Tensor<1, dim> diff = c2->center() - c1->center(); + return (diff * dir > 0); + } + + private: + /** + * Flow direction. + */ + const Tensor<1, dim> dir; + }; + + // Functions for creating permutation of cells for output and Block + // smoothers + template + std::vector + create_downstream_order(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 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_order(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 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_order(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; the following is essentially std::shuffle (which + // is new in C++11) but with a boost URNG + ::boost::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 = + ::boost::random::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_order(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; the following is essentially std::shuffle (which + // is new in C++11) but with a boost URNG + ::boost::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 = + ::boost::random::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; + } + + } // namespace + + + + // RHS and boundary is an adaptation from one in + // Finite Elements and Fast Iterative Solvers: with Applications + // in Incompressible Fluid Dynamics + 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; + + private: + static const Point center_point; + }; + + 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] * p[0] + p[1] * p[1] - 0.3 * 0.3) < + 1e-8 // around cylinder + || std::fabs(p[0] + 1) < 1e-8 // x == -1 + || std::fabs(p[1] - 1) < 1e-8 // y == 1 + || (std::fabs(p[1] + 1) < 1e-8 && p[0] < 0.5) // y == -1, x <= 0.5 + ) + { + return 0.0; + } + else 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 delta_value(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' + double Peclet = dir.norm() * hk / (2.0 * eps * pk); + 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(); + + std::unique_ptr>> create_smoother(); + + void solve(); + void refine_grid(); + void output_results(const unsigned int cycle) const; + + Triangulation triangulation; + DoFHandler dof_handler; + + FE_Q fe; + MappingQ mapping; + unsigned int quad_degree; + + 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; + + MGConstrainedDoFs mg_constrained_dofs; + + Settings settings; + const double epsilon; + Tensor<1, dim> advection_direction; + }; + + + + template + AdvectionProblem::AdvectionProblem(Settings settings) + : triangulation(Triangulation::limit_level_difference_at_vertices) + , dof_handler(triangulation) + , fe(settings.fe_degree) + , mapping(settings.fe_degree) + , quad_degree(2 * fe.degree + 2) + , settings(settings) + , epsilon(0.005) + { + // Set Advection direction (problem is an adaptation from one in + // Finite Elements and Fast Iterative Solvers: with Applications + // in Incompressible Fluid Dynamics) + 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_renum == "downstream" || + settings.dof_renum == "upstream") + { + const Tensor<1, dim> direction = + (settings.dof_renum == "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_renum == "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); + + std::set dirichlet_boundary_ids = {0, 1}; + mg_constrained_dofs.make_zero_boundary_constraints(dof_handler, + dirichlet_boundary_ids); + + 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) + { + const unsigned int level = cell->level(); + copy_data.level = level; + + const unsigned int dofs_per_cell = + scratch_data.fe_values.get_fe().dofs_per_cell; + copy_data.dofs_per_cell = dofs_per_cell; + + const unsigned int n_q_points = + scratch_data.fe_values.get_quadrature().size(); + copy_data.cell_matrix.reinit(dofs_per_cell, dofs_per_cell); + + if (!cell->is_level_cell()) + 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_sd ? delta_value(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_sd) + 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()) + { + 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_sd) + 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, quad_degree), + CopyData(), + MeshWorker::assemble_own_cells); + + + // Assemble GMG + std::vector> boundary_constraints( + triangulation.n_global_levels()); + for (unsigned int level = 0; level < triangulation.n_global_levels(); + ++level) + { + IndexSet dofset; + DoFTools::extract_locally_relevant_level_dofs(dof_handler, + level, + dofset); + boundary_constraints[level].reinit(dofset); + 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, quad_degree), + CopyData(), + MeshWorker::assemble_own_cells); + } + + + template + std::unique_ptr>> + AdvectionProblem::create_smoother() + { + if (settings.smoother_type == "sor") + { + typedef PreconditionSOR> Smoother; + + 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); + return smoother; + } + else if (settings.smoother_type == "jacobi") + { + typedef PreconditionJacobi> Smoother; + 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); + return smoother; + } + else if (settings.smoother_type == "block sor") + { + typedef RelaxationBlockSOR, double, Vector> + Smoother; + + static MGLevelObject smoother_data; + 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 = 1.0; + smoother_data[level].inversion = PreconditionBlockBase::svd; + + std::vector ordered_indices; + if (settings.dof_renum == "downstream") + ordered_indices = create_downstream_order(dof_handler, + advection_direction, + level); + else if (settings.dof_renum == "upstream") + ordered_indices = + create_downstream_order(dof_handler, + -1.0 * advection_direction, + level); + else if (settings.dof_renum == "random") + ordered_indices = create_random_order(dof_handler, level); + else if (settings.dof_renum == "none") + { + // Do nothing + } + else + AssertThrow(false, ExcNotImplemented()); + + smoother_data[level].order = + std::vector>(1, ordered_indices); + } + + auto smoother = + std_cxx14::make_unique, + Smoother, + Vector>>(); + smoother->initialize(mg_matrices, smoother_data); + smoother->set_steps(1); + return smoother; + } + else if (settings.smoother_type == "block jacobi") + { + typedef RelaxationBlockJacobi, + double, + Vector> + Smoother; + + static MGLevelObject smoother_data; + 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 = 0.25; + smoother_data[level].inversion = PreconditionBlockBase::svd; + + std::vector ordered_indices; + if (settings.dof_renum == "downstream") + ordered_indices = create_downstream_order(dof_handler, + advection_direction, + level); + else if (settings.dof_renum == "upstream") + ordered_indices = + create_downstream_order(dof_handler, + -1.0 * advection_direction, + level); + else if (settings.dof_renum == "random") + ordered_indices = create_random_order(dof_handler, level); + else if (settings.dof_renum == "none") + { + // Do nothing + } + else + AssertThrow(false, ExcNotImplemented()); + + smoother_data[level].order = + std::vector>(1, ordered_indices); + } + + auto smoother = + std_cxx14::make_unique, + Smoother, + Vector>>(); + smoother->initialize(mg_matrices, smoother_data); + smoother->set_steps(2); + return smoother; + } + else + AssertThrow(false, ExcNotImplemented()); + } + + + template + void AdvectionProblem::solve() + { + Timer time; + + const double solve_tol = 1e-8 * system_rhs.l2_norm(); + const unsigned int max_iters = 200; + SolverControl solver_control(max_iters, solve_tol, true, true); + solver_control.enable_history_data(); + + typedef MGTransferPrebuilt> Transfer; + 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); + + std::unique_ptr>> mg_smoother = create_smoother(); + + mg::Matrix> mg_matrix(mg_matrices); + mg::Matrix> mg_interface_matrix_in(mg_interface_in); + mg::Matrix> mg_interface_matrix_out(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_tol << "..." + << std::endl; + SolverGMRES<> solver(solver_control); + + time.restart(); + 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); + } + + + + template + void AdvectionProblem::output_results(const unsigned int cycle) const + { + DataOut data_out; + data_out.attach_dof_handler(dof_handler); + data_out.add_data_vector(solution, "solution"); + + // 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; + if (settings.dof_renum == "downstream") + { + ordered_indices = + create_downstream_order(dof_handler, advection_direction); + } + else if (settings.dof_renum == "upstream") + { + ordered_indices = + create_downstream_order(dof_handler, -1.0 * advection_direction); + } + else if (settings.dof_renum == "random") + { + ordered_indices = create_random_order(dof_handler); + } + else if (settings.dof_renum == "none") + { + ordered_indices.resize(n_active_cells); + for (unsigned int i = 0; i < n_active_cells; ++i) + ordered_indices[i] = i; + } + else + AssertThrow(false, ExcNotImplemented()); + + // 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); + } + + 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 Step100 + + +int main(int argc, char *argv[]) { try { - // do nothing. + Step100::Settings settings; + if (!settings.try_parse((argc > 1) ? (argv[1]) : "")) + return 0; + + Step100::AdvectionProblem<2> advection_problem_2d(settings); + advection_problem_2d.run(); } catch (std::exception &exc) { @@ -41,7 +1116,6 @@ int main() << "Aborting!" << std::endl << "----------------------------------------------------" << std::endl; - return 1; } catch (...) From 74fdd5139d12f8d1522cb4efe6105fe0ee42560f Mon Sep 17 00:00:00 2001 From: tcclevenger Date: Fri, 5 Apr 2019 17:09:38 -0600 Subject: [PATCH 373/507] requested changes --- examples/step-63/block_jacobi.prm | 14 +- examples/step-63/block_sor.prm | 14 +- examples/step-63/jacobi.prm | 14 +- examples/step-63/sor.prm | 15 +- examples/step-63/step-63.cc | 600 +++++++++++++++--------------- 5 files changed, 332 insertions(+), 325 deletions(-) diff --git a/examples/step-63/block_jacobi.prm b/examples/step-63/block_jacobi.prm index a8dc7f556696..9e6f98326eaa 100644 --- a/examples/step-63/block_jacobi.prm +++ b/examples/step-63/block_jacobi.prm @@ -1,14 +1,14 @@ # Finite Element degree -set fe degree = 1 +set Fe degree = 1 -# Smoother Type: sor|jacobi|block sor|block jacobi -set smoother type = block jacobi +# Smoother Type: SOR|Jacobi|block SOR|block Jacobi +set Smoother type = block Jacobi -# Dof renumbering: no|random|downstream|upstream -set dof renumbering = downstream +# DoF renumbering: no|downstream|upstream|random +set DoF renumbering = downstream # With streamline diffusion: true|false -set with sd = true +set With streamline diffusion = true # Output: true|false -set output = false +set Output = false diff --git a/examples/step-63/block_sor.prm b/examples/step-63/block_sor.prm index f5991834c4a5..375e7e63cb32 100644 --- a/examples/step-63/block_sor.prm +++ b/examples/step-63/block_sor.prm @@ -1,14 +1,14 @@ # Finite Element degree -set fe degree = 1 +set Fe degree = 1 -# Smoother Type: sor|jacobi|block sor|block jacobi -set smoother type = block sor +# Smoother Type: SOR|Jacobi|block SOR|block Jacobi +set Smoother type = block SOR -# Dof renumbering: none|random|downstream|upstream -set dof renumbering = downstream +# DoF renumbering: no|downstream|upstream|random +set DoF renumbering = downstream # With streamline diffusion: true|false -set with sd = true +set With streamline diffusion = true # Output: true|false -set output = false +set Output = false \ No newline at end of file diff --git a/examples/step-63/jacobi.prm b/examples/step-63/jacobi.prm index d6a55ff53b93..4c7365e06a7d 100644 --- a/examples/step-63/jacobi.prm +++ b/examples/step-63/jacobi.prm @@ -1,14 +1,14 @@ # Finite Element degree -set fe degree = 1 +set Fe degree = 1 -# Smoother Type: sor|jacobi|block sor|block jacobi -set smoother type = jacobi +# Smoother Type: SOR|Jacobi|block SOR|block Jacobi +set Smoother type = Jacobi -# Dof renumbering: no|random|downstream|upstream -set dof renumbering = downstream +# DoF renumbering: no|downstream|upstream|random +set DoF renumbering = downstream # With streamline diffusion: true|false -set with sd = true +set With streamline diffusion = true # Output: true|false -set output = false +set Output = false \ No newline at end of file diff --git a/examples/step-63/sor.prm b/examples/step-63/sor.prm index 47ab13c3d5b3..dbdc74c19810 100644 --- a/examples/step-63/sor.prm +++ b/examples/step-63/sor.prm @@ -1,15 +1,14 @@ # Finite Element degree -set fe degree = 1 +set Fe degree = 1 -# Smoother Type: sor|jacobi|block sor|block jacobi -set smoother type = sor - -# Dof renumbering: no|random|downstream|upstream -set dof renumbering = downstream +# 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 sd = true +set With streamline diffusion = true # Output: true|false -set output = 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 index dcfcd1fa54ec..3f9717ec8964 100644 --- a/examples/step-63/step-63.cc +++ b/examples/step-63/step-63.cc @@ -66,19 +66,12 @@ #include #include - - #include #include +#include - -#include -#include - - - -namespace Step100 +namespace Step63 { using namespace dealii; @@ -103,8 +96,13 @@ namespace Step100 FEValues fe_values; }; + + + struct CopyData { + CopyData() = default; + unsigned int level; unsigned int dofs_per_cell; @@ -116,38 +114,51 @@ namespace Step100 struct Settings { - bool try_parse(const std::string &prm_filename); + enum DoFRenumberingStrategy + { + none, + downstream, + upstream, + random + }; - unsigned int fe_degree; - std::string smoother_type; - std::string dof_renum; - bool with_sd; - bool output; - }; + bool get_parameters(const std::string &prm_filename); + unsigned int fe_degree; + std::string smoother_type; + DoFRenumberingStrategy dof_renumbering; + bool with_streamline_diffusion; + bool output; + }; - bool Settings::try_parse(const std::string &prm_filename) + bool Settings::get_parameters(const std::string &prm_filename) { + if (prm_filename.size() == 0) + { + std::cerr << "Usage: please pass a .prm file as the first argument" + << std::endl; + return false; + } + ParameterHandler prm; - prm.declare_entry("fe degree", + 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", + 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|random|downstream|upstream"), - "Dof renumbering: none|random|downstream|upstream"); - prm.declare_entry("with sd", + 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", + prm.declare_entry("Output","true", Patterns::Bool(), "Generate graphical output: true|false"); @@ -157,183 +168,155 @@ namespace Step100 } catch (const dealii::PathSearch::ExcFileNotFound &) { - if (prm_filename.size() > 0) - std::cerr << "ERRROR: could not open the .prm file '" << prm_filename - << "'" << std::endl; - else - std::cerr << "Usage: please pass a .prm file as the first argument" - << std::endl; + std::cerr << "ERROR: could not parse input from given .prm file" + << prm_filename << "'" << std::endl; prm.print_parameters(std::cout, ParameterHandler::Text); return false; } - this->fe_degree = prm.get_integer("fe degree"); - this->smoother_type = prm.get("smoother type"); - this->dof_renum = prm.get("dof renumbering"); - this->with_sd = prm.get_bool("with sd"); - this->output = prm.get_bool("output"); - return true; - } + 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"); - namespace - { - template - struct CompareDownstream - { - /** - * Constructor. - */ - CompareDownstream(const Tensor<1, dim> &dir) - : dir(dir) - {} - /** - * Return true if c1 less c2. - */ - bool operator()(const Iterator &c1, const Iterator &c2) const - { - const Tensor<1, dim> diff = c2->center() - c1->center(); - return (diff * dir > 0); - } + return true; + } - private: - /** - * Flow direction. - */ - const Tensor<1, dim> dir; - }; - // Functions for creating permutation of cells for output and Block - // smoothers - template - std::vector - create_downstream_order(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 CompareDownstream::level_cell_iterator, - dim> + // 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); + 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::sort(ordered_cells.begin(), ordered_cells.end(), comparator); - std::vector ordered_indices; - ordered_indices.reserve(dof.get_triangulation().n_cells(level)); + 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()); + for (unsigned int i = 0; i < ordered_cells.size(); ++i) + ordered_indices.push_back(ordered_cells[i]->index()); - return ordered_indices; - } + return ordered_indices; + } - template - std::vector - create_downstream_order(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 CompareDownstream::active_cell_iterator, - dim> + 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); + 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::sort(ordered_cells.begin(), ordered_cells.end(), comparator); - std::vector ordered_indices; - ordered_indices.reserve(dof.get_triangulation().n_active_cells()); + 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()); + for (unsigned int i = 0; i < ordered_cells.size(); ++i) + ordered_indices.push_back(ordered_cells[i]->index()); - return ordered_indices; - } + return ordered_indices; + } - template - std::vector create_random_order(const DoFHandler &dof, - const unsigned int level) - { - const unsigned int n_cells = dof.get_triangulation().n_cells(level); + 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); + 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()); + 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; the following is essentially std::shuffle (which - // is new in C++11) but with a boost URNG - ::boost::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 = - ::boost::random::uniform_int_distribution<>(0, i)( - random_number_generator); - - // if possible, swap the elements - if (i != j) - std::swap(ordered_cells[i], ordered_cells[j]); - } + // 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); - return ordered_cells; - } + // if possible, swap the elements + if (i != j) + std::swap(ordered_cells[i], ordered_cells[j]); + } - template - std::vector create_random_order(const DoFHandler &dof) - { - const unsigned int n_cells = dof.get_triangulation().n_active_cells(); + return ordered_cells; + } - std::vector ordered_cells; - ordered_cells.reserve(n_cells); + template + std::vector + create_random_cell_ordering(const DoFHandler &dof) + { + const unsigned int n_cells = dof.get_triangulation().n_active_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()); + std::vector ordered_cells; + ordered_cells.reserve(n_cells); - // shuffle the elements; the following is essentially std::shuffle (which - // is new in C++11) but with a boost URNG - ::boost::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 = - ::boost::random::uniform_int_distribution<>(0, i)( - random_number_generator); - - // if possible, swap the elements - if (i != j) - std::swap(ordered_cells[i], ordered_cells[j]); - } + 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()); - return ordered_cells; - } + // 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); - } // namespace + // if possible, swap the elements + if (i != j) + std::swap(ordered_cells[i], ordered_cells[j]); + } + + return ordered_cells; + } - // RHS and boundary is an adaptation from one in - // Finite Elements and Fast Iterative Solvers: with Applications - // in Incompressible Fluid Dynamics template class RightHandSide : public Function { @@ -348,9 +331,6 @@ namespace Step100 virtual void value_list(const std::vector> &points, std::vector & values, const unsigned int component = 0) const; - - private: - static const Point center_point; }; template @@ -440,15 +420,15 @@ namespace Step100 } template - double delta_value(const double hk, - const double eps, - const Tensor<1, dim> dir, - const double pk) + 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' - double Peclet = dir.norm() * hk / (2.0 * eps * pk); - double coth = + 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); @@ -480,9 +460,8 @@ namespace Step100 Triangulation triangulation; DoFHandler dof_handler; - FE_Q fe; - MappingQ mapping; - unsigned int quad_degree; + const FE_Q fe; + const MappingQ mapping; AffineConstraints constraints; @@ -499,11 +478,17 @@ namespace Step100 MGLevelObject> mg_interface_in; MGLevelObject> mg_interface_out; + mg::Matrix> mg_matrix; + mg::Matrix> mg_interface_matrix_in; + mg::Matrix> mg_interface_matrix_out; + + MGConstrainedDoFs mg_constrained_dofs; - Settings settings; const double epsilon; Tensor<1, dim> advection_direction; + + const Settings settings; }; @@ -514,13 +499,9 @@ namespace Step100 , dof_handler(triangulation) , fe(settings.fe_degree) , mapping(settings.fe_degree) - , quad_degree(2 * fe.degree + 2) - , settings(settings) , epsilon(0.005) + , settings(settings) { - // Set Advection direction (problem is an adaptation from one in - // Finite Elements and Fast Iterative Solvers: with Applications - // in Incompressible Fluid Dynamics) advection_direction[0] = -std::sin(numbers::PI / 6.0); if (dim > 1) advection_direction[1] = std::cos(numbers::PI / 6.0); @@ -571,13 +552,18 @@ namespace Step100 // 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.smoother_type == "SOR" || settings.smoother_type == "Jacobi") { - if (settings.dof_renum == "downstream" || - settings.dof_renum == "upstream") + if (settings.dof_renumbering == + Settings::DoFRenumberingStrategy::downstream || + settings.dof_renumbering == + Settings::DoFRenumberingStrategy::upstream) { const Tensor<1, dim> direction = - (settings.dof_renum == "upstream" ? -1.0 : 1.0) * + (settings.dof_renumbering == + Settings::DoFRenumberingStrategy::upstream ? + -1.0 : + 1.0) * advection_direction; for (unsigned int level = 0; level < n_levels; ++level) @@ -586,7 +572,8 @@ namespace Step100 direction, /*dof_wise_renumbering = */ true); } - else if (settings.dof_renum == "random") + else if (settings.dof_renumbering == + Settings::DoFRenumberingStrategy::random) { for (unsigned int level = 0; level < n_levels; ++level) DoFRenumbering::random(dof_handler, level); @@ -598,9 +585,7 @@ namespace Step100 mg_constrained_dofs.clear(); mg_constrained_dofs.initialize(dof_handler); - std::set dirichlet_boundary_ids = {0, 1}; - mg_constrained_dofs.make_zero_boundary_constraints(dof_handler, - dirichlet_boundary_ids); + mg_constrained_dofs.make_zero_boundary_constraints(dof_handler, {0, 1}); mg_matrices.resize(0, n_levels - 1); mg_matrices.clear_elements(); @@ -650,12 +635,12 @@ namespace Step100 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(); - copy_data.cell_matrix.reinit(dofs_per_cell, dofs_per_cell); - if (!cell->is_level_cell()) + if (cell->is_level_cell() == false) copy_data.cell_rhs.reinit(dofs_per_cell); copy_data.local_dof_indices.resize(dofs_per_cell); @@ -669,11 +654,11 @@ namespace Step100 right_hand_side.value_list(scratch_data.fe_values.get_quadrature_points(), rhs_values); - const double delta = settings.with_sd ? delta_value(cell->diameter(), - epsilon, - advection_direction, - settings.fe_degree) : - 0.0; + 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) @@ -689,7 +674,7 @@ namespace Step100 scratch_data.fe_values.shape_value(i, q_point)) * scratch_data.fe_values.JxW(q_point); - if (settings.with_sd) + if (settings.with_streamline_diffusion) copy_data.cell_matrix(i, j) += delta * (advection_direction * @@ -703,12 +688,12 @@ namespace Step100 scratch_data.fe_values.shape_grad(i, q_point)) * scratch_data.fe_values.JxW(q_point); } - if (!cell->is_level_cell()) + 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_sd) + 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) * @@ -743,7 +728,7 @@ namespace Step100 dof_handler.end(), cell_worker_active, copier_active, - ScratchData(fe, quad_degree), + ScratchData(fe, fe.degree + 1), CopyData(), MeshWorker::assemble_own_cells); @@ -754,11 +739,10 @@ namespace Step100 for (unsigned int level = 0; level < triangulation.n_global_levels(); ++level) { - IndexSet dofset; - DoFTools::extract_locally_relevant_level_dofs(dof_handler, - level, - dofset); - boundary_constraints[level].reinit(dofset); + 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( @@ -804,7 +788,7 @@ namespace Step100 dof_handler.end_mg(), cell_worker_mg, copier_mg, - ScratchData(fe, quad_degree), + ScratchData(fe, fe.degree + 1), CopyData(), MeshWorker::assemble_own_cells); } @@ -814,9 +798,9 @@ namespace Step100 std::unique_ptr>> AdvectionProblem::create_smoother() { - if (settings.smoother_type == "sor") + if (settings.smoother_type == "SOR") { - typedef PreconditionSOR> Smoother; + using Smoother = PreconditionSOR>; auto smoother = std_cxx14::make_unique, @@ -828,10 +812,10 @@ namespace Step100 smoother->set_steps(2); return smoother; } - else if (settings.smoother_type == "jacobi") + else if (settings.smoother_type == "Jacobi") { - typedef PreconditionJacobi> Smoother; - auto smoother = + using Smoother = PreconditionJacobi>; + auto smoother = std_cxx14::make_unique, Smoother, Vector>>(); @@ -841,11 +825,12 @@ namespace Step100 smoother->set_steps(4); return smoother; } - else if (settings.smoother_type == "block sor") + else if (settings.smoother_type == "block SOR") { - typedef RelaxationBlockSOR, double, Vector> - Smoother; + using Smoother = + RelaxationBlockSOR, double, Vector>; + // TODO: try and remove static static MGLevelObject smoother_data; smoother_data.resize(0, triangulation.n_levels() - 1); @@ -859,23 +844,34 @@ namespace Step100 smoother_data[level].inversion = PreconditionBlockBase::svd; std::vector ordered_indices; - if (settings.dof_renum == "downstream") - ordered_indices = create_downstream_order(dof_handler, - advection_direction, - level); - else if (settings.dof_renum == "upstream") - ordered_indices = - create_downstream_order(dof_handler, - -1.0 * advection_direction, - level); - else if (settings.dof_renum == "random") - ordered_indices = create_random_order(dof_handler, level); - else if (settings.dof_renum == "none") + switch (settings.dof_renumbering) { - // Do nothing + 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; } - else - AssertThrow(false, ExcNotImplemented()); smoother_data[level].order = std::vector>(1, ordered_indices); @@ -889,13 +885,12 @@ namespace Step100 smoother->set_steps(1); return smoother; } - else if (settings.smoother_type == "block jacobi") + else if (settings.smoother_type == "block Jacobi") { - typedef RelaxationBlockJacobi, - double, - Vector> - Smoother; + using Smoother = + RelaxationBlockJacobi, double, Vector>; + // TODO: try and remove static static MGLevelObject smoother_data; smoother_data.resize(0, triangulation.n_levels() - 1); @@ -909,23 +904,34 @@ namespace Step100 smoother_data[level].inversion = PreconditionBlockBase::svd; std::vector ordered_indices; - if (settings.dof_renum == "downstream") - ordered_indices = create_downstream_order(dof_handler, - advection_direction, - level); - else if (settings.dof_renum == "upstream") - ordered_indices = - create_downstream_order(dof_handler, - -1.0 * advection_direction, - level); - else if (settings.dof_renum == "random") - ordered_indices = create_random_order(dof_handler, level); - else if (settings.dof_renum == "none") + switch (settings.dof_renumbering) { - // Do nothing + 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; } - else - AssertThrow(false, ExcNotImplemented()); smoother_data[level].order = std::vector>(1, ordered_indices); @@ -947,15 +953,13 @@ namespace Step100 template void AdvectionProblem::solve() { - Timer time; - - const double solve_tol = 1e-8 * system_rhs.l2_norm(); - const unsigned int max_iters = 200; - SolverControl solver_control(max_iters, solve_tol, true, true); + 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(); - typedef MGTransferPrebuilt> Transfer; - Transfer mg_transfer(mg_constrained_dofs); + using Transfer = MGTransferPrebuilt>; + Transfer mg_transfer(mg_constrained_dofs); mg_transfer.build_matrices(dof_handler); FullMatrix coarse_matrix; @@ -963,11 +967,12 @@ namespace Step100 MGCoarseGridHouseholder> coarse_grid_solver; coarse_grid_solver.initialize(coarse_matrix); - std::unique_ptr>> mg_smoother = create_smoother(); + const std::unique_ptr>> mg_smoother = + create_smoother(); - mg::Matrix> mg_matrix(mg_matrices); - mg::Matrix> mg_interface_matrix_in(mg_interface_in); - mg::Matrix> mg_interface_matrix_out(mg_interface_out); + 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); @@ -977,12 +982,12 @@ namespace Step100 mg, mg_transfer); - - std::cout << " Solving with GMRES to tol " << solve_tol << "..." + std::cout << " Solving with GMRES to tol " << solve_tolerance << "..." << std::endl; SolverGMRES<> solver(solver_control); - time.restart(); + Timer time; + time.start(); solver.solve(system_matrix, solution, system_rhs, preconditioner); time.stop(); @@ -998,10 +1003,6 @@ namespace Step100 template void AdvectionProblem::output_results(const unsigned int cycle) const { - DataOut data_out; - data_out.attach_dof_handler(dof_handler); - data_out.add_data_vector(solution, "solution"); - // 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 @@ -1011,40 +1012,46 @@ namespace Step100 // 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; - if (settings.dof_renum == "downstream") + switch (settings.dof_renumbering) { - ordered_indices = - create_downstream_order(dof_handler, advection_direction); + 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; } - else if (settings.dof_renum == "upstream") - { - ordered_indices = - create_downstream_order(dof_handler, -1.0 * advection_direction); - } - else if (settings.dof_renum == "random") - { - ordered_indices = create_random_order(dof_handler); - } - else if (settings.dof_renum == "none") - { - ordered_indices.resize(n_active_cells); - for (unsigned int i = 0; i < n_active_cells; ++i) - ordered_indices[i] = i; - } - else - AssertThrow(false, ExcNotImplemented()); // 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 = @@ -1091,18 +1098,19 @@ namespace Step100 std::cout << std::endl; } } -} // namespace Step100 +} // namespace Step63 + int main(int argc, char *argv[]) { try { - Step100::Settings settings; - if (!settings.try_parse((argc > 1) ? (argv[1]) : "")) + Step63::Settings settings; + if (!settings.get_parameters((argc > 1) ? (argv[1]) : "")) return 0; - Step100::AdvectionProblem<2> advection_problem_2d(settings); + Step63::AdvectionProblem<2> advection_problem_2d(settings); advection_problem_2d.run(); } catch (std::exception &exc) From 085943837d1fd596249085a0343219de30ef1ed1 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Fri, 5 Apr 2019 19:36:52 +0200 Subject: [PATCH 374/507] Fixed documentation. --- include/deal.II/algorithms/general_data_storage.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/deal.II/algorithms/general_data_storage.h b/include/deal.II/algorithms/general_data_storage.h index ed2905776161..30228b9ffa8d 100644 --- a/include/deal.II/algorithms/general_data_storage.h +++ b/include/deal.II/algorithms/general_data_storage.h @@ -98,9 +98,11 @@ class GeneralDataStorage : public Subscriptor /** * Clear all data stored in this class instance. * - * After this function is called, all copied data owned by this class will - * go out of scope. Furthermore, all scoping requirements for data referenced - * by this class instance will be lifted. + * 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: * @@ -289,7 +291,7 @@ class GeneralDataStorage : public Subscriptor stores_object_with_name(const std::string &name) const; /** - * Find out if we store an object with given name. + * Remove the object with given name. */ void remove_object_with_name(const std::string &name); From d6406eedd0982dc7821c3fff5be50097f4daa441 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sun, 7 Apr 2019 08:40:37 +0200 Subject: [PATCH 375/507] Add alternative test output --- .../general_data_storage_01.debug.output.2 | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 tests/algorithms/general_data_storage_01.debug.output.2 diff --git a/tests/algorithms/general_data_storage_01.debug.output.2 b/tests/algorithms/general_data_storage_01.debug.output.2 new file mode 100644 index 000000000000..50b2af1bbd66 --- /dev/null +++ b/tests/algorithms/general_data_storage_01.debug.output.2 @@ -0,0 +1,74 @@ + +DEAL::Add by copy +DEAL::Size: 2 +DEAL::Add by reference +DEAL::Size: 2 +DEAL::Add or construct +DEAL::Size: 1 +DEAL::Merge +DEAL::Data pre-merge: +DEAL::value double +DEAL::Size: 1 +DEAL::Data 2 pre-merge: +DEAL::value double +DEAL::value_2 double +DEAL::Size: 2 +DEAL::Data post-merge: +DEAL::value double +DEAL::value_2 double +DEAL::Size: 2 +DEAL::Try to overwrite existing entry: Copy +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + void dealii::GeneralDataStorage::add_unique_copy(const string&, const Type&) [with Type = double; std::__cxx11::string = std::__cxx11::basic_string] +The violated condition was: + !stores_object_with_name(name) +Additional information: + An entry with the name value already exists. +-------------------------------------------------------- + +DEAL::Try to overwrite existing entry: Reference +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + void dealii::GeneralDataStorage::add_unique_reference(const string&, Type&) [with Type = const double; std::__cxx11::string = std::__cxx11::basic_string] +The violated condition was: + !stores_object_with_name(name) +Additional information: + An entry with the name value already exists. +-------------------------------------------------------- + +DEAL::Fetch non-existing entry +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + Type& dealii::GeneralDataStorage::get_object_with_name(const string&) [with Type = double; std::__cxx11::string = std::__cxx11::basic_string] +The violated condition was: + stores_object_with_name(name) +Additional information: + No entry with the name value exists. +-------------------------------------------------------- + +DEAL::Access removed entry (reference) +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + Type& dealii::GeneralDataStorage::get_object_with_name(const string&) [with Type = double; std::__cxx11::string = std::__cxx11::basic_string] +The violated condition was: + stores_object_with_name(name) +Additional information: + No entry with the name value exists. +-------------------------------------------------------- + +DEAL::Access removed entry (copy) +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + Type& dealii::GeneralDataStorage::get_object_with_name(const string&) [with Type = double; std::__cxx11::string = std::__cxx11::basic_string] +The violated condition was: + stores_object_with_name(name) +Additional information: + No entry with the name value exists. +-------------------------------------------------------- + From 5ddde2f9bc7638dd815ed82423ad98e053154f54 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sat, 30 Mar 2019 23:27:46 +0100 Subject: [PATCH 376/507] Add functions to perform symbolic math operations using SD::Expression --- .../changes/minor/20190330Jean-PaulPelteret | 4 + include/deal.II/differentiation/sd.h | 1 + .../differentiation/sd/symengine_math.h | 785 ++++++++++++++++++ source/differentiation/sd/CMakeLists.txt | 1 + source/differentiation/sd/symengine_math.cc | 339 ++++++++ 5 files changed, 1130 insertions(+) create mode 100644 doc/news/changes/minor/20190330Jean-PaulPelteret create mode 100644 include/deal.II/differentiation/sd/symengine_math.h create mode 100644 source/differentiation/sd/symengine_math.cc 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/include/deal.II/differentiation/sd.h b/include/deal.II/differentiation/sd.h index f2707cbfc601..0366a5fbd9c8 100644 --- a/include/deal.II/differentiation/sd.h +++ b/include/deal.II/differentiation/sd.h @@ -20,6 +20,7 @@ #ifdef DEAL_II_WITH_SYMENGINE +# include # include # include # include diff --git a/include/deal.II/differentiation/sd/symengine_math.h b/include/deal.II/differentiation/sd/symengine_math.h new file mode 100644 index 000000000000..9f18c603f924 --- /dev/null +++ b/include/deal.II/differentiation/sd/symengine_math.h @@ -0,0 +1,785 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_differentiation_sd_symengine_math_h +#define dealii_differentiation_sd_symengine_math_h + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include + +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + namespace SE = ::SymEngine; + + /** + * @name Mathematical functions + * + * It is necessary that all computed inputs to SymEngine functions are + * of type SE::RCP. So we instead simply offer a unified + * interface to Expression types and with other permutations of numbers + * we convert between them. + * + * For a full list of functions that we (ultimately) expect to support, see + * http://www.cplusplus.com/reference/cmath/. Those that are currently + * supported are extracted from symengine/{functions,pow}.h; + * symengine/type_codes.inc. + */ + + /** + * @name Power functions + */ + //@{ + + /** + * Return a symbolic number that represents a @p base value to the power of + * an @p exponent. + * + * Mimics the function std::pow(base,exponent) using the + * standard math library. + */ + Expression + pow(const Expression &base, const Expression &exponent); + + /** + * Return a symbolic number that represents a @p base value to the power of + * an @p exponent. + * + * Mimics the function std::pow(base,exponent) using the + * standard math library. + * + * This variant is used when the @p exponent is not a Expression. + */ + template ::value>::type> + Expression + pow(const Expression &base, const NumberType &exponent) + { + // Call other implementation + return pow(base, Expression(exponent)); + } + + /** + * Return a symbolic number that represents a @p base value to the power of + * an @p exponent. + * + * Mimics the function std::pow(base,exponent) using the + * standard math library. + * + * This variant is used when the @p base is not a Expression. + */ + template ::value>::type> + Expression + pow(const NumberType &base, const Expression &exponent) + { + // Call other implementation + return pow(Expression(base), exponent); + } + + /** + * Return a symbolic number that represents the square root of some value @p x. + * + * Mimics the function std::sqrt(x) using the standard math + * library. + */ + Expression + sqrt(const Expression &x); + + /** + * Return a symbolic number that represents the cubic root of some value @p x. + * + * Mimics the function std::cbrt(x) using the standard math + * library. + */ + Expression + cbrt(const Expression &x); + + /** + * Return a symbolic number that represents the Euler constant + * $e approx 2.71828$ raised to the given @p exponent. + * + * Mimics the function std::exp(exponent) using the standard + * math library. + */ + Expression + exp(const Expression &exponent); + + /** + * Return a symbolic number that represents the natural logarithm of a value @p x. + * + * Mimics the function std::log(x) using the standard math + * library. + */ + Expression + log(const Expression &x); + + /** + * Return a symbolic number that represents the logarithm of a value @p x with + * respect to a @p base number. + * + * Mimics the function std::log(x,base) using the standard + * math library. + */ + Expression + log(const Expression &x, const Expression &base); + + /** + * Return a symbolic number that represents the logarithm of a value @p x with + * respect to a @p base number. + * + * Mimics the function std::log(x,base) using the standard + * math library. + * + * This variant is used when the @p base is not a Expression. + */ + template ::value>::type> + Expression + log(const Expression &x, const NumberType &base) + { + // Call other implementation + return log(x, Expression(base)); + } + + /** + * Return a symbolic number that represents the logarithm of a value @p x with + * respect to a @p base number. + * + * Mimics the function std::log(x,base) using the standard + * math library. + * + * This variant is used when the @p value is not a Expression. + */ + template ::value>::type> + Expression + log(const NumberType &x, const Expression &base) + { + // Call other implementation + return log(Expression(x), base); + } + + /** + * Return a symbolic number that represents the base 10 logarithm of a value @p x. + * + * Mimics the function std::log10(x) using the standard math + * library. + */ + Expression + log10(const Expression &x); + + //@} + + /** + * @name Trignometric functions + */ + //@{ + + /** + * Return a symbolic number that represents the sine function with the + * given argument @p x. + * + * Mimics the function std::sin(x) using the standard math + * library. + */ + Expression + sin(const Expression &x); + + /** + * Return a symbolic number that represents the cosine function with the + * given argument @p x. + * + * Mimics the function std::cos(x) using the standard math + * library. + */ + Expression + cos(const Expression &x); + + /** + * Return a symbolic number that represents the tangent function with the + * given argument @p x. + * + * Mimics the function std::tan(x) using the standard math + * library. + */ + Expression + tan(const Expression &x); + + /** + * Return a symbolic number that represents the cosecant function with the + * given argument @p x. + * + * Mimics the function 1.0/std::sin(x) using the standard + * math library. + */ + Expression + csc(const Expression &x); + + /** + * Return a symbolic number that represents the secant function with the + * given argument @p x. + * + * Mimics the function 1.0/std::cos(x) using the standard + * math library. + */ + Expression + sec(const Expression &x); + + /** + * Return a symbolic number that represents the cotangent function with the + * given argument @p x. + * + * Mimics the function 1.0/std::tan(x) using the standard + * math library. + */ + Expression + cot(const Expression &x); + + /** + * Return a symbolic number that represents the inverse sine function with + * the + * given argument @p x. + * + * Mimics the function std::asin(x) using the standard math + * library. + */ + Expression + asin(const Expression &x); + + /** + * Return a symbolic number that represents the inverse cosine function + * with the + * given argument @p x. + * + * Mimics the function std::acos(x) using the standard math + * library. + */ + Expression + acos(const Expression &x); + + /** + * Return a symbolic number that represents the inverse tangent function + * with the + * given argument @p x. + * + * Mimics the function std::atan(x) using the standard math + * library. + */ + Expression + atan(const Expression &x); + + /** + * Return a symbolic number that represents the inverse tangent function + * with the + * given arguments @p x and @p y. + * + * Mimics the function std::atan2(y,x) using the standard + * math library. + */ + Expression + atan2(const Expression &y, const Expression &x); + + /** + * Return a symbolic number that represents the inverse tangent function + * with the + * given arguments @p x and @p y. + * + * Mimics the function std::atan2(y,x) using the standard + * math library. + * + * This variant is used when the numerator @p y is not a Expression. + */ + template ::value>::type> + Expression + atan2(const NumberType &y, const Expression &x) + { + // Call other implementation + return atan2(Expression(y), x); + } + + /** + * Return a symbolic number that represents the inverse tangent function + * with the + * given arguments @p x and @p y. + * + * Mimics the function std::atan2(y,x) using the standard + * math library. + * + * This variant is used when the denominator @p x is not a Expression. + */ + template ::value>::type> + Expression + atan2(const Expression &y, const NumberType &x) + { + // Call other implementation + return atan2(y, Expression(x)); + } + + /** + * Return a symbolic number that represents the inverse cosecant function + * with the + * given argument @p x. + * + * Mimics the function 1.0/std::asin(x) using the standard + * math library. + */ + Expression + acsc(const Expression &x); + + /** + * Return a symbolic number that represents the inverse secant function + * with the + * given argument @p x. + * + * Mimics the function 1.0/std::acos(x) using the standard + * math library. + */ + Expression + asec(const Expression &x); + + /** + * Return a symbolic number that represents the inverse cotangent function + * with the + * given argument @p x. + * + * Mimics the function 1.0/std::atan(x) using the standard + * math library. + */ + Expression + acot(const Expression &x); + + //@} + + /** + * @name Hyperbolic trignometric functions + */ + //@{ + + /** + * Return a symbolic number that represents the hyperbolic sine function + * with the + * given argument @p x. + * + * Mimics the function std::sinh(x) using the standard math + * library. + */ + Expression + sinh(const Expression &x); + + /** + * Return a symbolic number that represents the hyperbolic cosine function + * with the + * given argument @p x. + * + * Mimics the function std::cosh(x) using the standard math + * library. + */ + Expression + cosh(const Expression &x); + + /** + * Return a symbolic number that represents the hyperbolic tangent function + * with the + * given argument @p x. + * + * Mimics the function std::tanh(x) using the standard math + * library. + */ + Expression + tanh(const Expression &x); + + /** + * Return a symbolic number that represents the hyperbolic cosecant + * function with the + * given argument @p x. + * + * Mimics the function 1.0/std::sinh(x) using the standard + * math library. + */ + Expression + csch(const Expression &x); + + /** + * Return a symbolic number that represents the hyperbolic secant function + * with the + * given argument @p x. + * + * Mimics the function 1.0/std::cosh(x) using the standard + * math library. + */ + Expression + sech(const Expression &x); + + /** + * Return a symbolic number that represents the hyperbolic cotangent + * function with the + * given argument @p x. + * + * Mimics the function 1.0/std::tanh(x) using the standard + * math library. + */ + Expression + coth(const Expression &x); + + /** + * Return a symbolic number that represents the inverse hyperbolic sine + * function with the + * given argument @p x. + * + * Mimics the function std::asinh(x) using the standard math + * library. + */ + Expression + asinh(const Expression &x); + + /** + * Return a symbolic number that represents the inverse hyperbolic cosine + * function with the + * given argument @p x. + * + * Mimics the function std::acosh(x) using the standard math + * library. + */ + Expression + acosh(const Expression &x); + + /** + * Return a symbolic number that represents the inverse hyperbolic tangent + * function with the + * given argument @p x. + * + * Mimics the function std::atanh(x) using the standard math + * library. + */ + Expression + atanh(const Expression &x); + + /** + * Return a symbolic number that represents the inverse hyperbolic cosecant + * function with the + * given argument @p x. + * + * Mimics the function 1.0/std::asin(x) using the standard + * math library. + */ + Expression + acsch(const Expression &x); + + /** + * Return a symbolic number that represents the inverse hyperbolic secant + * function with the + * given argument @p x. + * + * Mimics the function 1.0/std::acos(x) using the standard + * math library. + */ + Expression + asech(const Expression &x); + + /** + * Return a symbolic number that represents the inverse hyperbolic + * cotangent function with the + * given argument @p x. + * + * Mimics the function 1.0/std::atan(x) using the standard + * math library. + */ + Expression + acoth(const Expression &x); + + //@} + + /** + * @name Other functions + */ + //@{ + + /** + * Return a symbolic number that represents the absolute value of value @p x. + * + * Mimics the function std::abs(x) using the standard math + * library. + */ + Expression + abs(const Expression &x); + + + /** + * Return a symbolic number that represents the absolute value of value @p x. + * + * Mimics the function std::fabs(x) using the standard math + * library. + */ + Expression + fabs(const Expression &x); + + + /** + * Return a symbolic number that represents the sign of value @p x. + * + * Although there is no such function in the standard library, it mimics + * the function boost::sign(x) using the + * boost math library. + */ + Expression + sign(const Expression &x); + + + /** + * Return a symbolic number that represents the @p value of the first + * argument that takes the @p sign of the second argument. + * + * Mimics the function std::copysign(value, sign) using + * the standard math library. + */ + Expression + copysign(const Expression &value, const Expression &sign); + + + /** + * Return a symbolic number that represents the floor of value @p x. + * + * Mimics the function std::floor(x) using the standard math + * library. + */ + Expression + floor(const Expression &x); + + + /** + * Return a symbolic number that represents the ceiling of value @p x. + * + * Mimics the function std::ceil(x) using the standard math + * library. + */ + Expression + ceil(const Expression &x); + + /** + * Return a symbolic number that represents the maximum of two + * values @p a and @p b. + * + * Mimics the function std::max(a,b) using the standard math + * library. + */ + Expression + max(const Expression &a, const Expression &b); + + /** + * Return a symbolic number that represents the maximum of two + * values @p a and @p b. + * + * Mimics the function std::max(a,b) using the standard math + * library. + * + * This variant is used when @p b is not a Expression. + */ + template ::value>::type> + Expression + max(const Expression &a, const NumberType &b) + { + // Call other implementation + return max(a, Expression(b)); + } + + /** + * Return a symbolic number that represents the maximum of two + * values @p a and @p b. + * + * Mimics the function std::max(a,b) using the standard math + * library. + * + * This variant is used when @p a is not a Expression. + */ + template ::value>::type> + Expression + max(const NumberType &a, const Expression &b) + { + // Call other implementation + return max(Expression(a), b); + } + + /** + * Return a symbolic number that represents the minimum of two + * values @p a and @p b. + * + * Mimics the function std::min(a,b) using the standard math + * library. + */ + Expression + min(const Expression &a, const Expression &b); + + /** + * Return a symbolic number that represents the minimum of two + * values @p a and @p b. + * + * Mimics the function std::min(a,b) using the standard math + * library. + * + * This variant is used when @p b is not a Expression. + */ + template ::value>::type> + Expression + min(const Expression &a, const NumberType &b) + { + // Call other implementation + return min(a, Expression(b)); + } + + /** + * Return a symbolic number that represents the minimum of two + * values @p a and @p b. + * + * Mimics the function std::min(a,b) using the standard math + * library. + * + * This variant is used when @p a is not a Expression. + */ + template ::value>::type> + Expression + min(const NumberType &a, const Expression &b) + { + // Call other implementation + return min(Expression(a), b); + } + + /** + * Return a symbolic number that represents error function with the + * given argument @p x. + * + * Mimics the function std::erf(x) using the standard math + * library. + */ + Expression + erf(const Expression &x); + + /** + * Return a symbolic number that represents complimentary error function + * with the given argument @p x. + * + * Mimics the function std::erfc(x) using the standard math + * library. + */ + Expression + erfc(const Expression &x); + + //@} + + } // namespace SD +} // namespace Differentiation + +DEAL_II_NAMESPACE_CLOSE + + +# ifndef DOXYGEN + +// Import math operations into standard namespace. +// This gives us the ability to use them within the Tensor class. +namespace std +{ + /** + * Expose SymEngine wrapper math functions + */ + +# define DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(func) \ + using dealii::Differentiation::SD::func; + +# define DEAL_II_EXPOSE_SYMENGINE_BINARY_MATH_FUNCTION(func) \ + using dealii::Differentiation::SD::func; + + DEAL_II_EXPOSE_SYMENGINE_BINARY_MATH_FUNCTION(pow) + DEAL_II_EXPOSE_SYMENGINE_BINARY_MATH_FUNCTION(max) + DEAL_II_EXPOSE_SYMENGINE_BINARY_MATH_FUNCTION(min) + DEAL_II_EXPOSE_SYMENGINE_BINARY_MATH_FUNCTION(copysign) + + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(exp) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(log10) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(sqrt) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(cbrt) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(erf) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(erfc) + // Note: Both unary and binary versions + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(log) + + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(abs) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(fabs) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(sign) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(floor) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(ceil) + + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(sin) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(cos) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(tan) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(csc) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(sec) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(cot) + + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(asin) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(acos) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(atan) + DEAL_II_EXPOSE_SYMENGINE_BINARY_MATH_FUNCTION(atan2) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(acsc) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(asec) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(acot) + + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(sinh) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(cosh) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(tanh) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(csch) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(sech) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(coth) + + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(asinh) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(acosh) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(atanh) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(acsch) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(asech) + DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION(acoth) + +# undef DEAL_II_EXPOSE_SYMENGINE_BINARY_MATH_FUNCTION +# undef DEAL_II_EXPOSE_SYMENGINE_UNARY_MATH_FUNCTION + +} // namespace std + +# endif // DOXYGEN + +#endif // DEAL_II_WITH_SYMENGINE + +#endif diff --git a/source/differentiation/sd/CMakeLists.txt b/source/differentiation/sd/CMakeLists.txt index f6730585d816..26920f47a919 100644 --- a/source/differentiation/sd/CMakeLists.txt +++ b/source/differentiation/sd/CMakeLists.txt @@ -16,6 +16,7 @@ INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) SET(_src + symengine_math.cc symengine_number_types.cc symengine_types.cc symengine_utilities.cc diff --git a/source/differentiation/sd/symengine_math.cc b/source/differentiation/sd/symengine_math.cc new file mode 100644 index 000000000000..0ea483a40513 --- /dev/null +++ b/source/differentiation/sd/symengine_math.cc @@ -0,0 +1,339 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +DEAL_II_DISABLE_EXTRA_DIAGNOSTICS +// Number operations +# include +# include +# include +# include +DEAL_II_ENABLE_EXTRA_DIAGNOSTICS + +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + namespace SE = ::SymEngine; + + /* --------------------------- Math functions ------------------------- */ + + Expression + pow(const Expression &base, const Expression &exponent) + { + return SE::pow(base.get_RCP(), exponent.get_RCP()); + } + + + Expression + sqrt(const Expression &x) + { + return SE::sqrt(x.get_RCP()); + } + + + Expression + cbrt(const Expression &x) + { + return SE::cbrt(x.get_RCP()); + } + + + Expression + exp(const Expression &exponent) + { + return SE::exp(exponent.get_RCP()); + } + + + Expression + log(const Expression &x) + { + return SE::log(x.get_RCP()); + } + + + Expression + log(const Expression &x, const Expression &base) + { + return SE::log(x.get_RCP(), base.get_RCP()); + } + + + Expression + log10(const Expression &x) + { + return log(x.get_RCP(), Expression(10.0)); + } + + + Expression + sin(const Expression &x) + { + return SE::sin(x.get_RCP()); + } + + + Expression + cos(const Expression &x) + { + return SE::cos(x.get_RCP()); + } + + + Expression + tan(const Expression &x) + { + return SE::tan(x.get_RCP()); + } + + + Expression + csc(const Expression &x) + { + return SE::csc(x.get_RCP()); + } + + + Expression + sec(const Expression &x) + { + return SE::sec(x.get_RCP()); + } + + + Expression + cot(const Expression &x) + { + return SE::cot(x.get_RCP()); + } + + + Expression + asin(const Expression &x) + { + return SE::asin(x.get_RCP()); + } + + + Expression + acos(const Expression &x) + { + return SE::acos(x.get_RCP()); + } + + + Expression + atan(const Expression &x) + { + return SE::atan(x.get_RCP()); + } + + + Expression + atan2(const Expression &y, const Expression &x) + { + return SE::atan2(y.get_RCP(), x.get_RCP()); + } + + + Expression + acsc(const Expression &x) + { + return SE::acsc(x.get_RCP()); + } + + + Expression + asec(const Expression &x) + { + return SE::asec(x.get_RCP()); + } + + + Expression + acot(const Expression &x) + { + return SE::acot(x.get_RCP()); + } + + + Expression + sinh(const Expression &x) + { + return SE::sinh(x.get_RCP()); + } + + + Expression + cosh(const Expression &x) + { + return SE::cosh(x.get_RCP()); + } + + + Expression + tanh(const Expression &x) + { + return SE::tanh(x.get_RCP()); + } + + + Expression + csch(const Expression &x) + { + return SE::csch(x.get_RCP()); + } + + + Expression + sech(const Expression &x) + { + return SE::sech(x.get_RCP()); + } + + + Expression + coth(const Expression &x) + { + return SE::coth(x.get_RCP()); + } + + + Expression + asinh(const Expression &x) + { + return SE::asinh(x.get_RCP()); + } + + + Expression + acosh(const Expression &x) + { + return SE::acosh(x.get_RCP()); + } + + + Expression + atanh(const Expression &x) + { + return SE::atanh(x.get_RCP()); + } + + + Expression + acsch(const Expression &x) + { + return SE::acsch(x.get_RCP()); + } + + + Expression + asech(const Expression &x) + { + return SE::asech(x.get_RCP()); + } + + + Expression + acoth(const Expression &x) + { + return SE::acoth(x.get_RCP()); + } + + + Expression + abs(const Expression &x) + { + return SE::abs(x.get_RCP()); + } + + + Expression + fabs(const Expression &x) + { + return SE::abs(x.get_RCP()); + } + + + Expression + sign(const Expression &x) + { + return SE::sign(x.get_RCP()); + } + + + Expression + copysign(const Expression &value, const Expression &sign) + { + return value * Expression(SE::sign(sign.get_RCP())); + } + + + Expression + floor(const Expression &x) + { + return SE::floor(x.get_RCP()); + } + + + Expression + ceil(const Expression &x) + { + return SE::ceiling(x.get_RCP()); + } + + + Expression + max(const Expression &a, const Expression &b) + { + return SE::max({a.get_RCP(), b.get_RCP()}); + } + + + Expression + min(const Expression &a, const Expression &b) + { + return SE::min({a.get_RCP(), b.get_RCP()}); + } + + + Expression + erf(const Expression &x) + { + return SE::erf(x.get_RCP()); + } + + + Expression + erfc(const Expression &x) + { + return SE::erfc(x.get_RCP()); + } + + } // namespace SD +} // namespace Differentiation + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE From fe78e1db653e0ce71cc18f03bfc4cb761d2179f1 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sat, 30 Mar 2019 23:27:57 +0100 Subject: [PATCH 377/507] Add test for symbolic math functions --- tests/symengine/symengine_number_type_02.cc | 492 ++++++++++++++++++ .../symengine/symengine_number_type_02.output | 300 +++++++++++ 2 files changed, 792 insertions(+) create mode 100644 tests/symengine/symengine_number_type_02.cc create mode 100644 tests/symengine/symengine_number_type_02.output diff --git a/tests/symengine/symengine_number_type_02.cc b/tests/symengine/symengine_number_type_02.cc new file mode 100644 index 000000000000..a78a3e8118cb --- /dev/null +++ b/tests/symengine/symengine_number_type_02.cc @@ -0,0 +1,492 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Check that the wrapper for symengine expressions can be used within +// math functions + +#include + +#include + +#include +#include +#include + +#include "../tests.h" + +using namespace dealii; +namespace SD = Differentiation::SD; +namespace SE = SymEngine; + +template +bool +same_number(const NumberType1 &val1, + const NumberType2 &val2, + const bool print = true, + const double tol_eps = 10.0) +{ + if (print == true) + std::cout << "Diff: " << std::abs(val1 - val2) << std::endl; + const long double eps1 = std::numeric_limits::epsilon(); + const long double eps2 = std::numeric_limits::epsilon(); + return std::abs(val1 - val2) <= tol_eps * std::max(eps1, eps2); +} + +template +void +test_number_functions() +{ + typedef SD::Expression SD_number_t; + typedef SE::RCP SE_double_t; + // typedef SD_number_t result_t; + typedef NumberType result_t; + typedef double float_result_t; + + // Primitive numbers + const NumberType x_(NumberType(2.2)); + const NumberType a_(NumberType(3.3)); + const NumberType b_(NumberType(-4.4)); + const NumberType inv_a_(NumberType(1.0 / a_)); + // Raw SymEngine number pointers + const SE_double_t x__(SE::real_double(x_)); + const SE_double_t a__(SE::real_double(a_)); + const SE_double_t b__(SE::real_double(b_)); + const SE_double_t inv_a__(SE::real_double(inv_a_)); + // Our wrapped numbers + const SD_number_t x(x_); + const SD_number_t a(a_); + const SD_number_t b(b_); + const SD_number_t inv_a(inv_a_); + + // SD_number_t f; // Temporary value; Check default constructor + // SD_number_t::substitution_map_t sub_vals; + + // --- Values --- + // NOTE: The returned results from SymEngineWrapper functions are actually + // symbolic in nature, so we cast them to the number in order to evaluate + // them. + + deallog.push("Power functions"); + { + deallog << "pow(a_,x_): " << std::pow(a_, x_) << std::endl; + deallog << "pow(a__,x__): " << *SE::pow(a__, x__) << std::endl; + deallog << "pow(a,x): " << static_cast(pow(a, x)) << std::endl; + deallog << "pow(a,x_): " << static_cast(pow(a, x_)) << std::endl; + deallog << "pow(a_,x): " << static_cast(pow(a_, x)) << std::endl; + Assert(same_number(static_cast(pow(a, x)), std::pow(a_, x_)), + ExcMessage("Incorrect result from pow function")); + // -------------- + deallog << "sqrt(a_): " << std::sqrt(a_) << std::endl; + deallog << "sqrt(a__): " << *SE::sqrt(a__) << std::endl; + deallog << "sqrt(a): " << sqrt(a) << std::endl; + deallog << "sqrt(a): " << static_cast(sqrt(a)) + << std::endl; + Assert(same_number(static_cast(sqrt(a)), std::sqrt(a_)), + ExcMessage("Incorrect result from sqrt function")); + // -------------- + deallog << "cbrt(a_): " << std::cbrt(a_) << std::endl; + deallog << "cbrt(a__): " << *SE::cbrt(a__) << std::endl; + deallog << "cbrt(a): " << cbrt(a) << std::endl; + deallog << "cbrt(a): " << static_cast(cbrt(a)) + << std::endl; + Assert(same_number(static_cast(cbrt(a)), std::cbrt(a_)), + ExcMessage("Incorrect result from cbrt function")); + // -------------- + deallog << "exp(a_): " << std::exp(a_) << std::endl; + deallog << "exp(a__): " << *SE::exp(a__) << std::endl; + deallog << "exp(a): " << exp(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "exp(a): " << static_cast(exp(a)) << std::endl; + Assert(same_number(static_cast(exp(a)), std::exp(a_)), + ExcMessage("Incorrect result from exp function")); + // -------------- + deallog << "log(a_): " << std::log(a_) << std::endl; + deallog << "log(a__): " << *SE::log(a__) << std::endl; + deallog << "log(a): " << log(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "log(a): " << static_cast(log(a)) << std::endl; + Assert(same_number(static_cast(log(a)), std::log(a_)), + ExcMessage("Incorrect result from log function")); + } + deallog.pop(); + + deallog.push("Other functions"); + { + deallog << "abs(b_): " << std::abs(b_) << std::endl; + deallog << "abs(b): " << static_cast(abs(b)) << std::endl; + Assert(same_number(static_cast(abs(b)), std::abs(b_)), + ExcMessage("Incorrect result from abs function")); + // -------------- + deallog << "copysign(1.0, b_): " << std::copysign(1.0, b_) << std::endl; + deallog << "sign(b): " << static_cast(sign(b)) << std::endl; + Assert(same_number(static_cast(sign(b)), std::copysign(1.0, b_)), + ExcMessage("Incorrect result from sign function")); + // -------------- + deallog << "copysign(a_, b_): " << std::copysign(a_, b_) << std::endl; + deallog << "copysign(a, b): " << static_cast(copysign(a, b)) + << std::endl; + Assert(same_number(static_cast(copysign(a, b)), + std::copysign(a_, b_)), + ExcMessage("Incorrect result from copysign function")); + // -------------- + deallog << "floor(b_): " << std::floor(b_) << std::endl; + deallog << "floor(b): " << static_cast(floor(b)) << std::endl; + Assert(same_number(static_cast(floor(b)), std::floor(b_)), + ExcMessage("Incorrect result from floor function")); + // -------------- + deallog << "ceil(b_): " << std::ceil(b_) << std::endl; + deallog << "ceil(b): " << static_cast(ceil(b)) << std::endl; + Assert(same_number(static_cast(ceil(b)), std::ceil(b_)), + ExcMessage("Incorrect result from ceil function")); + // -------------- + deallog << "max(a_,x_): " << std::max(a_, x_) << std::endl; + deallog << "max(a__,x__): " << *SE::max({a__, x__}) << std::endl; + deallog << "max(a,x): " << static_cast(max(a, x)) << std::endl; + deallog << "max(a,x_): " << static_cast(max(a, x_)) << std::endl; + deallog << "max(a_,x): " << static_cast(max(a_, x)) << std::endl; + Assert(same_number(static_cast(max(a, x)), std::max(a_, x_)), + ExcMessage("Incorrect result from max function")); + // -------------- + deallog << "min(a_,x_): " << std::min(a_, x_) << std::endl; + deallog << "min(a__,x__): " << *SE::min({a__, x__}) << std::endl; + deallog << "min(a,x): " << static_cast(min(a, x)) << std::endl; + deallog << "min(a,x_): " << static_cast(min(a, x_)) << std::endl; + deallog << "min(a_,x): " << static_cast(min(a_, x)) << std::endl; + Assert(same_number(static_cast(min(a, x)), std::min(a_, x_)), + ExcMessage("Incorrect result from max function")); + // -------------- + deallog << "erf(a_): " << std::erf(a_) << std::endl; + deallog << "erf(a__): " << *SE::erf(a__) << std::endl; + deallog << "erf(a): " << erf(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "erf(a): " << static_cast(erf(a)) << std::endl; + Assert(same_number(static_cast(erf(a)), std::erf(a_)), + ExcMessage("Incorrect result from erf function")); + // -------------- + deallog << "erfc(a_): " << std::erfc(a_) << std::endl; + deallog << "erfc(a__): " << *SE::erfc(a__) << std::endl; + deallog << "erfc(a): " << erfc(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "erfc(a): " << static_cast(erfc(a)) + << std::endl; + Assert(same_number(static_cast(erfc(a)), std::erfc(a_)), + ExcMessage("Incorrect result from erfc function")); + } + deallog.pop(); + + // References: + // https://en.wikipedia.org/wiki/Trigonometric_functions + // https://en.wikipedia.org/wiki/Hyperbolic_function + // http://mathworld.wolfram.com/InverseCosecant.html + deallog.push("Trig functions"); + { + deallog << "sin(a_): " << std::sin(a_) << std::endl; + deallog << "sin(a__): " << *SE::sin(a__) << std::endl; + deallog << "sin(a): " << sin(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "sin(a): " << static_cast(sin(a)) << std::endl; + Assert(same_number(static_cast(sin(a)), std::sin(a_)), + ExcMessage("Incorrect result from sin function")); + // -------------- + deallog << "cos(a_): " << std::cos(a_) << std::endl; + deallog << "cos(a__): " << *SE::cos(a__) << std::endl; + deallog << "cos(a): " << cos(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "cos(a): " << static_cast(cos(a)) << std::endl; + Assert(same_number(static_cast(cos(a)), std::cos(a_)), + ExcMessage("Incorrect result from cos function")); + // -------------- + deallog << "tan(a_): " << std::tan(a_) << std::endl; + deallog << "tan(a__): " << *SE::tan(a__) << std::endl; + deallog << "tan(a): " << tan(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "tan(a): " << static_cast(tan(a)) << std::endl; + Assert(same_number(static_cast(tan(a)), std::tan(a_)), + ExcMessage("Incorrect result from tan function")); + } + deallog.pop(); + + deallog.push("Reciprocal trig functions"); + { + deallog << "csc(a_): " << (NumberType(1.0) / std::sin(a_)) << std::endl; + deallog << "csc(a__): " << *SE::csc(a__) << std::endl; + deallog << "csc(a): " << csc(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "csc(a): " << static_cast(csc(a)) << std::endl; + Assert(same_number(static_cast(csc(a)), + (NumberType(1.0) / std::sin(a_))), + ExcMessage("Incorrect result from csc function")); + // -------------- + deallog << "sec(a_): " << (NumberType(1.0) / std::cos(a_)) << std::endl; + deallog << "sec(a__): " << *SE::sec(a__) << std::endl; + deallog << "sec(a): " << sec(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "sec(a): " << static_cast(sec(a)) << std::endl; + Assert(same_number(static_cast(sec(a)), + (NumberType(1.0) / std::cos(a_))), + ExcMessage("Incorrect result from sec function")); + // -------------- + deallog << "cot(a_): " << (NumberType(1.0) / std::tan(a_)) << std::endl; + deallog << "cot(a__): " << *SE::cot(a__) << std::endl; + deallog << "cot(a): " << cot(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "cot(a): " << static_cast(cot(a)) << std::endl; + Assert(same_number(static_cast(cot(a)), + (NumberType(1.0) / std::tan(a_))), + ExcMessage("Incorrect result from cot function")); + } + deallog.pop(); + + deallog.push("Inverse trig functions"); + { + deallog << "asin(inv_a_): " << std::asin(inv_a_) << std::endl; + deallog << "asin(inv_a__): " << *SE::asin(inv_a__) << std::endl; + deallog << "asin(inv_a): " << asin(inv_a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "asin(inv_a): " << static_cast(asin(inv_a)) + << std::endl; + Assert(same_number(static_cast(asin(inv_a)), + std::asin(inv_a_)), + ExcMessage("Incorrect result from asin function")); + // -------------- + deallog << "acos(inv_a_): " << std::acos(inv_a_) << std::endl; + deallog << "acos(inv_a__): " << *SE::acos(inv_a__) << std::endl; + deallog << "acos(inv_a): " << acos(inv_a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "acos(inv_a): " << static_cast(acos(inv_a)) + << std::endl; + Assert(same_number(static_cast(acos(inv_a)), + std::acos(inv_a_)), + ExcMessage("Incorrect result from acos function")); + // -------------- + deallog << "atan(inv_a_): " << std::atan(inv_a_) << std::endl; + deallog << "atan(inv_a__): " << *SE::atan(inv_a__) << std::endl; + deallog << "atan(inv_a): " << atan(inv_a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "atan(inv_a): " << static_cast(atan(inv_a)) + << std::endl; + Assert(same_number(static_cast(atan(inv_a)), + std::atan(inv_a_)), + ExcMessage("Incorrect result from atan function")); + // -------------- + deallog << "atan2(x_,a_): " << std::atan2(x_, a_) << std::endl; + deallog << "atan2(x__,a__): " << *SE::atan2(x__, a__) << std::endl; + deallog << "atan2(x,a): " << atan2(x, a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "atan2(x,a): " << static_cast(atan2(x, a)) + << std::endl; + Assert(same_number(static_cast(atan2(x, a)), + std::atan2(x_, a_)), + ExcMessage("Incorrect result from atan2 function")); + } + deallog.pop(); + + deallog.push("Reciprocal inverse trig functions"); + { + deallog << "acsc(a_): " << std::asin(NumberType(1.0) / a_) << std::endl; + deallog << "acsc(a__): " << *SE::acsc(a__) << std::endl; + deallog << "acsc(a): " << acsc(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "acsc(a): " << static_cast(acsc(a)) + << std::endl; + Assert(same_number(static_cast(acsc(a)), + std::asin(NumberType(1.0) / a_)), + ExcMessage("Incorrect result from acsc function")); + // -------------- + deallog << "asec(a_): " << std::acos(NumberType(1.0) / a_) << std::endl; + deallog << "asec(a__): " << *SE::asec(a__) << std::endl; + deallog << "asec(a): " << asec(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "asec(a): " << static_cast(asec(a)) + << std::endl; + Assert(same_number(static_cast(asec(a)), + std::acos(NumberType(1.0) / a_)), + ExcMessage("Incorrect result from asec function")); + // -------------- + deallog << "acot(a_): " << std::atan(NumberType(1.0) / a_) << std::endl; + deallog << "acot(a__): " << *SE::acot(a__) << std::endl; + deallog << "acot(a): " << acot(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "acot(a): " << static_cast(acot(a)) + << std::endl; + Assert(same_number(static_cast(acot(a)), + std::atan(NumberType(1.0) / a_)), + ExcMessage("Incorrect result from acot function")); + } + deallog.pop(); + + deallog.push("Hyperbolic trig functions"); + { + deallog << "sinh(a_): " << std::sinh(a_) << std::endl; + deallog << "sinh(a__): " << *SE::sinh(a__) << std::endl; + deallog << "sinh(a): " << sinh(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "sinh(a): " << static_cast(sinh(a)) + << std::endl; + Assert(same_number(static_cast(sinh(inv_a)), + std::sinh(inv_a_)), + ExcMessage("Incorrect result from sinh function")); + // -------------- + deallog << "cosh(a_): " << std::cosh(a_) << std::endl; + deallog << "cosh(a__): " << *SE::cosh(a__) << std::endl; + deallog << "cosh(a): " << cosh(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "cosh(a): " << static_cast(cosh(a)) + << std::endl; + Assert(same_number(static_cast(cosh(inv_a)), + std::cosh(inv_a_)), + ExcMessage("Incorrect result from cosh function")); + // -------------- + deallog << "tanh(a_): " << std::tanh(a_) << std::endl; + deallog << "tanh(a__): " << *SE::tanh(a__) << std::endl; + deallog << "tanh(a): " << tanh(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "tanh(a): " << static_cast(tanh(a)) + << std::endl; + Assert(same_number(static_cast(tanh(inv_a)), + std::tanh(inv_a_)), + ExcMessage("Incorrect result from tanh function")); + } + deallog.pop(); + + deallog.push("Reciprocal hyperbolic trig functions"); + { + deallog << "csch(a_): " << (NumberType(1.0) / std::sinh(a_)) << std::endl; + deallog << "csch(a__): " << *SE::csch(a__) << std::endl; + deallog << "csch(a): " << csch(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "csch(a): " << static_cast(csch(a)) + << std::endl; + Assert(same_number(static_cast(csch(a)), + (NumberType(1.0) / std::sinh(a_))), + ExcMessage("Incorrect result from csch function")); + // -------------- + deallog << "sech(a_): " << (NumberType(1.0) / std::cosh(a_)) << std::endl; + deallog << "sech(a__): " << *SE::sech(a__) << std::endl; + deallog << "sech(a): " << sech(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "sech(a): " << static_cast(sech(a)) + << std::endl; + Assert(same_number(static_cast(sech(a)), + (NumberType(1.0) / std::cosh(a_))), + ExcMessage("Incorrect result from sech function")); + // -------------- + deallog << "coth(a_): " << (NumberType(1.0) / std::tanh(a_)) << std::endl; + deallog << "coth(a__): " << *SE::coth(a__) << std::endl; + deallog << "coth(a): " << coth(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "coth(a): " << static_cast(coth(a)) + << std::endl; + Assert(same_number(static_cast(coth(a)), + (NumberType(1.0) / std::tanh(a_))), + ExcMessage("Incorrect result from coth function")); + } + deallog.pop(); + + deallog.push("Inverse hyperbolic trig functions"); + { + deallog << "asinh(inv_a_): " << std::asinh(inv_a_) << std::endl; + deallog << "asinh(inv_a__): " << *SE::asinh(inv_a__) << std::endl; + deallog << "asinh(inv_a): " << asinh(inv_a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "asinh(inv_a): " << static_cast(asinh(inv_a)) + << std::endl; + Assert(same_number(static_cast(asinh(inv_a)), + std::asinh(inv_a_)), + ExcMessage("Incorrect result from asinh function")); + // -------------- + deallog << "acosh(a_): " << std::acosh(a_) << std::endl; + deallog << "acosh(a__): " << *SE::acosh(a__) << std::endl; + deallog << "acosh(a): " << acosh(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "acosh(a): " << static_cast(acosh(a)) + << std::endl; + Assert(same_number(static_cast(acosh(a)), std::acosh(a_)), + ExcMessage("Incorrect result from acosh function")); + // -------------- + deallog << "atanh(inv_a_): " << std::atanh(inv_a_) << std::endl; + deallog << "atanh(inv_a__): " << *SE::atanh(inv_a__) << std::endl; + deallog << "atanh(inv_a): " << atanh(inv_a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "atanh(inv_a): " << static_cast(atanh(inv_a)) + << std::endl; + Assert(same_number(static_cast(atanh(inv_a)), + std::atanh(inv_a_)), + ExcMessage("Incorrect result from atanh function")); + } + deallog.pop(); + + deallog.push("Reciprocal inverse hyperbolic trig functions"); + { + deallog << "acsch(a_): " << std::asinh(NumberType(1.0) / a_) << std::endl; + deallog << "acsch(a__): " << *SE::acsch(a__) << std::endl; + deallog << "acsch(a): " << acsch(a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "acsch(a): " << static_cast(acsch(a)) + << std::endl; + Assert(same_number(static_cast(acsch(a)), + std::asinh(NumberType(1.0) / a_)), + ExcMessage("Incorrect result from acsch function")); + // -------------- + deallog << "asech(inv_a_): " << std::acosh(a_) << std::endl; + deallog << "asech(inv_a__): " << *SE::asech(inv_a__) << std::endl; + deallog << "asech(inv_a): " << asech(inv_a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "asech(inv_a): " << static_cast(asech(inv_a)) + << std::endl; + Assert(same_number(static_cast(asech(inv_a)), + std::acosh(a_)), + ExcMessage("Incorrect result from asech function")); + // -------------- + deallog << "acoth(a_): " << std::atanh(NumberType(1.0) / a_) << std::endl; + deallog << "acoth(a__): " << *SE::acoth(a__) << std::endl; + deallog << "acoth(a): " << acoth(inv_a) + << std::endl; // Returns a SymEngine function, not a number + deallog << "acoth(a): " << static_cast(acoth(a)) + << std::endl; + Assert(same_number(static_cast(acoth(a)), + std::atanh(NumberType(1.0) / a_)), + ExcMessage("Incorrect result from acoth function")); + } + deallog.pop(); +} + +int +main() +{ + initlog(); + + // Most of the functions tested return irrational values. Making a test + // work for both integer and floating point values is hard! + // deallog.push("Integer"); + // test_number_functions(); + + deallog.push("Float"); + test_number_functions(); + deallog.pop(); + + deallog.push("Double"); + test_number_functions(); + deallog.pop(); + + // Not available yet + // SymEngine::SymEngineException: Invalid Format: Expected Integer or Rational + // deallog.push("Complex double"); + // test_number_functions>(); + // deallog.pop(); + + deallog << "OK" << std::endl; +} diff --git a/tests/symengine/symengine_number_type_02.output b/tests/symengine/symengine_number_type_02.output new file mode 100644 index 000000000000..61f12a229a13 --- /dev/null +++ b/tests/symengine/symengine_number_type_02.output @@ -0,0 +1,300 @@ + +DEAL:Float:Power functions::pow(a_,x_): 13.8271 +DEAL:Float:Power functions::pow(a__,x__): 13.827086465678 +DEAL:Float:Power functions::pow(a,x): 13.8271 +DEAL:Float:Power functions::pow(a,x_): 13.8271 +DEAL:Float:Power functions::pow(a_,x): 13.8271 +DEAL:Float:Power functions::sqrt(a_): 1.81659 +DEAL:Float:Power functions::sqrt(a__): 1.81659019933398 +DEAL:Float:Power functions::sqrt(a): 1.81659019933398 +DEAL:Float:Power functions::sqrt(a): 1.81659 +DEAL:Float:Power functions::cbrt(a_): 1.48881 +DEAL:Float:Power functions::cbrt(a__): 1.48880554578294 +DEAL:Float:Power functions::cbrt(a): 1.48880554578294 +DEAL:Float:Power functions::cbrt(a): 1.48881 +DEAL:Float:Power functions::exp(a_): 27.1126 +DEAL:Float:Power functions::exp(a__): 27.1126376278265 +DEAL:Float:Power functions::exp(a): 27.1126376278265 +DEAL:Float:Power functions::exp(a): 27.1126 +DEAL:Float:Power functions::log(a_): 1.19392 +DEAL:Float:Power functions::log(a__): 1.19392245402282 +DEAL:Float:Power functions::log(a): 1.19392245402282 +DEAL:Float:Power functions::log(a): 1.19392 +DEAL:Float:Other functions::abs(b_): 4.40000 +DEAL:Float:Other functions::abs(b): 4.40000 +DEAL:Float:Other functions::copysign(1.0, b_): -1.00000 +DEAL:Float:Other functions::sign(b): -1.00000 +DEAL:Float:Other functions::copysign(a_, b_): -3.30000 +DEAL:Float:Other functions::copysign(a, b): -3.30000 +DEAL:Float:Other functions::floor(b_): -5.00000 +DEAL:Float:Other functions::floor(b): -5.00000 +DEAL:Float:Other functions::ceil(b_): -4.00000 +DEAL:Float:Other functions::ceil(b): -4.00000 +DEAL:Float:Other functions::max(a_,x_): 3.30000 +DEAL:Float:Other functions::max(a__,x__): 3.29999995231628 +DEAL:Float:Other functions::max(a,x): 3.30000 +DEAL:Float:Other functions::max(a,x_): 3.30000 +DEAL:Float:Other functions::max(a_,x): 3.30000 +DEAL:Float:Other functions::min(a_,x_): 2.20000 +DEAL:Float:Other functions::min(a__,x__): 2.20000004768372 +DEAL:Float:Other functions::min(a,x): 2.20000 +DEAL:Float:Other functions::min(a,x_): 2.20000 +DEAL:Float:Other functions::min(a_,x): 2.20000 +DEAL:Float:Other functions::erf(a_): 0.999997 +DEAL:Float:Other functions::erf(a__): 0.9999969422892 +DEAL:Float:Other functions::erf(a): 0.9999969422892 +DEAL:Float:Other functions::erf(a): 0.999997 +DEAL:Float:Other functions::erfc(a_): 3.05771e-06 +DEAL:Float:Other functions::erfc(a__): 3.05771079957068e-06 +DEAL:Float:Other functions::erfc(a): 3.05771079957068e-06 +DEAL:Float:Other functions::erfc(a): 3.05771e-06 +DEAL:Float:Trig functions::sin(a_): -0.157746 +DEAL:Float:Trig functions::sin(a__): -0.157745647056543 +DEAL:Float:Trig functions::sin(a): -0.157745647056543 +DEAL:Float:Trig functions::sin(a): -0.157746 +DEAL:Float:Trig functions::cos(a_): -0.987480 +DEAL:Float:Trig functions::cos(a__): -0.987479777430765 +DEAL:Float:Trig functions::cos(a): -0.987479777430765 +DEAL:Float:Trig functions::cos(a): -0.987480 +DEAL:Float:Trig functions::tan(a_): 0.159746 +DEAL:Float:Trig functions::tan(a__): 0.15974569875949 +DEAL:Float:Trig functions::tan(a): 0.15974569875949 +DEAL:Float:Trig functions::tan(a): 0.159746 +DEAL:Float:Reciprocal trig functions::csc(a_): -6.33932 +DEAL:Float:Reciprocal trig functions::csc(a__): -6.33931914229971 +DEAL:Float:Reciprocal trig functions::csc(a): -6.33931914229971 +DEAL:Float:Reciprocal trig functions::csc(a): -6.33932 +DEAL:Float:Reciprocal trig functions::sec(a_): -1.01268 +DEAL:Float:Reciprocal trig functions::sec(a__): -1.01267896604608 +DEAL:Float:Reciprocal trig functions::sec(a): -1.01267896604608 +DEAL:Float:Reciprocal trig functions::sec(a): -1.01268 +DEAL:Float:Reciprocal trig functions::cot(a_): 6.25995 +DEAL:Float:Reciprocal trig functions::cot(a__): 6.2599494557007 +DEAL:Float:Reciprocal trig functions::cot(a): 6.2599494557007 +DEAL:Float:Reciprocal trig functions::cot(a): 6.25995 +DEAL:Float:Inverse trig functions::asin(inv_a_): 0.307871 +DEAL:Float:Inverse trig functions::asin(inv_a__): 0.30787087787464 +DEAL:Float:Inverse trig functions::asin(inv_a): 0.30787087787464 +DEAL:Float:Inverse trig functions::asin(inv_a): 0.307871 +DEAL:Float:Inverse trig functions::acos(inv_a_): 1.26293 +DEAL:Float:Inverse trig functions::acos(inv_a__): 1.26292544892026 +DEAL:Float:Inverse trig functions::acos(inv_a): 1.26292544892026 +DEAL:Float:Inverse trig functions::acos(inv_a): 1.26293 +DEAL:Float:Inverse trig functions::atan(inv_a_): 0.294235 +DEAL:Float:Inverse trig functions::atan(inv_a__): 0.294234573382648 +DEAL:Float:Inverse trig functions::atan(inv_a): 0.294234573382648 +DEAL:Float:Inverse trig functions::atan(inv_a): 0.294235 +DEAL:Float:Inverse trig functions::atan2(x_,a_): 0.588003 +DEAL:Float:Inverse trig functions::atan2(x__,a__): atan2(2.20000004768372, 3.29999995231628) +DEAL:Float:Inverse trig functions::atan2(x,a): atan2(2.20000004768372, 3.29999995231628) +DEAL:Float:Inverse trig functions::atan2(x,a): 0.588003 +DEAL:Float:Reciprocal inverse trig functions::acsc(a_): 0.307871 +DEAL:Float:Reciprocal inverse trig functions::acsc(a__): 0.307870872992762 +DEAL:Float:Reciprocal inverse trig functions::acsc(a): 0.307870872992762 +DEAL:Float:Reciprocal inverse trig functions::acsc(a): 0.307871 +DEAL:Float:Reciprocal inverse trig functions::asec(a_): 1.26293 +DEAL:Float:Reciprocal inverse trig functions::asec(a__): 1.26292545380213 +DEAL:Float:Reciprocal inverse trig functions::asec(a): 1.26292545380213 +DEAL:Float:Reciprocal inverse trig functions::asec(a): 1.26293 +DEAL:Float:Reciprocal inverse trig functions::acot(a_): 0.294235 +DEAL:Float:Reciprocal inverse trig functions::acot(a__): 0.294234569121593 +DEAL:Float:Reciprocal inverse trig functions::acot(a): 0.294234569121593 +DEAL:Float:Reciprocal inverse trig functions::acot(a): 0.294235 +DEAL:Float:Hyperbolic trig functions::sinh(a_): 13.5379 +DEAL:Float:Hyperbolic trig functions::sinh(a__): 13.5378772293333 +DEAL:Float:Hyperbolic trig functions::sinh(a): 13.5378772293333 +DEAL:Float:Hyperbolic trig functions::sinh(a): 13.5379 +DEAL:Float:Hyperbolic trig functions::cosh(a_): 13.5748 +DEAL:Float:Hyperbolic trig functions::cosh(a__): 13.5747603984933 +DEAL:Float:Hyperbolic trig functions::cosh(a): 13.5747603984933 +DEAL:Float:Hyperbolic trig functions::cosh(a): 13.5748 +DEAL:Float:Hyperbolic trig functions::tanh(a_): 0.997283 +DEAL:Float:Hyperbolic trig functions::tanh(a__): 0.997282959840377 +DEAL:Float:Hyperbolic trig functions::tanh(a): 0.997282959840377 +DEAL:Float:Hyperbolic trig functions::tanh(a): 0.997283 +DEAL:Float:Reciprocal hyperbolic trig functions::csch(a_): 0.0738668 +DEAL:Float:Reciprocal hyperbolic trig functions::csch(a__): 0.0738668243964602 +DEAL:Float:Reciprocal hyperbolic trig functions::csch(a): 0.0738668243964602 +DEAL:Float:Reciprocal hyperbolic trig functions::csch(a): 0.0738668 +DEAL:Float:Reciprocal hyperbolic trig functions::sech(a_): 0.0736661 +DEAL:Float:Reciprocal hyperbolic trig functions::sech(a__): 0.0736661252681112 +DEAL:Float:Reciprocal hyperbolic trig functions::sech(a): 0.0736661252681112 +DEAL:Float:Reciprocal hyperbolic trig functions::sech(a): 0.0736661 +DEAL:Float:Reciprocal hyperbolic trig functions::coth(a_): 1.00272 +DEAL:Float:Reciprocal hyperbolic trig functions::coth(a__): 1.00272444257952 +DEAL:Float:Reciprocal hyperbolic trig functions::coth(a): 1.00272444257952 +DEAL:Float:Reciprocal hyperbolic trig functions::coth(a): 1.00272 +DEAL:Float:Inverse hyperbolic trig functions::asinh(inv_a_): 0.298574 +DEAL:Float:Inverse hyperbolic trig functions::asinh(inv_a__): 0.298574346656372 +DEAL:Float:Inverse hyperbolic trig functions::asinh(inv_a): 0.298574346656372 +DEAL:Float:Inverse hyperbolic trig functions::asinh(inv_a): 0.298574 +DEAL:Float:Inverse hyperbolic trig functions::acosh(a_): 1.86328 +DEAL:Float:Inverse hyperbolic trig functions::acosh(a__): 1.86327933599091 +DEAL:Float:Inverse hyperbolic trig functions::acosh(a): 1.86327933599091 +DEAL:Float:Inverse hyperbolic trig functions::acosh(a): 1.86328 +DEAL:Float:Inverse hyperbolic trig functions::atanh(inv_a_): 0.312853 +DEAL:Float:Inverse hyperbolic trig functions::atanh(inv_a__): 0.312852959826358 +DEAL:Float:Inverse hyperbolic trig functions::atanh(inv_a): 0.312852959826358 +DEAL:Float:Inverse hyperbolic trig functions::atanh(inv_a): 0.312853 +DEAL:Float:Reciprocal inverse hyperbolic trig functions::acsch(a_): 0.298574 +DEAL:Float:Reciprocal inverse hyperbolic trig functions::acsch(a__): 0.298574342203972 +DEAL:Float:Reciprocal inverse hyperbolic trig functions::acsch(a): 0.298574342203972 +DEAL:Float:Reciprocal inverse hyperbolic trig functions::acsch(a): 0.298574 +DEAL:Float:Reciprocal inverse hyperbolic trig functions::asech(inv_a_): 1.86328 +DEAL:Float:Reciprocal inverse hyperbolic trig functions::asech(inv_a__): 1.86327931988071 +DEAL:Float:Reciprocal inverse hyperbolic trig functions::asech(inv_a): 1.86327931988071 +DEAL:Float:Reciprocal inverse hyperbolic trig functions::asech(inv_a): 1.86328 +DEAL:Float:Reciprocal inverse hyperbolic trig functions::acoth(a_): 0.312853 +DEAL:Float:Reciprocal inverse hyperbolic trig functions::acoth(a__): 0.312852954703614 +DEAL:Float:Reciprocal inverse hyperbolic trig functions::acoth(a): 0.312852959826358 + 1.5707963267949*I +DEAL:Float:Reciprocal inverse hyperbolic trig functions::acoth(a): 0.312853 +DEAL:Double:Power functions::pow(a_,x_): 13.8271 +DEAL:Double:Power functions::pow(a__,x__): 13.8270861180441 +DEAL:Double:Power functions::pow(a,x): 13.8271 +DEAL:Double:Power functions::pow(a,x_): 13.8271 +DEAL:Double:Power functions::pow(a_,x): 13.8271 +DEAL:Double:Power functions::sqrt(a_): 1.81659 +DEAL:Double:Power functions::sqrt(a__): 1.81659021245849 +DEAL:Double:Power functions::sqrt(a): 1.81659021245849 +DEAL:Double:Power functions::sqrt(a): 1.81659 +DEAL:Double:Power functions::cbrt(a_): 1.48881 +DEAL:Double:Power functions::cbrt(a__): 1.48880555295383 +DEAL:Double:Power functions::cbrt(a): 1.48880555295383 +DEAL:Double:Power functions::cbrt(a): 1.48881 +DEAL:Double:Power functions::exp(a_): 27.1126 +DEAL:Double:Power functions::exp(a__): 27.1126389206579 +DEAL:Double:Power functions::exp(a): 27.1126389206579 +DEAL:Double:Power functions::exp(a): 27.1126 +DEAL:Double:Power functions::log(a_): 1.19392 +DEAL:Double:Power functions::log(a__): 1.19392246847243 +DEAL:Double:Power functions::log(a): 1.19392246847243 +DEAL:Double:Power functions::log(a): 1.19392 +DEAL:Double:Other functions::abs(b_): 4.40000 +DEAL:Double:Other functions::abs(b): 4.40000 +DEAL:Double:Other functions::copysign(1.0, b_): -1.00000 +DEAL:Double:Other functions::sign(b): -1.00000 +DEAL:Double:Other functions::copysign(a_, b_): -3.30000 +DEAL:Double:Other functions::copysign(a, b): -3.30000 +DEAL:Double:Other functions::floor(b_): -5.00000 +DEAL:Double:Other functions::floor(b): -5.00000 +DEAL:Double:Other functions::ceil(b_): -4.00000 +DEAL:Double:Other functions::ceil(b): -4.00000 +DEAL:Double:Other functions::max(a_,x_): 3.30000 +DEAL:Double:Other functions::max(a__,x__): 3.3 +DEAL:Double:Other functions::max(a,x): 3.30000 +DEAL:Double:Other functions::max(a,x_): 3.30000 +DEAL:Double:Other functions::max(a_,x): 3.30000 +DEAL:Double:Other functions::min(a_,x_): 2.20000 +DEAL:Double:Other functions::min(a__,x__): 2.2 +DEAL:Double:Other functions::min(a,x): 2.20000 +DEAL:Double:Other functions::min(a,x_): 2.20000 +DEAL:Double:Other functions::min(a_,x): 2.20000 +DEAL:Double:Other functions::erf(a_): 0.999997 +DEAL:Double:Other functions::erf(a__): 0.999996942290204 +DEAL:Double:Other functions::erf(a): 0.999996942290204 +DEAL:Double:Other functions::erf(a): 0.999997 +DEAL:Double:Other functions::erfc(a_): 3.05771e-06 +DEAL:Double:Other functions::erfc(a__): 3.05770979643816e-06 +DEAL:Double:Other functions::erfc(a): 3.05770979643816e-06 +DEAL:Double:Other functions::erfc(a): 3.05771e-06 +DEAL:Double:Trig functions::sin(a_): -0.157746 +DEAL:Double:Trig functions::sin(a__): -0.157745694143248 +DEAL:Double:Trig functions::sin(a): -0.157745694143248 +DEAL:Double:Trig functions::sin(a): -0.157746 +DEAL:Double:Trig functions::cos(a_): -0.987480 +DEAL:Double:Trig functions::cos(a__): -0.987479769908865 +DEAL:Double:Trig functions::cos(a): -0.987479769908865 +DEAL:Double:Trig functions::cos(a): -0.987480 +DEAL:Double:Trig functions::tan(a_): 0.159746 +DEAL:Double:Trig functions::tan(a__): 0.159745747660032 +DEAL:Double:Trig functions::tan(a): 0.159745747660032 +DEAL:Double:Trig functions::tan(a): 0.159746 +DEAL:Double:Reciprocal trig functions::csc(a_): -6.33932 +DEAL:Double:Reciprocal trig functions::csc(a__): -6.33931725002842 +DEAL:Double:Reciprocal trig functions::csc(a): -6.33931725002842 +DEAL:Double:Reciprocal trig functions::csc(a): -6.33932 +DEAL:Double:Reciprocal trig functions::sec(a_): -1.01268 +DEAL:Double:Reciprocal trig functions::sec(a__): -1.01267897375993 +DEAL:Double:Reciprocal trig functions::sec(a): -1.01267897375993 +DEAL:Double:Reciprocal trig functions::sec(a): -1.01268 +DEAL:Double:Reciprocal trig functions::cot(a_): 6.25995 +DEAL:Double:Reciprocal trig functions::cot(a__): 6.25994753943736 +DEAL:Double:Reciprocal trig functions::cot(a): 6.25994753943736 +DEAL:Double:Reciprocal trig functions::cot(a): 6.25995 +DEAL:Double:Inverse trig functions::asin(inv_a_): 0.307871 +DEAL:Double:Inverse trig functions::asin(inv_a__): 0.307870868398053 +DEAL:Double:Inverse trig functions::asin(inv_a): 0.307870868398053 +DEAL:Double:Inverse trig functions::asin(inv_a): 0.307871 +DEAL:Double:Inverse trig functions::acos(inv_a_): 1.26293 +DEAL:Double:Inverse trig functions::acos(inv_a__): 1.26292545839684 +DEAL:Double:Inverse trig functions::acos(inv_a): 1.26292545839684 +DEAL:Double:Inverse trig functions::acos(inv_a): 1.26293 +DEAL:Double:Inverse trig functions::atan(inv_a_): 0.294235 +DEAL:Double:Inverse trig functions::atan(inv_a__): 0.294234565111188 +DEAL:Double:Inverse trig functions::atan(inv_a): 0.294234565111188 +DEAL:Double:Inverse trig functions::atan(inv_a): 0.294235 +DEAL:Double:Inverse trig functions::atan2(x_,a_): 0.588003 +DEAL:Double:Inverse trig functions::atan2(x__,a__): atan2(2.2, 3.3) +DEAL:Double:Inverse trig functions::atan2(x,a): atan2(2.2, 3.3) +DEAL:Double:Inverse trig functions::atan2(x,a): 0.588003 +DEAL:Double:Reciprocal inverse trig functions::acsc(a_): 0.307871 +DEAL:Double:Reciprocal inverse trig functions::acsc(a__): 0.307870868398053 +DEAL:Double:Reciprocal inverse trig functions::acsc(a): 0.307870868398053 +DEAL:Double:Reciprocal inverse trig functions::acsc(a): 0.307871 +DEAL:Double:Reciprocal inverse trig functions::asec(a_): 1.26293 +DEAL:Double:Reciprocal inverse trig functions::asec(a__): 1.26292545839684 +DEAL:Double:Reciprocal inverse trig functions::asec(a): 1.26292545839684 +DEAL:Double:Reciprocal inverse trig functions::asec(a): 1.26293 +DEAL:Double:Reciprocal inverse trig functions::acot(a_): 0.294235 +DEAL:Double:Reciprocal inverse trig functions::acot(a__): 0.294234565111188 +DEAL:Double:Reciprocal inverse trig functions::acot(a): 0.294234565111188 +DEAL:Double:Reciprocal inverse trig functions::acot(a): 0.294235 +DEAL:Double:Hyperbolic trig functions::sinh(a_): 13.5379 +DEAL:Double:Hyperbolic trig functions::sinh(a__): 13.5378778766283 +DEAL:Double:Hyperbolic trig functions::sinh(a): 13.5378778766283 +DEAL:Double:Hyperbolic trig functions::sinh(a): 13.5379 +DEAL:Double:Hyperbolic trig functions::cosh(a_): 13.5748 +DEAL:Double:Hyperbolic trig functions::cosh(a__): 13.5747610440296 +DEAL:Double:Hyperbolic trig functions::cosh(a): 13.5747610440296 +DEAL:Double:Hyperbolic trig functions::cosh(a): 13.5748 +DEAL:Double:Hyperbolic trig functions::tanh(a_): 0.997283 +DEAL:Double:Hyperbolic trig functions::tanh(a__): 0.997282960099142 +DEAL:Double:Hyperbolic trig functions::tanh(a): 0.997282960099142 +DEAL:Double:Hyperbolic trig functions::tanh(a): 0.997283 +DEAL:Double:Reciprocal hyperbolic trig functions::csch(a_): 0.0738668 +DEAL:Double:Reciprocal hyperbolic trig functions::csch(a__): 0.0738668208646195 +DEAL:Double:Reciprocal hyperbolic trig functions::csch(a): 0.0738668208646195 +DEAL:Double:Reciprocal hyperbolic trig functions::csch(a): 0.0738668 +DEAL:Double:Reciprocal hyperbolic trig functions::sech(a_): 0.0736661 +DEAL:Double:Reciprocal hyperbolic trig functions::sech(a__): 0.0736661217649808 +DEAL:Double:Reciprocal hyperbolic trig functions::sech(a): 0.0736661217649808 +DEAL:Double:Reciprocal hyperbolic trig functions::sech(a): 0.0736661 +DEAL:Double:Reciprocal hyperbolic trig functions::coth(a_): 1.00272 +DEAL:Double:Reciprocal hyperbolic trig functions::coth(a__): 1.00272444231935 +DEAL:Double:Reciprocal hyperbolic trig functions::coth(a): 1.00272444231935 +DEAL:Double:Reciprocal hyperbolic trig functions::coth(a): 1.00272 +DEAL:Double:Inverse hyperbolic trig functions::asinh(inv_a_): 0.298574 +DEAL:Double:Inverse hyperbolic trig functions::asinh(inv_a__): 0.298574338013478 +DEAL:Double:Inverse hyperbolic trig functions::asinh(inv_a): 0.298574338013478 +DEAL:Double:Inverse hyperbolic trig functions::asinh(inv_a): 0.298574 +DEAL:Double:Inverse hyperbolic trig functions::acosh(a_): 1.86328 +DEAL:Double:Inverse hyperbolic trig functions::acosh(a__): 1.86327935115345 +DEAL:Double:Inverse hyperbolic trig functions::acosh(a): 1.86327935115345 +DEAL:Double:Inverse hyperbolic trig functions::acosh(a): 1.86328 +DEAL:Double:Inverse hyperbolic trig functions::atanh(inv_a_): 0.312853 +DEAL:Double:Inverse hyperbolic trig functions::atanh(inv_a__): 0.312852949882206 +DEAL:Double:Inverse hyperbolic trig functions::atanh(inv_a): 0.312852949882206 +DEAL:Double:Inverse hyperbolic trig functions::atanh(inv_a): 0.312853 +DEAL:Double:Reciprocal inverse hyperbolic trig functions::acsch(a_): 0.298574 +DEAL:Double:Reciprocal inverse hyperbolic trig functions::acsch(a__): 0.298574338013478 +DEAL:Double:Reciprocal inverse hyperbolic trig functions::acsch(a): 0.298574338013478 +DEAL:Double:Reciprocal inverse hyperbolic trig functions::acsch(a): 0.298574 +DEAL:Double:Reciprocal inverse hyperbolic trig functions::asech(inv_a_): 1.86328 +DEAL:Double:Reciprocal inverse hyperbolic trig functions::asech(inv_a__): 1.86327935115345 +DEAL:Double:Reciprocal inverse hyperbolic trig functions::asech(inv_a): 1.86327935115345 +DEAL:Double:Reciprocal inverse hyperbolic trig functions::asech(inv_a): 1.86328 +DEAL:Double:Reciprocal inverse hyperbolic trig functions::acoth(a_): 0.312853 +DEAL:Double:Reciprocal inverse hyperbolic trig functions::acoth(a__): 0.312852949882206 +DEAL:Double:Reciprocal inverse hyperbolic trig functions::acoth(a): 0.312852949882206 + 1.5707963267949*I +DEAL:Double:Reciprocal inverse hyperbolic trig functions::acoth(a): 0.312853 +DEAL::OK From 6d1e3d8af4c25588c430fcddfeb2608747053614 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sun, 7 Apr 2019 21:47:27 +0200 Subject: [PATCH 378/507] Try to reproduce GCC tester error with ambiguous constructor --- tests/algorithms/general_data_storage_01.cc | 23 +++++++++++++++++++ .../general_data_storage_01.debug.output | 1 + .../general_data_storage_01.debug.output.2 | 1 + .../general_data_storage_01.release.output | 1 + 4 files changed, 26 insertions(+) diff --git a/tests/algorithms/general_data_storage_01.cc b/tests/algorithms/general_data_storage_01.cc index fc421e7895af..5721492f80b3 100644 --- a/tests/algorithms/general_data_storage_01.cc +++ b/tests/algorithms/general_data_storage_01.cc @@ -138,6 +138,29 @@ main() deallog << "Size: " << data.size() << std::endl; } + deallog << "Ambiguous construction" << std::endl; + { + // Pass Arguments by lvalue reference + { + const double val_1 = 1.0; + const double &val_2 = + data.get_or_add_object_with_name("value", val_1); + } + + // Pass Arguments by rvalue reference + { + double val_1 = 1.0; + const double &val_2 = + data.get_or_add_object_with_name("value", std::move(val_1)); + } + + // Pass Arguments ambiguously + { + const double &val_2 = + data.get_or_add_object_with_name("value", 1.0); + } + } + deal_II_exceptions::disable_abort_on_exception(); diff --git a/tests/algorithms/general_data_storage_01.debug.output b/tests/algorithms/general_data_storage_01.debug.output index 4583c5e2160f..0c9a8b99b98c 100644 --- a/tests/algorithms/general_data_storage_01.debug.output +++ b/tests/algorithms/general_data_storage_01.debug.output @@ -17,6 +17,7 @@ DEAL::Data post-merge: DEAL::value double DEAL::value_2 double DEAL::Size: 2 +DEAL::Ambiguous construction DEAL::Try to overwrite existing entry: Copy DEAL:: -------------------------------------------------------- diff --git a/tests/algorithms/general_data_storage_01.debug.output.2 b/tests/algorithms/general_data_storage_01.debug.output.2 index 50b2af1bbd66..f44444ad4eac 100644 --- a/tests/algorithms/general_data_storage_01.debug.output.2 +++ b/tests/algorithms/general_data_storage_01.debug.output.2 @@ -17,6 +17,7 @@ DEAL::Data post-merge: DEAL::value double DEAL::value_2 double DEAL::Size: 2 +DEAL::Ambiguous construction DEAL::Try to overwrite existing entry: Copy DEAL:: -------------------------------------------------------- diff --git a/tests/algorithms/general_data_storage_01.release.output b/tests/algorithms/general_data_storage_01.release.output index b10d09135f90..9384e0f746b8 100644 --- a/tests/algorithms/general_data_storage_01.release.output +++ b/tests/algorithms/general_data_storage_01.release.output @@ -17,6 +17,7 @@ DEAL::Data post-merge: DEAL::value double DEAL::value_2 double DEAL::Size: 2 +DEAL::Ambiguous construction DEAL::Try to overwrite existing entry: Copy DEAL::Try to overwrite existing entry: Reference DEAL::Fetch non-existing entry From 5d4698301c187af9b00387ab9b51a06128011128 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 8 Apr 2019 14:49:40 +0200 Subject: [PATCH 379/507] Require SymEngine version 0.4 --- cmake/configure/configure_symengine.cmake | 29 +++++++++++++++++++---- cmake/modules/FindSYMENGINE.cmake | 2 +- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/cmake/configure/configure_symengine.cmake b/cmake/configure/configure_symengine.cmake index 4485401c9bec..20da3601c285 100644 --- a/cmake/configure/configure_symengine.cmake +++ b/cmake/configure/configure_symengine.cmake @@ -17,11 +17,32 @@ # Configuration for the SymEngine library: # -# -# We require at least version 0.3 of the symengine library: -# -SET(SYMENGINE_MINIMUM_REQUIRED_VERSION "0.3") +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}) diff --git a/cmake/modules/FindSYMENGINE.cmake b/cmake/modules/FindSYMENGINE.cmake index 9c9dbbba071f..20b73fa50b6e 100644 --- a/cmake/modules/FindSYMENGINE.cmake +++ b/cmake/modules/FindSYMENGINE.cmake @@ -35,7 +35,7 @@ SET (DEAL_II_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) # # Include the SymEngine: # -FIND_PACKAGE(SymEngine ${SYMENGINE_MINIMUM_REQUIRED_VERSION} +FIND_PACKAGE(SymEngine CONFIG QUIET HINTS ${SYMENGINE_DIR} PATH_SUFFIXES lib/cmake/symengine From b4d6601602eec04a783924dd65123543383d523e Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Mon, 8 Apr 2019 08:01:39 -0600 Subject: [PATCH 380/507] mpi quicktests fail mpirun completes about not finding the executable. This reverts part of --- tests/quick_tests/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/quick_tests/CMakeLists.txt b/tests/quick_tests/CMakeLists.txt index ba2493fdb300..7c3023344e36 100644 --- a/tests/quick_tests/CMakeLists.txt +++ b/tests/quick_tests/CMakeLists.txt @@ -46,7 +46,11 @@ MACRO(make_quicktest test_basename build_name mpi_run) IF("${mpi_run}" STREQUAL "") SET(_command ${_target}) ELSE() - SET(_command ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${mpi_run} ${MPIEXEC_PREFLAGS} ${_target}) + IF(CMAKE_SYSTEM_NAME MATCHES "Windows") + SET(_command ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${mpi_run} ${MPIEXEC_PREFLAGS} ${_target}) + ELSE() + SET(_command ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${mpi_run} ${MPIEXEC_PREFLAGS} ./${_target}) + ENDIF() ENDIF() ADD_CUSTOM_TARGET(${_target}.run DEPENDS ${_target} From 036cb4fa105161ae5caacb5b28855ea84473b622 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 8 Apr 2019 23:19:12 +0200 Subject: [PATCH 381/507] Fix ambiguous function call --- .../deal.II/algorithms/general_data_storage.h | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/include/deal.II/algorithms/general_data_storage.h b/include/deal.II/algorithms/general_data_storage.h index 30228b9ffa8d..07d9075e60af 100644 --- a/include/deal.II/algorithms/general_data_storage.h +++ b/include/deal.II/algorithms/general_data_storage.h @@ -244,9 +244,11 @@ class GeneralDataStorage : public Subscriptor * arguments. For this function, the @p arguments are passed as * lvalue references. */ - template + template Type & - get_or_add_object_with_name(const std::string &name, Args &... arguments); + 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 @@ -258,9 +260,11 @@ class GeneralDataStorage : public Subscriptor * arguments. In contrast to the previous function of the same name, for * this function the @p arguments are passed as rvalue references. */ - template + template Type & - get_or_add_object_with_name(const std::string &name, Args &&... arguments); + get_or_add_object_with_name(const std::string &name, + Arg && argument, + Args &&... arguments); /** * Return a reference to the object with given name. @@ -443,25 +447,29 @@ GeneralDataStorage::get_object_with_name(const std::string &name) const } -template +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(arguments...)); + add_unique_copy(name, Type(argument, arguments...)); return get_object_with_name(name); } -template +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(arguments)...)); + add_unique_copy(name, + Type(std::forward(argument), + std::forward(arguments)...)); return get_object_with_name(name); } From aa543df321a53c520966486eed1483bb32da5125 Mon Sep 17 00:00:00 2001 From: Kurt Kremitzki Date: Mon, 8 Apr 2019 19:52:52 -0500 Subject: [PATCH 382/507] Update dead LICENSE link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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: -------------------- From d31a04bb005a449944114a4ec23e1e4881737e16 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 9 Apr 2019 15:03:19 +0200 Subject: [PATCH 383/507] Add overload for default constructors --- .../deal.II/algorithms/general_data_storage.h | 18 ++++++++++++++++++ tests/algorithms/general_data_storage_01.cc | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/include/deal.II/algorithms/general_data_storage.h b/include/deal.II/algorithms/general_data_storage.h index 07d9075e60af..2517b411497a 100644 --- a/include/deal.II/algorithms/general_data_storage.h +++ b/include/deal.II/algorithms/general_data_storage.h @@ -266,6 +266,13 @@ class GeneralDataStorage : public Subscriptor 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. * @@ -475,6 +482,17 @@ GeneralDataStorage::get_or_add_object_with_name(const std::string &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 diff --git a/tests/algorithms/general_data_storage_01.cc b/tests/algorithms/general_data_storage_01.cc index 5721492f80b3..483149a9b8a3 100644 --- a/tests/algorithms/general_data_storage_01.cc +++ b/tests/algorithms/general_data_storage_01.cc @@ -145,6 +145,8 @@ main() const double val_1 = 1.0; const double &val_2 = data.get_or_add_object_with_name("value", val_1); + const std::string &str = + data.get_or_add_object_with_name("empty string"); } // Pass Arguments by rvalue reference @@ -152,12 +154,16 @@ main() double val_1 = 1.0; const double &val_2 = data.get_or_add_object_with_name("value", std::move(val_1)); + const std::string &str = + data.get_or_add_object_with_name("empty string"); } // Pass Arguments ambiguously { const double &val_2 = data.get_or_add_object_with_name("value", 1.0); + const std::string &str = + data.get_or_add_object_with_name("empty string"); } } From 9c036a426574082c326a181300d71f17439cfd02 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Mon, 8 Apr 2019 08:17:43 -0600 Subject: [PATCH 384/507] [CI]: run quicktests also execute the quicktests as part of CI --- Jenkinsfile | 2 ++ contrib/ci/Jenkinsfile.osx | 1 + 2 files changed, 3 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 48064a8afb4f..4f94fc4410eb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -131,6 +131,7 @@ 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 --no-compress-output -T test ''' @@ -182,6 +183,7 @@ 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 --no-compress-output -T test ''' diff --git a/contrib/ci/Jenkinsfile.osx b/contrib/ci/Jenkinsfile.osx index c214ca0a8efa..8538cbdcdde7 100644 --- a/contrib/ci/Jenkinsfile.osx +++ b/contrib/ci/Jenkinsfile.osx @@ -94,6 +94,7 @@ pipeline -D DEAL_II_CXX_FLAGS='-Werror' \ -D CMAKE_BUILD_TYPE=Debug \ $WORKSPACE/ && make -j 4 + make test # quicktests ''' } } From 5ac43cff8e80725a5895ba5ec914c1bd4611b2f7 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Mon, 8 Apr 2019 13:25:30 -0600 Subject: [PATCH 385/507] CI: catch failures --- Jenkinsfile | 2 ++ contrib/ci/Jenkinsfile.osx | 1 + 2 files changed, 3 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 4f94fc4410eb..2f6d440b15bd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -120,6 +120,7 @@ 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 mkdir -p /home/dealii/build @@ -173,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 diff --git a/contrib/ci/Jenkinsfile.osx b/contrib/ci/Jenkinsfile.osx index 8538cbdcdde7..5c0d92165ca2 100644 --- a/contrib/ci/Jenkinsfile.osx +++ b/contrib/ci/Jenkinsfile.osx @@ -88,6 +88,7 @@ pipeline { sh "echo \"building on node ${env.NODE_NAME}\"" sh '''#!/bin/bash + set -e mkdir build && cd build cmake \ -D DEAL_II_WITH_MPI=OFF \ From 05e5cb6c2269be5df9bb642f9dae8a857515fab1 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 9 Apr 2019 23:04:16 +0200 Subject: [PATCH 386/507] CopyData --- include/deal.II/meshworker/copy_data.h | 164 +++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 include/deal.II/meshworker/copy_data.h diff --git a/include/deal.II/meshworker/copy_data.h b/include/deal.II/meshworker/copy_data.h new file mode 100644 index 000000000000..252f4bab6e31 --- /dev/null +++ b/include/deal.II/meshworker/copy_data.h @@ -0,0 +1,164 @@ +// --------------------------------------------------------------------- +// +// 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_meshworker_copy_data_h +#define dealii_meshworker_copy_data_h + +#include + +#include + +#include +#include + +#include + +DEAL_II_NAMESPACE_OPEN + +namespace MeshWorker +{ + /** + * Helper copy data struct. + * + * This class is a good default drop in CopyData object for the + * WorkStream::run() and MeshWorker::mesh_loop() functions. + * + * It arrays of (local) full matrices, vectors, and local degrees of freedom + * index vectors, with size determined by the corresponding template argument. + * + * In particular, you can specify the following template arguments + * + * - @p n_matrices: Size of the array of matrices + * - @p n_vectors: size of the array of vectors + * - @p n_dof_indices: size of the array of local dof indices + * + * @author Luca Heltai, 2019. + */ + template + struct CopyData + { + /** + * Initialize everything with the same @p size. This is usually the number + * of local degrees of freedom. + */ + CopyData(const unsigned int size); + + /** + * For every object, specify the size they should have. + */ + CopyData( + const std::array, n_matrices> &matrix_sizes, + const std::array & vector_sizes, + const std::array &dof_indices_sizes); + + /** + * Deep copy constructor. + */ + CopyData(const CopyData &other) = + default; + + /** + * Allow resetting of all elements of the struct to zero, by simply + * calling `(*this) = 0;` + * + * Notice that the only allowed number here is really `0`. Calling this + * function with any other number will trigger an assertion. + * + * The elements of the arrays of local degrees of freedom indices are + * all set to numbers::invalid_dof_index. + */ + void + operator=(const double &number); + + /** + * An array of local matrices. + */ + std::array, n_matrices> matrices; + + /** + * An array of local vectors. + */ + std::array, n_vectors> vectors; + + /** + * An array of local degrees of freedom indices. + */ + std::array, n_dof_indices> + local_dof_indices; + }; + + +#ifndef DOXYGEN + // + // Template definitions + // + template + CopyData::CopyData( + const unsigned int size) + { + for (auto &m : matrices) + m.reinit({size, size}); + for (auto &v : vectors) + v.reinit(size); + for (auto &d : local_dof_indices) + d.resize(size); + } + + + + template + CopyData::CopyData( + const std::array, n_matrices> &matrix_sizes, + const std::array & vector_sizes, + const std::array &dof_indices_sizes) + { + for (unsigned int i = 0; i < n_matrices; ++i) + matrices[i].reinit(matrix_sizes[i++]); + + for (unsigned int i = 0; i < n_vectors; ++i) + vectors[i].reinit(vector_sizes[i++]); + + for (unsigned int i = 0; i < n_dof_indices; ++i) + local_dof_indices[i].resize(dof_indices_sizes[i++]); + } + + + + template + void + CopyData:: + operator=(const double &number) + { + Assert(number == 0.0, + ExcMessage("You should only call this method with " + "argument 0.0")); + + for (auto &m : matrices) + m = number; + for (auto &v : vectors) + v = number; + for (auto &d : local_dof_indices) + for (auto &val : d) + val = numbers::invalid_dof_index; + } + +#endif // DOXYGEN +} // namespace MeshWorker + +DEAL_II_NAMESPACE_CLOSE + +#endif From 5c7445b1ca3c72c36553ab859af1e0be2876de5d Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 9 Apr 2019 23:04:36 +0200 Subject: [PATCH 387/507] ScratchData --- include/deal.II/meshworker/scratch_data.h | 1264 +++++++++++++++++++++ source/meshworker/CMakeLists.txt | 2 + source/meshworker/scratch_data.cc | 356 ++++++ source/meshworker/scratch_data.inst.in | 23 + 4 files changed, 1645 insertions(+) create mode 100644 include/deal.II/meshworker/scratch_data.h create mode 100644 source/meshworker/scratch_data.cc create mode 100644 source/meshworker/scratch_data.inst.in diff --git a/include/deal.II/meshworker/scratch_data.h b/include/deal.II/meshworker/scratch_data.h new file mode 100644 index 000000000000..c249357c0824 --- /dev/null +++ b/include/deal.II/meshworker/scratch_data.h @@ -0,0 +1,1264 @@ +// --------------------------------------------------------------------- +// +// 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_meshworker_scratch_data_h +#define dealii_meshworker_scratch_data_h + +#include + +#include + +#include + +#include +#include + +#include + +#include +#include +#include + +DEAL_II_NAMESPACE_OPEN + +namespace MeshWorker +{ + namespace internal + { + /** + * Alias used to deduce the OutputType when asking for values or gradients + * of shape functions multiplied with the given @p NumberType. + */ + template + using OutputType = typename FEValuesViews::View:: + template OutputType; + } // namespace internal + + /** + * A helper class to simplify the parallel assembly of linear and non-linear + * problems, and the evaluation of finite element fields. + * + * This class is a drop in ScratchData to use with the WorkStream::run() + * function and with the MeshWorker::mesh_loop function(). + * + * The ScratchData class has three main goals: + * - to create FEValues, FEFaceValues, and FESubfaceValues for the current + * cell and for its neighbor cell *on demand* (only if they are + * necessary for the algorithm provided by the user), and to provide a + * uniform interface to access the FEValues objects when assembling cell, + * face, or subface contributions + * - to store arbitrary data types (or references to arbitrary data types), + * that can be retrieved by name (for example, when the assembly needs to + * make reference to other objects such as previous time steps' solution + * vectors, previous nonlinear iteration vectors, geometry descriptions, + * etc.) in an object of type + * - to provide a reasonable interface for those use cases where the user may + * need temporary vectors of data at quadrature points, allowing the + * construction of these temporaries *on demand*, and easy access to + * values, gradients, etc., of already computed solution vectors. + * + * The methods in @ref CurrentCellMethods initialize on demand internal FEValues, + * FEFaceValues, and FESubfaceValues objects on the current cell, allowing the + * use of this class as a single substitute for three different objects used + * to integrate and query finite element values on cells, faces, and subfaces. + * + * Similarly, the methods in @ref NeighborCellMethods initialize on demand + * (different) internal FEValues, FEFaceValues, and FESubfaceValues, on + * neighbor cells, allowing the use of this class aslo as a single substitute + * for the additional three objects you would typically need to integrate on + * the neighbor cell, and on its faces and subfaces (for example, in + * discontinuous Galerkin methods). + * + * If you need to retrieve values or gradients of finite element solution + * vectors, on the cell, face, or subface that has just beeing initialized + * with one of the functions in @ref CurrentCellMethods, you can use the + * methods in @ref CurrentCellEvaluation. + * + * An example usage for this class is given by the following snippet of code: + * + * @code + * ScratchData scratch(fe, + * cell_quadrature, + * update_values | update_gradients); + * + * FEValuesExtractors::Vector velocity(0); + * FEValuesExtractors::Scalar pressure(dim); + * + * ... + * + * for(const auto &cell : dof_handler.active_cell_iterators()) + * { + * const auto &fe_values = scratch.reinit(cell); + * scratch.extract_local_dof_values("current_solution", + * current_solution); + * + * scratch.extract_local_dof_values("previous_solution", + * previous_solution); + * + * const auto &local_solution_values = + * scratch.get_local_dof_values("current_solution", + * current_solution); + * + * const auto &local_previous_solution_values = + * scratch.get_local_dof_values("previous_solution", + * previous_solution); + * + * const auto &previous_solution_values_velocity = + * scratch.get_values("previous_solution", velocity); + * const auto &previous_solution_values_pressure = + * scratch.get_values("previous_solution", pressure); + * + * const auto &solution_values_velocity = + * scratch.get_values("solution", velocity); + * const auto &solution_values_pressure = + * scratch.get_values("solution", pressure); + * + * const auto &solution_symmetric_gradients_velocity = + * scratch.get_symmetric_gradients("solution", velocity); + * + * // Do something with the above. + * } + * @endcode + * + * The order in which you call functions of this class matters: if you call + * the ScratchData::reinit() function that takes an active cell iterator, + * then subsequent calls to methods that internally need an FEValuesBase + * object will use the internal FEValues object initialized with the given + * cell to perform their calculations. On the other hand, if you have called + * the ScratchData::reinit() method that also takes a face index, all + * subsequent calls to methods that need an FEValuesBase object, will use an + * internally stored FEFaceValues object, initialized with the cell and face + * index passed to the ScratchData::reinit() function. The same applies for + * the ScratchData::reinit() method that takes three arguments: the cell, the + * face index, and the subface index. + * + * The user code should be structured without interleaving work on cells and + * work on faces. + * + * Consider, for example, the following snippet of code: + * + * @code + * ScratchData scratch(...); + * FEValuesExtractors::Scalar temperature(0); + * + * for(const auto &cell : dof_handler.active_cell_iterators()) + * { + * const auto &fe_values = scratch.reinit(cell); + * const auto &local_dof_values = + * scratch.extract_local_dof_values("solution", solution); + * + * // This will contain all values of the temperature on the cell + * // quadrature points + * const auto &solution_values_cell = + * scratch.get_values("solution", temperature); + * + * // Do something with values on the cell + * ... + * + * // Now start working on the faces + * for(unsigned int f=0; f::faces_per_cell; ++f) + * { + * const auto &fe_face_values = scratch.reinit(cell, f); + * + * // Now we'll have access to the values of the temperature on the faces + * const auto &solution_values_face = + * scratch.get_values("solution", temperature); + * + * // Notice how the function call is the same, but the result depends + * // on what was the last reinit() function that was called. In this + * // case, we called reinit(cell, f), triggering internal work on + * // faces. + * } + * + * // At this point, we would like to go back and work on cells, + * // for example querying the values of the gradients: + * const auto &solution_gradients = + * scratch.get_gradients("solution", temperature); + * + * // This assertion would be triggered in debug mode + * AssertDimension(solution_gradients.size(), quadrature_cell.size()); + * + * // However, with the above call the content of solution_gradients is the + * // gradient of the temperature on the quadrature points of the last face + * // visited in the previous loop. + * // If you really want to have the values of the gradients on the cell, + * // at this point your only option is to call + * scratch.reinit(cell); + * + * // (again) before querying for the gradients: + * const auto &solution_gradients_cell = + * scratch.get_gradients("solution", temperature); + * + * // The call to reinit(cell), however, is an expensive one. You + * // should make sure you only call it once per cell by grouping together + * // all queries that concern cells in the same place (right after you + * // call the reinit(cell) method). + * // A similar argument holds for all calls on each face and subface. + * } + * @endcode + * + * 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}}, + * Doi = {10.1016/j.softx.2018.09.004}, + * Volume = {7}, + * Year = {2018}} + * @endcode + * + * @author Luca Heltai, 2019. + */ + template + class ScratchData + { + public: + /** + * Create an empty ScratchData object. A SmartPointer pointing to + * @p mapping and @p fe is stored internally. Make sure they live longer + * than this class instance. + * + * The constructor does not initialize any of the internal FEValues objects. + * These are initialized the first time one of the reinit() functions is + * called, using the arguments passed here. + * + * @param mapping The mapping to use in the internal FEValues objects + * @param fe The finite element + * @param quadrature The cell quadrature + * @param update_flags UpdateFlags for the current cell FEValues and + * neighbor cell FEValues + * @param face_quadrature Face quadrature, used for FEFaceFvalues and + * FESubfaceValues for both the current cell and the neighbor cell + * @param face_update_flags UpdateFlags used for FEFaceFvalues and + * FESubfaceValues for both the current cell and the neighbor cell + */ + ScratchData( + const Mapping & mapping, + const FiniteElement &fe, + const Quadrature & quadrature, + const UpdateFlags & update_flags, + const Quadrature &face_quadrature = Quadrature(), + const UpdateFlags & face_update_flags = update_default); + + /** + * Similar to the other constructor, but this one allows to specify + * different flags for neighbor cells and faces. + * + * @param mapping The mapping to use in the internal FEValues objects + * @param fe The finite element + * @param quadrature The cell quadrature + * @param update_flags UpdateFlags for the current cell FEValues + * @param neighbor_update_flags UpdateFlags for the neighbor cell FEValues + * @param face_quadrature Face quadrature, used for FEFaceFvalues and + * FESubfaceValues for both the current cell and the neighbor cell + * @param face_update_flags UpdateFlags used for FEFaceFvalues and + * FESubfaceValues for the current cell + * @param neighbor_face_update_flags UpdateFlags used for FEFaceFvalues and + * FESubfaceValues for the neighbor cell + */ + ScratchData( + const Mapping & mapping, + const FiniteElement &fe, + const Quadrature & quadrature, + const UpdateFlags & update_flags, + const UpdateFlags & neighbor_update_flags, + const Quadrature &face_quadrature = Quadrature(), + const UpdateFlags & face_update_flags = update_default, + const UpdateFlags & neighbor_face_update_flags = update_default); + + /** + * Same as the other constructor, using the default MappingQ1. + * + * @param mapping The mapping to use in the internal FEValues objects + * @param fe The finite element + * @param quadrature The cell quadrature + * @param update_flags UpdateFlags for the current cell FEValues + * @param neighbor_update_flags UpdateFlags for the neighbor cell FEValues + * @param face_quadrature Face quadrature, used for FEFaceFvalues and + * FESubfaceValues for both the current cell and the neighbor cell + * @param face_update_flags UpdateFlags used for FEFaceFvalues and + * FESubfaceValues for the current cell + * @param neighbor_face_update_flags UpdateFlags used for FEFaceFvalues and + * FESubfaceValues for the neighbor cell + */ + ScratchData( + const FiniteElement &fe, + const Quadrature & quadrature, + const UpdateFlags & update_flags, + const Quadrature &face_quadrature = Quadrature(), + const UpdateFlags & face_update_flags = update_default); + + /** + * Same as the other constructor, using the default MappingQ1. + * + * @param mapping The mapping to use in the internal FEValues objects + * @param fe The finite element + * @param quadrature The cell quadrature + * @param update_flags UpdateFlags for the current cell FEValues + * @param neighbor_update_flags UpdateFlags for the neighbor cell FEValues + * @param face_quadrature Face quadrature, used for FEFaceFvalues and + * FESubfaceValues for both the current cell and the neighbor cell + * @param face_update_flags UpdateFlags used for FEFaceFvalues and + * FESubfaceValues for the current cell + * @param neighbor_face_update_flags UpdateFlags used for FEFaceFvalues and + * FESubfaceValues for the neighbor cell + */ + ScratchData( + const FiniteElement &fe, + const Quadrature & quadrature, + const UpdateFlags & update_flags, + const UpdateFlags & neighbor_update_flags, + const Quadrature &face_quadrature = Quadrature(), + const UpdateFlags & face_update_flags = update_default, + const UpdateFlags & neighbor_face_update_flags = update_default); + + /** + * Deep copy constructor. FEValues objects are not copied. + */ + ScratchData(const ScratchData &scratch); + + /** + * \defgroup CurrentCellMethos Methods to work on current cell + */ + /**@{*/ + + /** + * Initialize the internal FEValues with the given @p cell, and return + * a reference to it. + * + * After calling this function, get_current_fe_values() will return the + * same object of this method, as an FEValuesBase reference. + */ + const FEValues & + reinit( + const typename DoFHandler::active_cell_iterator &cell); + + /** + * Initialize the internal FEFaceValues to use the given @p face_no on the given + * @p cell, and return a reference to it. + * + * After calling this function, get_current_fe_values() will return the + * same object of this method, as an FEValuesBase reference. + */ + const FEFaceValues & + reinit(const typename DoFHandler::active_cell_iterator &cell, + const unsigned int face_no); + + /** + * Initialize the internal FESubfaceValues to use the given @p subface_no, + * on @p face_no, on the given @p cell, and return a reference to it. + * + * After calling this function, get_current_fe_values() will return the + * same object of this method, as an FEValuesBase reference. + * + * If @p subface_no is numbers::invalid_unsigned_int, the reinit() function + * that takes only the @p cell and the @p face_no is called. + */ + const FEFaceValuesBase & + reinit(const typename DoFHandler::active_cell_iterator &cell, + const unsigned int face_no, + const unsigned int subface_no); + + /** + * Get the currently initialized FEValues. + * + * This function will return the internal FEValues if the + * reinit(cell) function was called last. If the reinit(cell, face_no) + * function was called, then this function returns the internal + * FEFaceValues, and if the reinit(cell, face_no, subface_no) function was + * called (with a valid @p subface_no argument), it returns the internal + * FESubfaceValues object. + */ + const FEValuesBase & + get_current_fe_values() const; + + /** + * Return the quadrature points of the internal FEValues object. + */ + const std::vector> & + get_quadrature_points() const; + + /** + * Return the JxW values of the internal FEValues object. + */ + const std::vector & + get_JxW_values() const; + + /** + * Return the last computed normal vectors. + */ + const std::vector> & + get_normal_vectors() const; + + /** + * Return the local dof indices for the cell passed the last time the + * reinit() function was called. + */ + const std::vector & + get_local_dof_indices() const; + + /** @} */ // CurrentCellMethods + + /** + * @defgroup NeighborCellMethods Methods to work on neighbor cell + */ + /** @{ */ + + /** + * Initialize the internal neighbor FEValues to use the given @p cell, and + * return a reference to it. + * + * After calling this function, get_current_fe_values() will return the + * same object of this method, as an FEValuesBase reference. + */ + const FEValues & + reinit_neighbor( + const typename DoFHandler::active_cell_iterator &cell); + + /** + * Initialize the internal FEFaceValues to use the given @p face_no on the + * given @p cell, and return a reference to it. + * + * After calling this function, get_current_fe_values() will return the + * same object of this method, as an FEValuesBase reference. + */ + const FEFaceValues & + reinit_neighbor( + const typename DoFHandler::active_cell_iterator &cell, + const unsigned int face_no); + + /** + * Initialize the internal FESubfaceValues to use the given @p subface_no, + * on @p face_no, on the given @p cell, and return a reference to it. + * + * After calling this function, get_current_fe_values() will return the + * same object of this method, as an FEValuesBase reference. + * + * If @p subface_no is numbers::invalid_unsigned_int, the reinit() function + * that takes only the @p cell and the @p face_no is called. + */ + const FEFaceValuesBase & + reinit_neighbor( + const typename DoFHandler::active_cell_iterator &cell, + const unsigned int face_no, + const unsigned int subface_no); + + /** + * Get the currently initialized neighbor FEValues. + * + * This function will return the neighbor FEValues if the + * reinit_neighbor(cell) function was called last. If the + * reinit_neighbor(cell, face_no) function was called, then this function + * returns the internal neighbor FEFaceValues, and if the + * reinit_neighbor(cell, face_no, subface_no) function was + * called (with a valid @p subface_no argument), it returns the internal neighbor + * FESubfaceValues object. + */ + const FEValuesBase & + get_current_neighbor_fe_values() const; + + /** + * Return the JxW values of the neighbor FEValues object. + */ + const std::vector & + get_neighbor_JxW_values() const; + + /** + * Return the last computed normal vectors on the neighbor. + */ + const std::vector> & + get_neighbor_normal_vectors(); + + /** + * Return the local dof indices of the neighbor passed the last time the + * reinit_neighbor() function was called. + */ + const std::vector & + get_neighbor_dof_indices() const; + + /** @} */ // NeighborCellMethods + + /** + * Return a GeneralDataStorage object that can be used to store store any + * amount of data, of any type, which is then made accessible by an + * identifier string. + */ + GeneralDataStorage & + get_general_data_storage(); + + /** @defgroup CurrentCellEvaluation Evaluation of finite element fields + * and their derivatives on the current cell + * @{ + */ + + /** + * Extract the local dof values associated with the internally initialized + * cell. + * + * Before you call this function, you have to make sure you have previously + * called one of the reinit() functions. + * + * At every call of this function, a new vector of dof values is generated + * and stored internally, unless a previous vector with the same name is + * found. If this is the case, the content of that vector is overwritten. + * + * If you give a unique @p global_vector_name, then for each cell you are + * guaranteed to get a unique vector of independent dofs of the same type + * as the dummy variable. If you use an automatic differentiation number + * type (like Sacado::Fad::DFad, + * Sacado::Fad::DFad>, etc.) this method will + * also initialize the independent variables internally, allowing you + * to perform automatic differentiation. + * + * You can access the extracted local dof values by calling the method + * get_local_dof_values() with the same @p global_vector_name argument + * you passed here. + * + * Notice that using this initialization strategy renders the use of this + * ScratchData object incompatible with the AD helper classes (since they + * do their own data management). In particular, it is necessary for the + * user to manage all of the AD data themselves (both before and after this + * call). + */ + template + void + extract_local_dof_values(const std::string &global_vector_name, + const VectorType & input_vector, + const Number dummy = Number(0)); + + /** + * After calling extract_local_dof_values(), you can retrieve the stored + * information through this method. + * + * Both the argument @p global_vector_name and the type of the @p dummy + * variable should match the ones you passed to the + * extract_local_dof_values() function. + */ + template + const std::vector & + get_local_dof_values(const std::string &global_vector_name, + Number dummy = Number(0)) const; + + /** + * For the solution vector identified by @p global_vector_name, compute + * the values of the function at the quadrature points, and return a + * vector with the correct type deduced by the Extractor you passed as the + * @p variable argument. + * + * Before you can call this method, you need to call the + * extract_local_dof_values() method at least once, passing the same + * @p global_vector_name string, and the same type for the variable @p dummy. + * + * If you have not previously called the extract_local_dof_values() method, + * this function will throw an exception. + * + * For this function to work properly, the underlying FEValues, + * FEFaceValues, or FESubfaceValues object for which you called one of the + * reinit() functions, must have computed the information you are + * requesting. To do so, the update_values flag must be an element of the + * list of UpdateFlags that you passed to the constructor of this object. + * See "The interplay of UpdateFlags, Mapping, and FiniteElement" in + * the documentation of the FEValues class for more information. + */ + template + const std::vector< + typename internal::OutputType:: + value_type> & + get_values(const std::string &global_vector_name, + const Extractor & variable, + const Number dummy = Number(0)); + + /** + * For the solution vector identified by @p global_vector_name, compute + * the gradients of the function at the quadrature points, and return a + * vector with the correct type deduced by the Extractor you passed as the + * @p variable argument. + * + * Before you can call this method, you need to call the + * extract_local_dof_values() method at least once, passing the same + * @p global_vector_name string, and the same type for the variable @p dummy. + * + * If you have not previously called the extract_local_dof_values() method, + * this function will throw an exception. + * + * For this function to work properly, the underlying FEValues, + * FEFaceValues, or FESubfaceValues object for which you called one of the + * reinit() functions, must have computed the information you are + * requesting. To do so, the update_gradients flag must be an element of the + * list of UpdateFlags that you passed to the constructor of this object. + * See "The interplay of UpdateFlags, Mapping, and FiniteElement" in + * the documentation of the FEValues class for more information. + */ + template + const std::vector< + typename internal::OutputType:: + gradient_type> & + get_gradients(const std::string &global_vector_name, + const Extractor & variable, + const Number dummy = Number(0)); + + /** + * For the solution vector identified by @p global_vector_name, compute + * the symmetric gradients of the function at the quadrature points, and + * return a vector with the correct type deduced by the Extractor you passed + * as the + * @p variable argument. + * + * Before you can call this method, you need to call the + * extract_local_dof_values() method at least once, passing the same + * @p global_vector_name string, and the same type for the variable @p dummy. + * + * If you have not previously called the extract_local_dof_values() method, + * this function will throw an exception. + * + * For this function to work properly, the underlying FEValues, + * FEFaceValues, or FESubfaceValues object for which you called one of the + * reinit() functions, must have computed the information you are + * requesting. To do so, the update_gradients flag must be an element of the + * list of UpdateFlags that you passed to the constructor of this object. + * See "The interplay of UpdateFlags, Mapping, and FiniteElement" in + * the documentation of the FEValues class for more information. + */ + template + const std::vector< + typename internal::OutputType:: + symmetric_gradient_type> & + get_symmetric_gradients(const std::string &global_vector_name, + const Extractor & variable, + const Number dummy = Number(0)); + + /** + * For the solution vector identified by @p global_vector_name, compute + * the divergences of the function at the quadrature points, and return a + * vector with the correct type deduced by the Extractor you passed as the + * @p variable argument. + * + * Before you can call this method, you need to call the + * extract_local_dof_values() method at least once, passing the same + * @p global_vector_name string, and the same type for the variable @p dummy. + * + * If you have not previously called the extract_local_dof_values() method, + * this function will throw an exception. + * + * For this function to work properly, the underlying FEValues, + * FEFaceValues, or FESubfaceValues object for which you called one of the + * reinit() functions, must have computed the information you are + * requesting. To do so, the update_gradients flag must be an element of the + * list of UpdateFlags that you passed to the constructor of this object. + * See "The interplay of UpdateFlags, Mapping, and FiniteElement" in + * the documentation of the FEValues class for more information. + */ + template + const std::vector< + typename internal::OutputType:: + divergence_type> & + get_divergences(const std::string &global_vector_name, + const Extractor & variable, + const Number dummy = Number(0)); + + /** + * For the solution vector identified by @p global_vector_name, compute + * the curls of the function at the quadrature points, and return a + * vector with the correct type deduced by the Extractor you passed as the + * @p variable argument. + * + * Before you can call this method, you need to call the + * extract_local_dof_values() method at least once, passing the same + * @p global_vector_name string, and the same type for the variable @p dummy. + * + * If you have not previously called the extract_local_dof_values() method, + * this function will throw an exception. + * + * For this function to work properly, the underlying FEValues, + * FEFaceValues, or FESubfaceValues object for which you called one of the + * reinit() functions, must have computed the information you are + * requesting. To do so, the update_gradients flag must be an element of the + * list of UpdateFlags that you passed to the constructor of this object. + * See "The interplay of UpdateFlags, Mapping, and FiniteElement" in + * the documentation of the FEValues class for more information. + */ + template + const std::vector::curl_type> + & + get_curls(const std::string &global_vector_name, + const Extractor & variable, + const Number dummy = Number(0)); + + /** + * For the solution vector identified by @p global_vector_name, compute + * the hessians of the function at the quadrature points, and return a + * vector with the correct type deduced by the Extractor you passed as the + * @p variable argument. + * + * Before you can call this method, you need to call the + * extract_local_dof_values() method at least once, passing the same + * @p global_vector_name string, and the same type for the variable @p dummy. + * + * If you have not previously called the extract_local_dof_values() method, + * this function will throw an exception. + * + * For this function to work properly, the underlying FEValues, + * FEFaceValues, or FESubfaceValues object for which you called one of the + * reinit() functions, must have computed the information you are + * requesting. To do so, the update_hessians flag must be an element of the + * list of UpdateFlags that you passed to the constructor of this object. + * See "The interplay of UpdateFlags, Mapping, and FiniteElement" in + * the documentation of the FEValues class for more information. + */ + template + const std::vector< + typename internal::OutputType:: + hessian_type> & + get_hessians(const std::string &global_vector_name, + const Extractor & variable, + const Number dummy = Number(0)); + + /** + * For the solution vector identified by @p global_vector_name, compute + * the third_derivatives of the function at the quadrature points, and + * return a vector with the correct type deduced by the Extractor you passed + * as the @p variable argument. + * + * Before you can call this method, you need to call the + * extract_local_dof_values() method at least once, passing the same + * @p global_vector_name string, and the same type for the variable @p dummy. + * + * If you have not previously called the extract_local_dof_values() method, + * this function will throw an exception. + * + * For this function to work properly, the underlying FEValues, + * FEFaceValues, or FESubfaceValues object for which you called one of the + * reinit() functions, must have computed the information you are + * requesting. To do so, the update_3rd_derivatives flag must be an + * element of the list of UpdateFlags that you passed to the constructor of + * this object. See "The interplay of UpdateFlags, Mapping, and + * FiniteElement" in the documentation of the FEValues for more information. + */ + template + const std::vector< + typename internal::OutputType:: + third_derivative_type> & + get_third_derivatives(const std::string &global_vector_name, + const Extractor & variable, + const Number dummy = Number(0)); + + /** @} */ // CurrentCellEvaluation + + /** + * Return a reference to the used mapping. + */ + const Mapping & + get_mapping() const; + + private: + /** + * Construct a unique name to store vectors of values, gradients, + * divergences, etc., in the internal GeneralDataStorage object. + */ + template + std::string + get_unique_name(const std::string &global_vector_name, + const Extractor & variable, + const std::string &object_type, + const unsigned int size, + const Number & exemplar_number) const; + + /** + * Construct a unique name to store local dof values. + */ + template + std::string + get_unique_dofs_name(const std::string &global_vector_name, + const unsigned int size, + const Number & exemplar_number) const; + + /** + * The mapping used by the internal FEValues. Make sure it lives + * longer than this class. + */ + SmartPointer> mapping; + + /** + * The finite element used by the internal FEValues. Make sure it lives + * longer than this class. + */ + SmartPointer> fe; + + /** + * Quadrature formula used to integrate on the current cell, and on its + * neighbor. + */ + Quadrature cell_quadrature; + + /** + * Quadrature formula used to integrate on faces, subfaces, and neighbor + * faces and subfaces. + */ + Quadrature face_quadrature; + + /** + * UpdateFlags to use when initializing the cell FEValues object. + */ + UpdateFlags cell_update_flags; + + /** + * UpdateFlags to use when initializing the neighbor cell FEValues objects. + */ + UpdateFlags neighbor_cell_update_flags; + + /** + * UpdateFlags to use when initializing FEFaceValues and FESubfaceValues + * objects. + */ + UpdateFlags face_update_flags; + + /** + * UpdateFlags to use when initializing neighbor FEFaceValues and + * FESubfaceValues objects. + */ + UpdateFlags neighbor_face_update_flags; + + /** + * Finite element values on the current cell. + */ + std::unique_ptr> fe_values; + + /** + * Finite element values on the current face. + */ + std::unique_ptr> fe_face_values; + + /** + * Finite element values on the current subface. + */ + std::unique_ptr> fe_subface_values; + + /** + * Finite element values on the neighbor cell. + */ + std::unique_ptr> neighbor_fe_values; + + /** + * Finite element values on the neighbor face. + */ + std::unique_ptr> neighbor_fe_face_values; + + /** + * Finite element values on the neighbor subface. + */ + std::unique_ptr> neighbor_fe_subface_values; + + /** + * Dof indices on the current cell. + */ + std::vector local_dof_indices; + + /** + * Dof indices on the neighbor cell. + */ + std::vector neighbor_dof_indices; + + /** + * User data storage. + */ + GeneralDataStorage user_data_storage; + + /** + * Internal data storage. + */ + GeneralDataStorage internal_data_storage; + + /** + * A pointer to the last used FEValues/FEFaceValues, or FESubfaceValues + * object on this cell. + */ + SmartPointer> current_fe_values; + + /** + * A pointer to the last used FEValues/FEFaceValues, or FESubfaceValues + * object on the neighbor cell. + */ + SmartPointer> current_neighbor_fe_values; + }; + +#ifndef DOXYGEN + template + template + std::string + ScratchData::get_unique_name( + const std::string &global_vector_name, + const Extractor & variable, + const std::string &object_type, + const unsigned int size, + const Number & exemplar_number) const + { + return global_vector_name + "_" + variable.get_name() + "_" + object_type + + "_" + Utilities::int_to_string(size) + "_" + + Utilities::type_to_string(exemplar_number); + } + + + + template + template + std::string + ScratchData::get_unique_dofs_name( + const std::string &global_vector_name, + const unsigned int size, + const Number & exemplar_number) const + { + return global_vector_name + "_independent_local_dofs_" + + Utilities::int_to_string(size) + "_" + + Utilities::type_to_string(exemplar_number); + } + + + + template + template + void + ScratchData::extract_local_dof_values( + const std::string &global_vector_name, + const VectorType & input_vector, + const Number dummy) + { + const unsigned int n_dofs = get_current_fe_values().get_fe().dofs_per_cell; + + const std::string name = + get_unique_dofs_name(global_vector_name, n_dofs, dummy); + + auto &independent_local_dofs = + internal_data_storage + .template get_or_add_object_with_name>(name, + n_dofs); + + AssertDimension(independent_local_dofs.size(), n_dofs); + + if (Differentiation::AD::is_tapeless_ad_number::value == true) + for (unsigned int i = 0; i < n_dofs; ++i) + Differentiation::AD::internal::Marking::independent_variable( + input_vector(local_dof_indices[i]), + i, + n_dofs, + independent_local_dofs[i]); + else + for (unsigned int i = 0; i < n_dofs; ++i) + independent_local_dofs[i] = input_vector(local_dof_indices[i]); + } + + + + template + template + const std::vector & + ScratchData::get_local_dof_values( + const std::string &global_vector_name, + Number dummy) const + { + const unsigned int n_dofs = get_current_fe_values().get_fe().dofs_per_cell; + + const std::string dofs_name = + get_unique_dofs_name(global_vector_name, n_dofs, dummy); + + Assert( + internal_data_storage.stores_object_with_name(dofs_name), + ExcMessage( + "You did not call yet extract_local_dof_values with the right types!")); + + return internal_data_storage + .template get_object_with_name>(dofs_name); + } + + + + template + template + const std::vector< + typename internal::OutputType::value_type> + & + ScratchData::get_values( + const std::string &global_vector_name, + const Extractor & variable, + const Number dummy) + { + const std::vector &independent_local_dofs = + get_local_dof_values(global_vector_name, dummy); + + const FEValuesBase &fev = get_current_fe_values(); + + const unsigned int n_q_points = fev.n_quadrature_points; + + const std::string name = get_unique_name( + global_vector_name, variable, "_values_q", n_q_points, dummy); + + // Now build the return type + using RetType = + std::vector::value_type>; + + RetType &ret = + internal_data_storage.template get_or_add_object_with_name( + name, n_q_points); + + AssertDimension(ret.size(), n_q_points); + + fev[variable].get_function_values_from_local_dof_values( + independent_local_dofs, ret); + return ret; + } + + + + template + template + const std::vector< + typename internal::OutputType:: + gradient_type> & + ScratchData::get_gradients( + const std::string &global_vector_name, + const Extractor & variable, + const Number dummy) + { + const std::vector &independent_local_dofs = + get_local_dof_values(global_vector_name, dummy); + + const FEValuesBase &fev = get_current_fe_values(); + + const unsigned int n_q_points = fev.n_quadrature_points; + + const std::string name = get_unique_name( + global_vector_name, variable, "_gradients_q", n_q_points, dummy); + + // Now build the return type + using RetType = std::vector< + typename internal::OutputType:: + gradient_type>; + + RetType &ret = + internal_data_storage.template get_or_add_object_with_name( + name, n_q_points); + + AssertDimension(ret.size(), n_q_points); + + fev[variable].get_function_gradients_from_local_dof_values( + independent_local_dofs, ret); + return ret; + } + + + + template + template + const std::vector< + typename internal::OutputType:: + hessian_type> & + ScratchData::get_hessians( + const std::string &global_vector_name, + const Extractor & variable, + const Number dummy) + { + const std::vector &independent_local_dofs = + get_local_dof_values(global_vector_name, dummy); + + const FEValuesBase &fev = get_current_fe_values(); + + const unsigned int n_q_points = fev.n_quadrature_points; + + const std::string name = get_unique_name( + global_vector_name, variable, "_hessians_q", n_q_points, dummy); + + // Now build the return type + using RetType = + std::vector::hessian_type>; + + RetType &ret = + internal_data_storage.template get_or_add_object_with_name( + name, n_q_points); + + + AssertDimension(ret.size(), n_q_points); + + fev[variable].get_function_hessians_from_local_dof_values( + independent_local_dofs, ret); + return ret; + } + + + + template + template + const std::vector< + typename internal::OutputType:: + third_derivative_type> & + ScratchData::get_third_derivatives( + const std::string &global_vector_name, + const Extractor & variable, + const Number dummy) + { + const std::vector &independent_local_dofs = + get_local_dof_values(global_vector_name, dummy); + + const FEValuesBase &fev = get_current_fe_values(); + + const unsigned int n_q_points = fev.n_quadrature_points; + + const std::string name = get_unique_name( + global_vector_name, variable, "_third_derivatives_q", n_q_points, dummy); + + // Now build the return type + using RetType = std::vector< + typename internal::OutputType:: + third_derivative_type>; + + RetType &ret = + internal_data_storage.template get_or_add_object_with_name( + name, n_q_points); + + + AssertDimension(ret.size(), n_q_points); + + fev[variable].get_function_third_derivatives_from_local_dof_values( + independent_local_dofs, ret); + return ret; + } + + + + template + template + const std::vector< + typename internal::OutputType:: + symmetric_gradient_type> & + ScratchData::get_symmetric_gradients( + const std::string &global_vector_name, + const Extractor & variable, + const Number dummy) + { + const std::vector &independent_local_dofs = + get_local_dof_values(global_vector_name, dummy); + + const FEValuesBase &fev = get_current_fe_values(); + + const unsigned int n_q_points = fev.n_quadrature_points; + + const std::string name = get_unique_name( + global_vector_name, variable, "_symmetric_gradient_q", n_q_points, dummy); + + + // Now build the return type + using RetType = std::vector< + typename internal::OutputType:: + symmetric_gradient_type>; + + RetType &ret = + internal_data_storage.template get_or_add_object_with_name( + name, n_q_points); + + + AssertDimension(ret.size(), n_q_points); + + fev[variable].get_function_symmetric_gradients_from_local_dof_values( + independent_local_dofs, ret); + return ret; + } + + + template + template + const std::vector< + typename internal::OutputType:: + divergence_type> & + ScratchData::get_divergences( + const std::string &global_vector_name, + const Extractor & variable, + const Number dummy) + { + const std::vector &independent_local_dofs = + get_local_dof_values(global_vector_name, dummy); + + const FEValuesBase &fev = get_current_fe_values(); + + const unsigned int n_q_points = fev.n_quadrature_points; + + const std::string name = get_unique_name( + global_vector_name, variable, "_divergence_q", n_q_points, dummy); + + // Now build the return type + using RetType = std::vector< + typename internal::OutputType:: + divergence_type>; + + RetType &ret = + internal_data_storage.template get_or_add_object_with_name( + name, n_q_points); + + + AssertDimension(ret.size(), n_q_points); + + fev[variable].get_function_divergences_from_local_dof_values( + independent_local_dofs, ret); + return ret; + } + + + + template + template + const std::vector< + typename internal::OutputType::curl_type> + & + ScratchData::get_curls(const std::string &global_vector_name, + const Extractor & variable, + const Number dummy) + { + const std::vector &independent_local_dofs = + get_local_dof_values(global_vector_name, dummy); + + const FEValuesBase &fev = get_current_fe_values(); + + const unsigned int n_q_points = fev.n_quadrature_points; + + const std::string name = get_unique_name( + global_vector_name, variable, "_curl_q", n_q_points, dummy); + + // Now build the return type + using RetType = + std::vector::curl_type>; + + RetType &ret = + internal_data_storage.template get_or_add_object_with_name( + name, n_q_points); + + AssertDimension(ret.size(), n_q_points); + + fev[variable].get_function_curls_from_local_dof_values( + independent_local_dofs, ret); + return ret; + } + +#endif + +} // namespace MeshWorker + +DEAL_II_NAMESPACE_CLOSE + +#endif diff --git a/source/meshworker/CMakeLists.txt b/source/meshworker/CMakeLists.txt index 557829dbadff..f939da489433 100644 --- a/source/meshworker/CMakeLists.txt +++ b/source/meshworker/CMakeLists.txt @@ -19,11 +19,13 @@ SET(_src mesh_worker.cc mesh_worker_info.cc mesh_worker_vector_selector.cc + scratch_data.cc ) SET(_inst mesh_worker_info.inst.in mesh_worker_vector_selector.inst.in + scratch_data.inst.in ) FILE(GLOB _header diff --git a/source/meshworker/scratch_data.cc b/source/meshworker/scratch_data.cc new file mode 100644 index 000000000000..8e6e8708c8fe --- /dev/null +++ b/source/meshworker/scratch_data.cc @@ -0,0 +1,356 @@ +// --------------------------------------------------------------------- +// +// 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 + +DEAL_II_NAMESPACE_OPEN + +namespace MeshWorker +{ + template + ScratchData::ScratchData( + const Mapping & mapping, + const FiniteElement &fe, + const Quadrature & quadrature, + const UpdateFlags & update_flags, + const Quadrature & face_quadrature, + const UpdateFlags & face_update_flags) + : mapping(&mapping) + , fe(&fe) + , cell_quadrature(quadrature) + , face_quadrature(face_quadrature) + , cell_update_flags(update_flags) + , neighbor_cell_update_flags(update_flags) + , face_update_flags(face_update_flags) + , neighbor_face_update_flags(face_update_flags) + , local_dof_indices(fe.dofs_per_cell) + , neighbor_dof_indices(fe.dofs_per_cell) + {} + + + + template + ScratchData::ScratchData( + const Mapping & mapping, + const FiniteElement &fe, + const Quadrature & quadrature, + const UpdateFlags & update_flags, + const UpdateFlags & neighbor_update_flags, + const Quadrature & face_quadrature, + const UpdateFlags & face_update_flags, + const UpdateFlags & neighbor_face_update_flags) + : mapping(&mapping) + , fe(&fe) + , cell_quadrature(quadrature) + , face_quadrature(face_quadrature) + , cell_update_flags(update_flags) + , neighbor_cell_update_flags(neighbor_update_flags) + , face_update_flags(face_update_flags) + , neighbor_face_update_flags(neighbor_face_update_flags) + , local_dof_indices(fe.dofs_per_cell) + , neighbor_dof_indices(fe.dofs_per_cell) + {} + + + + template + ScratchData::ScratchData( + const FiniteElement &fe, + const Quadrature & quadrature, + const UpdateFlags & update_flags, + const Quadrature & face_quadrature, + const UpdateFlags & face_update_flags) + : ScratchData(StaticMappingQ1::mapping, + fe, + quadrature, + update_flags, + face_quadrature, + face_update_flags) + {} + + + + template + ScratchData::ScratchData( + const FiniteElement &fe, + const Quadrature & quadrature, + const UpdateFlags & update_flags, + const UpdateFlags & neighbor_update_flags, + const Quadrature & face_quadrature, + const UpdateFlags & face_update_flags, + const UpdateFlags & neighbor_face_update_flags) + : ScratchData(StaticMappingQ1::mapping, + fe, + quadrature, + update_flags, + neighbor_update_flags, + face_quadrature, + face_update_flags, + neighbor_face_update_flags) + {} + + + + template + ScratchData::ScratchData( + const ScratchData &scratch) + : mapping(scratch.mapping) + , fe(scratch.fe) + , cell_quadrature(scratch.cell_quadrature) + , face_quadrature(scratch.face_quadrature) + , cell_update_flags(scratch.cell_update_flags) + , neighbor_cell_update_flags(scratch.neighbor_cell_update_flags) + , face_update_flags(scratch.face_update_flags) + , neighbor_face_update_flags(scratch.neighbor_face_update_flags) + , local_dof_indices(scratch.local_dof_indices) + , neighbor_dof_indices(scratch.neighbor_dof_indices) + , user_data_storage(scratch.user_data_storage) + , internal_data_storage(scratch.internal_data_storage) + {} + + + + template + const FEValues & + ScratchData::reinit( + const typename DoFHandler::active_cell_iterator &cell) + { + if (!fe_values) + fe_values = std::make_unique>(*mapping, + *fe, + cell_quadrature, + cell_update_flags); + + fe_values->reinit(cell); + cell->get_dof_indices(local_dof_indices); + current_fe_values = fe_values.get(); + return *fe_values; + } + + + + template + const FEFaceValues & + ScratchData::reinit( + const typename DoFHandler::active_cell_iterator &cell, + const unsigned int face_no) + { + if (!fe_face_values) + fe_face_values = std::make_unique>( + *mapping, *fe, face_quadrature, face_update_flags); + + fe_face_values->reinit(cell, face_no); + cell->get_dof_indices(local_dof_indices); + current_fe_values = fe_face_values.get(); + return *fe_face_values; + } + + + + template + const FEFaceValuesBase & + ScratchData::reinit( + const typename DoFHandler::active_cell_iterator &cell, + const unsigned int face_no, + const unsigned int subface_no) + { + if (subface_no != numbers::invalid_unsigned_int) + { + if (!fe_subface_values) + fe_subface_values = std::make_unique>( + *mapping, *fe, face_quadrature, face_update_flags); + fe_subface_values->reinit(cell, face_no, subface_no); + cell->get_dof_indices(local_dof_indices); + + current_fe_values = fe_subface_values.get(); + return *fe_subface_values; + } + else + return reinit(cell, face_no); + } + + + + template + const FEValues & + ScratchData::reinit_neighbor( + const typename DoFHandler::active_cell_iterator &cell) + { + if (!neighbor_fe_values) + neighbor_fe_values = std::make_unique>( + *mapping, *fe, cell_quadrature, neighbor_cell_update_flags); + + neighbor_fe_values->reinit(cell); + cell->get_dof_indices(neighbor_dof_indices); + current_neighbor_fe_values = neighbor_fe_values.get(); + return *neighbor_fe_values; + } + + + + template + const FEFaceValues & + ScratchData::reinit_neighbor( + const typename DoFHandler::active_cell_iterator &cell, + const unsigned int face_no) + { + if (!neighbor_fe_face_values) + neighbor_fe_face_values = std::make_unique>( + *mapping, *fe, face_quadrature, neighbor_face_update_flags); + neighbor_fe_face_values->reinit(cell, face_no); + cell->get_dof_indices(neighbor_dof_indices); + current_neighbor_fe_values = neighbor_fe_face_values.get(); + return *neighbor_fe_face_values; + } + + + + template + const FEFaceValuesBase & + ScratchData::reinit_neighbor( + const typename DoFHandler::active_cell_iterator &cell, + const unsigned int face_no, + const unsigned int subface_no) + { + if (subface_no != numbers::invalid_unsigned_int) + { + if (!neighbor_fe_subface_values) + neighbor_fe_subface_values = + std::make_unique>( + *mapping, *fe, face_quadrature, neighbor_face_update_flags); + neighbor_fe_subface_values->reinit(cell, face_no, subface_no); + cell->get_dof_indices(neighbor_dof_indices); + current_neighbor_fe_values = neighbor_fe_subface_values.get(); + return *neighbor_fe_subface_values; + } + else + return reinit_neighbor(cell, face_no); + } + + + + template + const FEValuesBase & + ScratchData::get_current_fe_values() const + { + Assert(current_fe_values != nullptr, + ExcMessage("You have to initialize the cache using one of the " + "reinit functions first!")); + return *current_fe_values; + } + + + + template + const FEValuesBase & + ScratchData::get_current_neighbor_fe_values() const + { + Assert(current_neighbor_fe_values != nullptr, + ExcMessage("You have to initialize the cache using one of the " + "reinit functions first!")); + return *current_neighbor_fe_values; + } + + + + template + const std::vector> & + ScratchData::get_quadrature_points() const + { + return get_current_fe_values().get_quadrature_points(); + } + + + + template + const std::vector & + ScratchData::get_JxW_values() const + { + return get_current_fe_values().get_JxW_values(); + } + + + + template + const std::vector & + ScratchData::get_neighbor_JxW_values() const + { + return get_current_neighbor_fe_values().get_JxW_values(); + } + + + + template + const std::vector> & + ScratchData::get_normal_vectors() const + { + return get_current_fe_values().get_normal_vectors(); + } + + + + template + const std::vector> & + ScratchData::get_neighbor_normal_vectors() + { + return get_current_neighbor_fe_values().get_normal_vectors(); + } + + + + template + const std::vector & + ScratchData::get_local_dof_indices() const + { + return local_dof_indices; + } + + + + template + const std::vector & + ScratchData::get_neighbor_dof_indices() const + { + return neighbor_dof_indices; + } + + + + template + GeneralDataStorage & + ScratchData::get_general_data_storage() + { + return user_data_storage; + } + + + + template + const Mapping & + ScratchData::get_mapping() const + { + return *mapping; + } + +} // namespace MeshWorker +DEAL_II_NAMESPACE_CLOSE + +// Explicit instantiations +DEAL_II_NAMESPACE_OPEN +namespace MeshWorker +{ +#include "scratch_data.inst" +} +DEAL_II_NAMESPACE_CLOSE \ No newline at end of file diff --git a/source/meshworker/scratch_data.inst.in b/source/meshworker/scratch_data.inst.in new file mode 100644 index 000000000000..96eb79e413d1 --- /dev/null +++ b/source/meshworker/scratch_data.inst.in @@ -0,0 +1,23 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { +#if deal_II_dimension <= deal_II_space_dimension + template class ScratchData; + +#endif + } From 6081ccfebeedef8ee769fb45ef46d3cff966b3fd Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 9 Apr 2019 23:04:47 +0200 Subject: [PATCH 388/507] Test ScratchData on simple volume computation --- tests/meshworker/scratch_data_01.cc | 141 ++++++++++++++++++++++++ tests/meshworker/scratch_data_01.output | 13 +++ 2 files changed, 154 insertions(+) create mode 100644 tests/meshworker/scratch_data_01.cc create mode 100644 tests/meshworker/scratch_data_01.output diff --git a/tests/meshworker/scratch_data_01.cc b/tests/meshworker/scratch_data_01.cc new file mode 100644 index 000000000000..52dec187939e --- /dev/null +++ b/tests/meshworker/scratch_data_01.cc @@ -0,0 +1,141 @@ +/* --------------------------------------------------------------------- + * + * 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. + * + * --------------------------------------------------------------------- + */ + +// Test ScratchData on simple volume computation + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "../tests.h" + +using namespace MeshWorker; + +template +void +test() +{ + Triangulation tria; + FE_Q fe(1); + DoFHandler dh(tria); + GridGenerator::hyper_cube(tria); + tria.refine_global(1); + tria.begin_active()->set_refine_flag(); + tria.execute_coarsening_and_refinement(); + dh.distribute_dofs(fe); + + QGauss quad(3); + QGauss face_quad(3); + + UpdateFlags cell_flags = update_JxW_values; + UpdateFlags face_flags = update_JxW_values; + + using ScratchData = MeshWorker::ScratchData; + using CopyData = MeshWorker::CopyData<0, 1, 0>; + + ScratchData scratch(fe, quad, cell_flags, face_quad, face_flags); + CopyData copy(3); // store measures + + auto cell = dh.begin_active(); + auto endc = dh.end(); + + typedef decltype(cell) Iterator; + + auto measures = std::make_tuple(0.0, 0.0, 0.0); + + + auto cell_worker = [](const Iterator &cell, ScratchData &s, CopyData &c) { + const auto &fev = s.reinit(cell); + const auto &JxW = s.get_JxW_values(); + c = 0; + for (auto w : JxW) + c.vectors[0][0] += w; + }; + + auto boundary_worker = [](const Iterator & cell, + const unsigned int &f, + ScratchData & s, + CopyData & c) { + const auto &fev = s.reinit(cell, f); + const auto &JxW = s.get_JxW_values(); + for (auto w : JxW) + c.vectors[0][1] += w; + }; + + auto face_worker = [](const Iterator & cell, + const unsigned int &f, + const unsigned int &sf, + const Iterator & ncell, + const unsigned int &nf, + const unsigned int &nsf, + ScratchData & s, + CopyData & c) { + const auto &fev = s.reinit(cell, f, sf); + const auto &nfev = s.reinit_neighbor(ncell, nf, nsf); + + const auto &JxW = s.get_JxW_values(); + const auto &nJxW = s.get_neighbor_JxW_values(); + for (auto w : JxW) + c.vectors[0][2] += w; + }; + + auto copier = [&measures](const CopyData &c) { + std::get<0>(measures) += c.vectors[0][0]; + std::get<1>(measures) += c.vectors[0][1]; + std::get<2>(measures) += c.vectors[0][2]; + }; + + mesh_loop(cell, + endc, + cell_worker, + copier, + scratch, + copy, + assemble_own_cells | assemble_boundary_faces | + assemble_own_interior_faces_once, + boundary_worker, + face_worker); + + deallog << "Testing <" << dim << "," << spacedim << ">" << std::endl; + + deallog << "Volume: " << std::get<0>(measures) << std::endl; + + deallog << "Boundary surface: " << std::get<1>(measures) << std::endl; + + deallog << "Interior surface: " << std::get<2>(measures) << std::endl; +} + + + +int +main() +{ + initlog(); + + test<2, 2>(); + test<2, 3>(); + test<3, 3>(); +} diff --git a/tests/meshworker/scratch_data_01.output b/tests/meshworker/scratch_data_01.output new file mode 100644 index 000000000000..b9c1ecd3d347 --- /dev/null +++ b/tests/meshworker/scratch_data_01.output @@ -0,0 +1,13 @@ + +DEAL::Testing <2,2> +DEAL::Volume: 1.00000 +DEAL::Boundary surface: 4.00000 +DEAL::Interior surface: 3.00000 +DEAL::Testing <2,3> +DEAL::Volume: 1.00000 +DEAL::Boundary surface: 4.00000 +DEAL::Interior surface: 3.00000 +DEAL::Testing <3,3> +DEAL::Volume: 1.00000 +DEAL::Boundary surface: 6.00000 +DEAL::Interior surface: 3.75000 From ccfcc960d721d97b3f790cb8da342c46b3868eca Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 9 Apr 2019 23:04:56 +0200 Subject: [PATCH 389/507] Test ScratchData for Laplacian (conforming) --- tests/meshworker/scratch_data_02.cc | 159 ++++++++++++++++++ ...02.with_muparser=on.with_umfpack=on.output | 2 + 2 files changed, 161 insertions(+) create mode 100644 tests/meshworker/scratch_data_02.cc create mode 100644 tests/meshworker/scratch_data_02.with_muparser=on.with_umfpack=on.output diff --git a/tests/meshworker/scratch_data_02.cc b/tests/meshworker/scratch_data_02.cc new file mode 100644 index 000000000000..d74bc90b0579 --- /dev/null +++ b/tests/meshworker/scratch_data_02.cc @@ -0,0 +1,159 @@ +/* --------------------------------------------------------------------- + * + * 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. + * + * --------------------------------------------------------------------- + */ + +// Check mesh_loop + ScratchData for Laplacian (conforming) + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "../tests.h" + +using namespace MeshWorker; + +template +void +test() +{ + Triangulation tria; + FE_Q fe(1); + DoFHandler dh(tria); + + FunctionParser rhs_function("1"); + FunctionParser boundary_function("0"); + + AffineConstraints constraints; + + GridGenerator::hyper_cube(tria); + tria.refine_global(5); + tria.execute_coarsening_and_refinement(); + dh.distribute_dofs(fe); + + + DoFTools::make_hanging_node_constraints(dh, constraints); + VectorTools::interpolate_boundary_values(dh, + 0, + boundary_function, + constraints); + + constraints.close(); + + SparsityPattern sparsity; + + { + DynamicSparsityPattern dsp(dh.n_dofs(), dh.n_dofs()); + DoFTools::make_flux_sparsity_pattern(dh, dsp); + sparsity.copy_from(dsp); + } + + SparseMatrix matrix; + matrix.reinit(sparsity); + + Vector solution(dh.n_dofs()); + Vector rhs(dh.n_dofs()); + + QGauss quad(3); + QGauss face_quad(3); + + UpdateFlags cell_flags = update_values | update_gradients | + update_quadrature_points | update_JxW_values; + UpdateFlags face_flags = update_JxW_values; + + using ScratchData = MeshWorker::ScratchData; + using CopyData = MeshWorker::CopyData<1, 1, 1>; + + ScratchData scratch(fe, quad, cell_flags, face_quad, face_flags); + CopyData copy(fe.dofs_per_cell); + + auto cell = dh.begin_active(); + auto endc = dh.end(); + + typedef decltype(cell) Iterator; + + auto cell_worker = + [&rhs_function](const Iterator &cell, ScratchData &s, CopyData &c) { + const auto &fev = s.reinit(cell); + const auto &JxW = s.get_JxW_values(); + const auto &p = s.get_quadrature_points(); + + c = 0; + + c.local_dof_indices[0] = s.get_local_dof_indices(); + + for (unsigned int q = 0; q < p.size(); ++q) + for (unsigned int i = 0; i < fev.dofs_per_cell; ++i) + { + for (unsigned int j = 0; j < fev.dofs_per_cell; ++j) + { + c.matrices[0](i, j) += + fev.shape_grad(i, q) * fev.shape_grad(j, q) * JxW[q]; + } + c.vectors[0](i) += + fev.shape_value(i, q) * rhs_function.value(p[q]) * JxW[q]; + } + }; + + auto copier = [&constraints, &matrix, &rhs](const CopyData &c) { + constraints.distribute_local_to_global( + c.matrices[0], c.vectors[0], c.local_dof_indices[0], matrix, rhs); + }; + + mesh_loop(cell, endc, cell_worker, copier, scratch, copy, assemble_own_cells); + + SparseDirectUMFPACK inv; + inv.initialize(matrix); + + inv.vmult(solution, rhs); + constraints.distribute(solution); + + deallog << "Linfty norm of solution: " << solution.linfty_norm() << std::endl; +} + + +int +main() +{ + initlog(); + + test<2, 2>(); +} diff --git a/tests/meshworker/scratch_data_02.with_muparser=on.with_umfpack=on.output b/tests/meshworker/scratch_data_02.with_muparser=on.with_umfpack=on.output new file mode 100644 index 000000000000..b5ad838ee801 --- /dev/null +++ b/tests/meshworker/scratch_data_02.with_muparser=on.with_umfpack=on.output @@ -0,0 +1,2 @@ + +DEAL::Linfty norm of solution: 0.0737281 From 7d6357304090cccb8407443d95cf90be94012eed Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 9 Apr 2019 23:05:08 +0200 Subject: [PATCH 390/507] Test ScratchData for Laplacian (SIPDG) --- tests/meshworker/scratch_data_03.cc | 240 ++++++++++++++++++ ...03.with_muparser=on.with_umfpack=on.output | 2 + 2 files changed, 242 insertions(+) create mode 100644 tests/meshworker/scratch_data_03.cc create mode 100644 tests/meshworker/scratch_data_03.with_muparser=on.with_umfpack=on.output diff --git a/tests/meshworker/scratch_data_03.cc b/tests/meshworker/scratch_data_03.cc new file mode 100644 index 000000000000..c8dd6ebf9a52 --- /dev/null +++ b/tests/meshworker/scratch_data_03.cc @@ -0,0 +1,240 @@ +/* --------------------------------------------------------------------- + * + * 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. + * + * --------------------------------------------------------------------- + */ + +// Solve Laplacian using SIPG + mesh_loop + ScratchData + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "../tests.h" + +using namespace MeshWorker; + +template +void +test() +{ + Triangulation tria; + FE_DGQ fe(1); + DoFHandler dh(tria); + + FunctionParser rhs_function("1"); + FunctionParser boundary_function("0"); + + AffineConstraints constraints; + constraints.close(); + + GridGenerator::hyper_cube(tria); + tria.refine_global(5); + tria.execute_coarsening_and_refinement(); + dh.distribute_dofs(fe); + + + SparsityPattern sparsity; + + { + DynamicSparsityPattern dsp(dh.n_dofs(), dh.n_dofs()); + DoFTools::make_flux_sparsity_pattern(dh, dsp); + sparsity.copy_from(dsp); + } + + SparseMatrix matrix; + matrix.reinit(sparsity); + + Vector solution(dh.n_dofs()); + Vector rhs(dh.n_dofs()); + + QGauss quad(3); + QGauss face_quad(3); + + UpdateFlags cell_flags = update_values | update_gradients | + update_quadrature_points | update_JxW_values; + UpdateFlags face_flags = update_values | update_gradients | + update_quadrature_points | + update_face_normal_vectors | update_JxW_values; + + // Stabilization for SIPG + double gamma = 100; + + using ScratchData = MeshWorker::ScratchData; + using CopyData = MeshWorker::CopyData<1 + GeometryInfo::faces_per_cell, + 1, + 1 + GeometryInfo::faces_per_cell>; + + ScratchData scratch(fe, quad, cell_flags, face_quad, face_flags); + CopyData copy(fe.dofs_per_cell); + + auto cell = dh.begin_active(); + auto endc = dh.end(); + + typedef decltype(cell) Iterator; + + auto cell_worker = + [&rhs_function](const Iterator &cell, ScratchData &s, CopyData &c) { + const auto &fev = s.reinit(cell); + const auto &JxW = s.get_JxW_values(); + const auto &p = s.get_quadrature_points(); + + c = 0; + + c.local_dof_indices[0] = s.get_local_dof_indices(); + + for (unsigned int q = 0; q < p.size(); ++q) + for (unsigned int i = 0; i < fev.dofs_per_cell; ++i) + { + for (unsigned int j = 0; j < fev.dofs_per_cell; ++j) + { + c.matrices[0](i, j) += + fev.shape_grad(i, q) * fev.shape_grad(j, q) * JxW[q]; + } + c.vectors[0](i) += + fev.shape_value(i, q) * rhs_function.value(p[q]) * JxW[q]; + } + }; + + auto boundary_worker = [gamma, &boundary_function](const Iterator & cell, + const unsigned int &f, + ScratchData & s, + CopyData & c) { + const auto &fev = s.reinit(cell, f); + const auto &JxW = s.get_JxW_values(); + const auto &p = s.get_quadrature_points(); + const auto &n = s.get_normal_vectors(); + + for (unsigned int q = 0; q < p.size(); ++q) + for (unsigned int i = 0; i < fev.dofs_per_cell; ++i) + { + for (unsigned int j = 0; j < fev.dofs_per_cell; ++j) + { + c.matrices[0](i, j) += + (-fev.shape_grad(i, q) * n[q] * fev.shape_value(j, q) + + -fev.shape_grad(j, q) * n[q] * fev.shape_value(i, q) + + gamma / cell->face(f)->diameter() * fev.shape_value(i, q) * + fev.shape_value(j, q)) * + JxW[q]; + } + c.vectors[0](i) += + ((gamma / cell->face(f)->diameter() * fev.shape_value(i, q) - + fev.shape_grad(i, q) * n[q]) * + boundary_function.value(p[q])) * + JxW[q]; + } + }; + + auto face_worker = [gamma](const Iterator & cell, + const unsigned int &f, + const unsigned int &sf, + const Iterator & ncell, + const unsigned int &nf, + const unsigned int &nsf, + ScratchData & s, + CopyData & c) { + const auto &fev = s.reinit(cell, f, sf); + const auto &JxW = s.get_JxW_values(); + const auto &nfev = s.reinit_neighbor(ncell, nf, nsf); + + c.local_dof_indices[f + 1] = s.get_neighbor_dof_indices(); + + const auto &p = s.get_quadrature_points(); + const auto &n = s.get_normal_vectors(); + const auto &nn = s.get_neighbor_normal_vectors(); + + const double gh = gamma / cell->face(f)->diameter(); + + for (unsigned int q = 0; q < p.size(); ++q) + for (unsigned int i = 0; i < fev.dofs_per_cell; ++i) + for (unsigned int j = 0; j < fev.dofs_per_cell; ++j) + { + c.matrices[0](i, j) += + (-.5 * fev.shape_grad(i, q) * n[q] * fev.shape_value(j, q) + + -.5 * fev.shape_value(i, q) * n[q] * fev.shape_grad(j, q) + + gh * fev.shape_value(i, q) * fev.shape_value(j, q)) * + JxW[q]; + + c.matrices[f + 1](i, j) += + (-.5 * fev.shape_grad(i, q) * nn[q] * nfev.shape_value(j, q) + + -.5 * fev.shape_value(i, q) * n[q] * nfev.shape_grad(j, q) - + gh * fev.shape_value(i, q) * nfev.shape_value(j, q)) * + JxW[q]; + } + }; + + auto copier = [&constraints, &matrix, &rhs](const CopyData &c) { + constraints.distribute_local_to_global( + c.matrices[0], c.vectors[0], c.local_dof_indices[0], matrix, rhs); + + for (unsigned int f = 0; f < GeometryInfo::faces_per_cell; ++f) + constraints.distribute_local_to_global(c.matrices[1 + f], + c.local_dof_indices[0], + c.local_dof_indices[1 + f], + matrix); + }; + + mesh_loop(cell, + endc, + cell_worker, + copier, + scratch, + copy, + assemble_own_cells | assemble_boundary_faces | + assemble_own_interior_faces_both, + boundary_worker, + face_worker); + + SparseDirectUMFPACK inv; + inv.initialize(matrix); + + inv.vmult(solution, rhs); + constraints.distribute(solution); + + deallog << "Linfty norm of solution " << solution.linfty_norm() << std::endl; +} + + +int +main() +{ + initlog(); + test<2, 2>(); +} diff --git a/tests/meshworker/scratch_data_03.with_muparser=on.with_umfpack=on.output b/tests/meshworker/scratch_data_03.with_muparser=on.with_umfpack=on.output new file mode 100644 index 000000000000..1b2777af1658 --- /dev/null +++ b/tests/meshworker/scratch_data_03.with_muparser=on.with_umfpack=on.output @@ -0,0 +1,2 @@ + +DEAL::Linfty norm of solution 0.0737281 From c4a8e9cadee0a4e53eeca593bddc52265189d636 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 9 Apr 2019 23:05:17 +0200 Subject: [PATCH 391/507] Test ScratchData get_values --- tests/meshworker/scratch_data_04.cc | 131 ++++++++++++++++++ .../scratch_data_04.with_muparser=on.output | 2 + 2 files changed, 133 insertions(+) create mode 100644 tests/meshworker/scratch_data_04.cc create mode 100644 tests/meshworker/scratch_data_04.with_muparser=on.output diff --git a/tests/meshworker/scratch_data_04.cc b/tests/meshworker/scratch_data_04.cc new file mode 100644 index 000000000000..48877551557f --- /dev/null +++ b/tests/meshworker/scratch_data_04.cc @@ -0,0 +1,131 @@ +/* --------------------------------------------------------------------- + * + * 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. + * + * --------------------------------------------------------------------- + */ + +// Compute integral of known function using mesh_loop and ScratchData + +#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 "../tests.h" + +using namespace MeshWorker; + +template +void +test() +{ + Triangulation tria; + FE_Q fe(1); + DoFHandler dh(tria); + + FunctionParser integral_function("x"); + GridGenerator::hyper_cube(tria); + tria.refine_global(5); + tria.execute_coarsening_and_refinement(); + dh.distribute_dofs(fe); + + Vector solution(dh.n_dofs()); + + VectorTools::interpolate(dh, integral_function, solution); + + QGauss quad(3); + + UpdateFlags cell_flags = update_values | update_gradients | + update_quadrature_points | update_JxW_values; + + using ScratchData = ScratchData; + struct CopyData + {}; + + + double H1_norm = 0; + FEValuesExtractors::Scalar scalar(0); + + ScratchData scratch(fe, quad, cell_flags); + CopyData copy; + + auto cell = dh.begin_active(); + auto endc = dh.end(); + + typedef decltype(cell) Iterator; + + + auto cell_integrator = [&H1_norm, &solution, &scalar](const Iterator &cell, + ScratchData & s, + CopyData & c) { + const auto &fev = s.reinit(cell); + const auto &JxW = s.get_JxW_values(); + + s.extract_local_dof_values("solution", solution); + + const auto &u = s.get_values("solution", scalar); + const auto &grad_u = s.get_gradients("solution", scalar); + + for (unsigned int q = 0; q < u.size(); ++q) + H1_norm += (u[q] * u[q] + grad_u[q] * grad_u[q]) * JxW[q]; + }; + + const auto empty_copyer = [](const CopyData &) {}; + + mesh_loop(cell, + endc, + cell_integrator, + empty_copyer, + scratch, + copy, + assemble_own_cells); + + deallog << "H1 norm: " << std::sqrt(H1_norm) << std::endl; +} + + +int +main() +{ + initlog(1); + MultithreadInfo::set_thread_limit(1); // to make output deterministic + + test<2, 2>(); +} diff --git a/tests/meshworker/scratch_data_04.with_muparser=on.output b/tests/meshworker/scratch_data_04.with_muparser=on.output new file mode 100644 index 000000000000..b906801d0d6e --- /dev/null +++ b/tests/meshworker/scratch_data_04.with_muparser=on.output @@ -0,0 +1,2 @@ + +DEAL::H1 norm: 1.15470 From da5071eb97fb2c287e666f7da846ac0f61d18421 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 9 Apr 2019 23:05:28 +0200 Subject: [PATCH 392/507] ScratchData with Sacado applied to Residual --- tests/meshworker/scratch_data_05.cc | 178 ++++++++++++++++++ ...on.with_muparser=on.with_umfpack=on.output | 2 + 2 files changed, 180 insertions(+) create mode 100644 tests/meshworker/scratch_data_05.cc create mode 100644 tests/meshworker/scratch_data_05.with_trilinos=on.with_muparser=on.with_umfpack=on.output diff --git a/tests/meshworker/scratch_data_05.cc b/tests/meshworker/scratch_data_05.cc new file mode 100644 index 000000000000..1d72bead03b8 --- /dev/null +++ b/tests/meshworker/scratch_data_05.cc @@ -0,0 +1,178 @@ +/* --------------------------------------------------------------------- + * + * 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. + * + * --------------------------------------------------------------------- + */ + +// Compute Laplacian using mesh_loop, sacado, and ScratchData + +#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 "../tests.h" + +using namespace MeshWorker; + +typedef Sacado::Fad::DFad Sdouble; +typedef Sacado::Fad::DFad SSdouble; + +template +void +test() +{ + Triangulation tria; + FE_Q fe(1); + DoFHandler dh(tria); + + FunctionParser rhs_function("1"); + FunctionParser boundary_function("0"); + + AffineConstraints constraints; + + GridGenerator::hyper_cube(tria); + tria.refine_global(5); + tria.execute_coarsening_and_refinement(); + dh.distribute_dofs(fe); + + + DoFTools::make_hanging_node_constraints(dh, constraints); + VectorTools::interpolate_boundary_values(dh, + 0, + boundary_function, + constraints); + + constraints.close(); + + SparsityPattern sparsity; + + { + DynamicSparsityPattern dsp(dh.n_dofs(), dh.n_dofs()); + DoFTools::make_flux_sparsity_pattern(dh, dsp); + sparsity.copy_from(dsp); + } + + SparseMatrix matrix; + matrix.reinit(sparsity); + + Vector solution(dh.n_dofs()); + Vector rhs(dh.n_dofs()); + + QGauss quad(3); + + UpdateFlags cell_flags = update_values | update_gradients | + update_quadrature_points | update_JxW_values; + + using ScratchData = MeshWorker::ScratchData; + using CopyData = MeshWorker::CopyData<1, 1, 1>; + + ScratchData scratch(fe, quad, cell_flags); + CopyData copy(fe.dofs_per_cell); + + auto cell = dh.begin_active(); + auto endc = dh.end(); + + typedef decltype(cell) Iterator; + + FEValuesExtractors::Scalar scalar(0); + + auto cell_worker = [&rhs_function, &solution, &scalar](const Iterator &cell, + ScratchData & s, + CopyData & c) { + const auto &fev = s.reinit(cell); + const auto &JxW = s.get_JxW_values(); + const auto &p = s.get_quadrature_points(); + + Sdouble dummy; + std::vector residual(fev.dofs_per_cell, Sdouble(0)); + + s.extract_local_dof_values("solution", solution, dummy); + const auto &u = s.get_values("solution", scalar, dummy); + const auto &grad_u = s.get_gradients("solution", scalar, dummy); + + c = 0; + + c.local_dof_indices[0] = s.get_local_dof_indices(); + + for (unsigned int i = 0; i < fev.dofs_per_cell; ++i) + for (unsigned int q = 0; q < p.size(); ++q) + { + residual[i] += (fev.shape_grad(i, q) * grad_u[q] - + rhs_function.value(p[q]) * fev.shape_value(i, q)) * + JxW[q]; + } + + // Copy from Sacado to normal vectors + for (unsigned int i = 0; i < fev.dofs_per_cell; ++i) + { + c.vectors[0][i] = -residual[i].val(); + for (unsigned int j = 0; j < fev.dofs_per_cell; ++j) + c.matrices[0](i, j) = residual[i].dx(j); + } + }; + + auto copier = [&constraints, &matrix, &rhs](const CopyData &c) { + constraints.distribute_local_to_global( + c.matrices[0], c.vectors[0], c.local_dof_indices[0], matrix, rhs); + }; + + mesh_loop(cell, endc, cell_worker, copier, scratch, copy, assemble_own_cells); + + SparseDirectUMFPACK inv; + inv.initialize(matrix); + + inv.vmult(solution, rhs); + constraints.distribute(solution); + + deallog << "Linfty norm of solution: " << solution.linfty_norm() << std::endl; +} + + +int +main() +{ + initlog(1); + MultithreadInfo::set_thread_limit(1); // to make output deterministic + + test<2, 2>(); +} diff --git a/tests/meshworker/scratch_data_05.with_trilinos=on.with_muparser=on.with_umfpack=on.output b/tests/meshworker/scratch_data_05.with_trilinos=on.with_muparser=on.with_umfpack=on.output new file mode 100644 index 000000000000..b5ad838ee801 --- /dev/null +++ b/tests/meshworker/scratch_data_05.with_trilinos=on.with_muparser=on.with_umfpack=on.output @@ -0,0 +1,2 @@ + +DEAL::Linfty norm of solution: 0.0737281 From 07af92a315cbe64494ecc6e38912d74c846fde10 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 9 Apr 2019 23:05:35 +0200 Subject: [PATCH 393/507] ScratchData + Sacado applied to energies --- tests/meshworker/scratch_data_06.cc | 177 ++++++++++++++++++ ...on.with_muparser=on.with_umfpack=on.output | 2 + 2 files changed, 179 insertions(+) create mode 100644 tests/meshworker/scratch_data_06.cc create mode 100644 tests/meshworker/scratch_data_06.with_trilinos=on.with_muparser=on.with_umfpack=on.output diff --git a/tests/meshworker/scratch_data_06.cc b/tests/meshworker/scratch_data_06.cc new file mode 100644 index 000000000000..9dd081d08264 --- /dev/null +++ b/tests/meshworker/scratch_data_06.cc @@ -0,0 +1,177 @@ +/* --------------------------------------------------------------------- + * + * 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. + * + * --------------------------------------------------------------------- + */ + +// Compute Laplacian using mesh_loop, sacado, ScratchData, with +// second derivatives. + +#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 "../tests.h" + +using namespace MeshWorker; + +typedef Sacado::Fad::DFad Sdouble; +typedef Sacado::Fad::DFad SSdouble; + +template +void +test() +{ + Triangulation tria; + FE_Q fe(1); + DoFHandler dh(tria); + + FunctionParser rhs_function("1"); + FunctionParser boundary_function("0"); + + AffineConstraints constraints; + + GridGenerator::hyper_cube(tria); + tria.refine_global(5); + tria.execute_coarsening_and_refinement(); + dh.distribute_dofs(fe); + + + DoFTools::make_hanging_node_constraints(dh, constraints); + VectorTools::interpolate_boundary_values(dh, + 0, + boundary_function, + constraints); + + constraints.close(); + + SparsityPattern sparsity; + + { + DynamicSparsityPattern dsp(dh.n_dofs(), dh.n_dofs()); + DoFTools::make_flux_sparsity_pattern(dh, dsp); + sparsity.copy_from(dsp); + } + + SparseMatrix matrix; + matrix.reinit(sparsity); + + Vector solution(dh.n_dofs()); + Vector rhs(dh.n_dofs()); + + QGauss quad(3); + + UpdateFlags cell_flags = update_values | update_gradients | + update_quadrature_points | update_JxW_values; + + using ScratchData = MeshWorker::ScratchData; + using CopyData = MeshWorker::CopyData<1, 1, 1>; + + ScratchData scratch(fe, quad, cell_flags); + CopyData copy(fe.dofs_per_cell); + + auto cell = dh.begin_active(); + auto endc = dh.end(); + + typedef decltype(cell) Iterator; + + FEValuesExtractors::Scalar scalar(0); + + auto cell_worker = [&rhs_function, &solution, &scalar](const Iterator &cell, + ScratchData & s, + CopyData & c) { + const auto &fev = s.reinit(cell); + const auto &JxW = s.get_JxW_values(); + const auto &p = s.get_quadrature_points(); + + SSdouble energy(0); + + s.extract_local_dof_values("solution", solution, energy); + const auto &u = s.get_values("solution", scalar, energy); + const auto &grad_u = s.get_gradients("solution", scalar, energy); + + c = 0; + + c.local_dof_indices[0] = s.get_local_dof_indices(); + + for (unsigned int q = 0; q < p.size(); ++q) + { + energy += + (.5 * grad_u[q] * grad_u[q] - rhs_function.value(p[q]) * u[q]) * + JxW[q]; + } + + // Copy from Sacado to normal vectors + for (unsigned int i = 0; i < fev.dofs_per_cell; ++i) + { + c.vectors[0][i] = -energy.dx(i).val(); + for (unsigned int j = 0; j < fev.dofs_per_cell; ++j) + c.matrices[0](i, j) = energy.dx(i).dx(j); + } + }; + + auto copier = [&constraints, &matrix, &rhs](const CopyData &c) { + constraints.distribute_local_to_global( + c.matrices[0], c.vectors[0], c.local_dof_indices[0], matrix, rhs); + }; + + mesh_loop(cell, endc, cell_worker, copier, scratch, copy, assemble_own_cells); + + SparseDirectUMFPACK inv; + inv.initialize(matrix); + + inv.vmult(solution, rhs); + constraints.distribute(solution); + + deallog << "Linfty norm of solution: " << solution.linfty_norm() << std::endl; +} + + +int +main() +{ + initlog(1); + MultithreadInfo::set_thread_limit(1); // to make output deterministic + + test<2, 2>(); +} diff --git a/tests/meshworker/scratch_data_06.with_trilinos=on.with_muparser=on.with_umfpack=on.output b/tests/meshworker/scratch_data_06.with_trilinos=on.with_muparser=on.with_umfpack=on.output new file mode 100644 index 000000000000..b5ad838ee801 --- /dev/null +++ b/tests/meshworker/scratch_data_06.with_trilinos=on.with_muparser=on.with_umfpack=on.output @@ -0,0 +1,2 @@ + +DEAL::Linfty norm of solution: 0.0737281 From f9f9254334e929bfa5cc6ddc92452610eb8efdcf Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 9 Apr 2019 23:05:47 +0200 Subject: [PATCH 394/507] ScratchData + Sacado FD+RD applied to energies --- tests/meshworker/scratch_data_07.cc | 185 ++++++++++++++++++ ...on.with_muparser=on.with_umfpack=on.output | 2 + 2 files changed, 187 insertions(+) create mode 100644 tests/meshworker/scratch_data_07.cc create mode 100644 tests/meshworker/scratch_data_07.with_trilinos=on.with_muparser=on.with_umfpack=on.output diff --git a/tests/meshworker/scratch_data_07.cc b/tests/meshworker/scratch_data_07.cc new file mode 100644 index 000000000000..a1a4b13aee4f --- /dev/null +++ b/tests/meshworker/scratch_data_07.cc @@ -0,0 +1,185 @@ +/* --------------------------------------------------------------------- + * + * 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. + * + * --------------------------------------------------------------------- + */ + +// Compute Laplacian using mesh_loop, sacado, ScratchData, with +// second derivatives, using forward and backward derivatives. + +#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 "../tests.h" + +using namespace MeshWorker; + +typedef Sacado::Fad::DFad Sdouble; +typedef Sacado::Fad::DFad SSdouble; +typedef Sacado::Rad::ADvar RSdouble; + +template +void +test() +{ + Triangulation tria; + FE_Q fe(1); + DoFHandler dh(tria); + + FunctionParser rhs_function("1"); + FunctionParser boundary_function("0"); + + AffineConstraints constraints; + + GridGenerator::hyper_cube(tria); + tria.refine_global(5); + tria.execute_coarsening_and_refinement(); + dh.distribute_dofs(fe); + + + DoFTools::make_hanging_node_constraints(dh, constraints); + VectorTools::interpolate_boundary_values(dh, + 0, + boundary_function, + constraints); + + constraints.close(); + + SparsityPattern sparsity; + + { + DynamicSparsityPattern dsp(dh.n_dofs(), dh.n_dofs()); + DoFTools::make_flux_sparsity_pattern(dh, dsp); + sparsity.copy_from(dsp); + } + + SparseMatrix matrix; + matrix.reinit(sparsity); + + Vector solution(dh.n_dofs()); + Vector rhs(dh.n_dofs()); + + QGauss quad(3); + + UpdateFlags cell_flags = update_values | update_gradients | + update_quadrature_points | update_JxW_values; + + using ScratchData = MeshWorker::ScratchData; + using CopyData = MeshWorker::CopyData<1, 1, 1>; + + ScratchData scratch(fe, quad, cell_flags); + CopyData copy(fe.dofs_per_cell); + + auto cell = dh.begin_active(); + auto endc = dh.end(); + + typedef decltype(cell) Iterator; + + FEValuesExtractors::Scalar scalar(0); + + auto cell_worker = [&rhs_function, &solution, &scalar](const Iterator &cell, + ScratchData & s, + CopyData & c) { + const auto &fev = s.reinit(cell); + const auto &JxW = s.get_JxW_values(); + const auto &p = s.get_quadrature_points(); + + RSdouble energy(0); + + s.extract_local_dof_values("solution", solution, energy); + const auto &local_dof_values = s.get_local_dof_values("solution", energy); + const auto &u = s.get_values("solution", scalar, energy); + const auto &grad_u = s.get_gradients("solution", scalar, energy); + + c = 0; + + c.local_dof_indices[0] = s.get_local_dof_indices(); + + for (unsigned int q = 0; q < p.size(); ++q) + { + energy += + (.5 * grad_u[q] * grad_u[q] - rhs_function.value(p[q]) * u[q]) * + JxW[q]; + } + + // Compute derivatives of reverse-mode AD variables + RSdouble::Gradcomp(); + // Copy from Sacado to normal vectors + for (unsigned int i = 0; i < fev.dofs_per_cell; ++i) + { + // Compute the residual + const auto res_i = local_dof_values[i].adj(); + c.vectors[0][i] = -res_i.val(); + + // And the matrix + for (unsigned int j = 0; j < fev.dofs_per_cell; ++j) + c.matrices[0](i, j) = res_i.dx(j); + } + }; + + auto copier = [&constraints, &matrix, &rhs](const CopyData &c) { + constraints.distribute_local_to_global( + c.matrices[0], c.vectors[0], c.local_dof_indices[0], matrix, rhs); + }; + + mesh_loop(cell, endc, cell_worker, copier, scratch, copy, assemble_own_cells); + + SparseDirectUMFPACK inv; + inv.initialize(matrix); + + inv.vmult(solution, rhs); + constraints.distribute(solution); + + deallog << "Linfty norm of solution: " << solution.linfty_norm() << std::endl; +} + + +int +main() +{ + initlog(1); + MultithreadInfo::set_thread_limit(1); // to make output deterministic + + test<2, 2>(); +} diff --git a/tests/meshworker/scratch_data_07.with_trilinos=on.with_muparser=on.with_umfpack=on.output b/tests/meshworker/scratch_data_07.with_trilinos=on.with_muparser=on.with_umfpack=on.output new file mode 100644 index 000000000000..b5ad838ee801 --- /dev/null +++ b/tests/meshworker/scratch_data_07.with_trilinos=on.with_muparser=on.with_umfpack=on.output @@ -0,0 +1,2 @@ + +DEAL::Linfty norm of solution: 0.0737281 From 48301cc2693e7ce5ff3f2eb1e2b152bb1e2b1d8f Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 9 Apr 2019 23:05:59 +0200 Subject: [PATCH 395/507] ChangeLog --- doc/news/changes/minor/20190313LucaHeltai | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/news/changes/minor/20190313LucaHeltai 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) + From b69e909c2a8c1c4f5425c286b5404100e79aab8e Mon Sep 17 00:00:00 2001 From: Reza Rastak Date: Tue, 9 Apr 2019 22:38:14 -0700 Subject: [PATCH 396/507] Fixed documentation error in filtered_iterator.h --- include/deal.II/grid/filtered_iterator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/deal.II/grid/filtered_iterator.h b/include/deal.II/grid/filtered_iterator.h index 88f47c7a3bfb..0ee727aee79b 100644 --- a/include/deal.II/grid/filtered_iterator.h +++ b/include/deal.II/grid/filtered_iterator.h @@ -849,7 +849,7 @@ namespace internal * ... * const auto filtered_iterators_range = * filter_iterators(dof_handler.active_cell_iterators(), - * IteratorFilters::LocallyOwned()); + * IteratorFilters::LocallyOwnedCell()); * for (const auto &cell : filtered_iterators_range) * { * fe_values.reinit (cell); From 431cc648927fc59e1173b7791e7655d591759835 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Wed, 10 Apr 2019 18:50:34 +0200 Subject: [PATCH 397/507] Comments. --- include/deal.II/meshworker/copy_data.h | 6 +++--- include/deal.II/meshworker/scratch_data.h | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/deal.II/meshworker/copy_data.h b/include/deal.II/meshworker/copy_data.h index 252f4bab6e31..d3c1549e3f17 100644 --- a/include/deal.II/meshworker/copy_data.h +++ b/include/deal.II/meshworker/copy_data.h @@ -40,9 +40,9 @@ namespace MeshWorker * * In particular, you can specify the following template arguments * - * - @p n_matrices: Size of the array of matrices - * - @p n_vectors: size of the array of vectors - * - @p n_dof_indices: size of the array of local dof indices + * - @tparam n_matrices: Size of the array of matrices + * - @tparam n_vectors: size of the array of vectors + * - @tparam n_dof_indices: size of the array of local dof indices * * @author Luca Heltai, 2019. */ diff --git a/include/deal.II/meshworker/scratch_data.h b/include/deal.II/meshworker/scratch_data.h index c249357c0824..6b466286164e 100644 --- a/include/deal.II/meshworker/scratch_data.h +++ b/include/deal.II/meshworker/scratch_data.h @@ -212,15 +212,15 @@ namespace MeshWorker * When using this class, please cite * @code{.bib} * @article{SartoriGiulianiBardelloni-2018-a, - * Author = {Sartori, Alberto and Giuliani, Nicola and + * 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}}, - * Doi = {10.1016/j.softx.2018.09.004}, - * Volume = {7}, - * Year = {2018}} + * Pages = {318--327}, + * Title = {{deal2lkit: A toolkit library for high performance + * programming in deal.II}}, + * Doi = {10.1016/j.softx.2018.09.004}, + * Volume = {7}, + * Year = {2018}} * @endcode * * @author Luca Heltai, 2019. From c6e49c5d7f5604eef01433c9a4263c9512edd62b Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Wed, 10 Apr 2019 22:35:20 +0200 Subject: [PATCH 398/507] defgroup -> name --- include/deal.II/meshworker/scratch_data.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/deal.II/meshworker/scratch_data.h b/include/deal.II/meshworker/scratch_data.h index 6b466286164e..5c4088d5baaa 100644 --- a/include/deal.II/meshworker/scratch_data.h +++ b/include/deal.II/meshworker/scratch_data.h @@ -334,7 +334,7 @@ namespace MeshWorker ScratchData(const ScratchData &scratch); /** - * \defgroup CurrentCellMethos Methods to work on current cell + * @name CurrentCellMethos Methods to work on current cell */ /**@{*/ @@ -416,7 +416,7 @@ namespace MeshWorker /** @} */ // CurrentCellMethods /** - * @defgroup NeighborCellMethods Methods to work on neighbor cell + * @name NeighborCellMethods Methods to work on neighbor cell */ /** @{ */ @@ -502,7 +502,7 @@ namespace MeshWorker GeneralDataStorage & get_general_data_storage(); - /** @defgroup CurrentCellEvaluation Evaluation of finite element fields + /** @name CurrentCellEvaluation Evaluation of finite element fields * and their derivatives on the current cell * @{ */ From f9178378db4981fd64446b8b4202f6c0b2cdc2f0 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 11 Apr 2019 14:54:15 +0200 Subject: [PATCH 399/507] Replace std::make_unique by std_cxx14::make_unique --- source/meshworker/scratch_data.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/source/meshworker/scratch_data.cc b/source/meshworker/scratch_data.cc index 8e6e8708c8fe..c55c72e77e64 100644 --- a/source/meshworker/scratch_data.cc +++ b/source/meshworker/scratch_data.cc @@ -128,10 +128,8 @@ namespace MeshWorker const typename DoFHandler::active_cell_iterator &cell) { if (!fe_values) - fe_values = std::make_unique>(*mapping, - *fe, - cell_quadrature, - cell_update_flags); + fe_values = std_cxx14::make_unique>( + *mapping, *fe, cell_quadrature, cell_update_flags); fe_values->reinit(cell); cell->get_dof_indices(local_dof_indices); @@ -148,7 +146,7 @@ namespace MeshWorker const unsigned int face_no) { if (!fe_face_values) - fe_face_values = std::make_unique>( + fe_face_values = std_cxx14::make_unique>( *mapping, *fe, face_quadrature, face_update_flags); fe_face_values->reinit(cell, face_no); @@ -169,8 +167,9 @@ namespace MeshWorker if (subface_no != numbers::invalid_unsigned_int) { if (!fe_subface_values) - fe_subface_values = std::make_unique>( - *mapping, *fe, face_quadrature, face_update_flags); + fe_subface_values = + std_cxx14::make_unique>( + *mapping, *fe, face_quadrature, face_update_flags); fe_subface_values->reinit(cell, face_no, subface_no); cell->get_dof_indices(local_dof_indices); @@ -189,7 +188,7 @@ namespace MeshWorker const typename DoFHandler::active_cell_iterator &cell) { if (!neighbor_fe_values) - neighbor_fe_values = std::make_unique>( + neighbor_fe_values = std_cxx14::make_unique>( *mapping, *fe, cell_quadrature, neighbor_cell_update_flags); neighbor_fe_values->reinit(cell); @@ -207,8 +206,9 @@ namespace MeshWorker const unsigned int face_no) { if (!neighbor_fe_face_values) - neighbor_fe_face_values = std::make_unique>( - *mapping, *fe, face_quadrature, neighbor_face_update_flags); + neighbor_fe_face_values = + std_cxx14::make_unique>( + *mapping, *fe, face_quadrature, neighbor_face_update_flags); neighbor_fe_face_values->reinit(cell, face_no); cell->get_dof_indices(neighbor_dof_indices); current_neighbor_fe_values = neighbor_fe_face_values.get(); @@ -228,7 +228,7 @@ namespace MeshWorker { if (!neighbor_fe_subface_values) neighbor_fe_subface_values = - std::make_unique>( + std_cxx14::make_unique>( *mapping, *fe, face_quadrature, neighbor_face_update_flags); neighbor_fe_subface_values->reinit(cell, face_no, subface_no); cell->get_dof_indices(neighbor_dof_indices); @@ -353,4 +353,4 @@ namespace MeshWorker { #include "scratch_data.inst" } -DEAL_II_NAMESPACE_CLOSE \ No newline at end of file +DEAL_II_NAMESPACE_CLOSE From 69a1d048aa702a5ca320f9de22a6b859960b07be Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 9 Apr 2019 04:26:59 +0200 Subject: [PATCH 400/507] Use std::string in SmartPointer and Subscriptor interface --- doc/news/changes/minor/20190408Arndt | 4 ++ include/deal.II/base/smartpointer.h | 6 +-- include/deal.II/base/subscriptor.h | 38 ++----------------- source/base/subscriptor.cc | 11 +++--- .../base/unsubscribe_subscriptor.debug.output | 4 +- ...subscribe_subscriptor.debug.output.clang-6 | 4 +- ...unsubscribe_subscriptor.debug.output.intel | 4 +- 7 files changed, 22 insertions(+), 49 deletions(-) create mode 100644 doc/news/changes/minor/20190408Arndt 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/include/deal.II/base/smartpointer.h b/include/deal.II/base/smartpointer.h index 82066b872a94..a27fce37afa3 100644 --- a/include/deal.II/base/smartpointer.h +++ b/include/deal.II/base/smartpointer.h @@ -95,7 +95,7 @@ class SmartPointer * The id is used in the call to Subscriptor::subscribe(id) and by * ~SmartPointer() in the call to Subscriptor::unsubscribe(). */ - SmartPointer(T *t, const char *id); + SmartPointer(T *t, const std::string &id); /** * Constructor taking a normal pointer. If possible, i.e. if the pointer is @@ -200,7 +200,7 @@ class SmartPointer /** * The identification for the subscriptor. */ - const char *const id; + const std::string id; /** * The Smartpointer is invalidated when the object pointed to is destroyed @@ -235,7 +235,7 @@ inline SmartPointer::SmartPointer(T *t) template -inline SmartPointer::SmartPointer(T *t, const char *id) +inline SmartPointer::SmartPointer(T *t, const std::string &id) : t(t) , id(id) , pointed_to_object_is_alive(false) diff --git a/include/deal.II/base/subscriptor.h b/include/deal.II/base/subscriptor.h index aae53ff17d17..cd07834741d2 100644 --- a/include/deal.II/base/subscriptor.h +++ b/include/deal.II/base/subscriptor.h @@ -105,23 +105,11 @@ class Subscriptor /** * Subscribes a user of the object by storing the pointer @p validity. The - * subscriber may be identified by text supplied as @p identifier. The latter - * variable must not be a temporary and its type must decay to - * const char *. In particular, calling this function with a rvalue reference - * is not allowed. - */ - template - typename std::enable_if< - std::is_same::value>::type - subscribe(std::atomic *const validity, - ConstCharStar identifier = nullptr) const; - - /** - * Calling subscribe() with a rvalue reference as identifier is not allowed. + * subscriber may be identified by text supplied as @p identifier. */ void subscribe(std::atomic *const validity, - const char *&& identifier) const = delete; + const std::string & identifier = "") const; /** * Unsubscribes a user from the object. @@ -131,7 +119,7 @@ class Subscriptor */ void unsubscribe(std::atomic *const validity, - const char * identifier = nullptr) const; + const std::string & identifier = "") const; /** * Return the present number of subscriptions to this object. This allows to @@ -222,24 +210,11 @@ class Subscriptor */ mutable std::atomic counter; - /* - * Functor struct used for key comparison in #counter_map. - * Not the memory location but the actual C-string content is compared. - */ - struct MapCompare - { - bool - operator()(const char *lhs, const char *rhs) const - { - return std::strcmp(lhs, rhs) > 0; - } - }; - /** * In this map, we count subscriptions for each different identification * string supplied to subscribe(). */ - mutable std::map counter_map; + mutable std::map counter_map; /** * The data type used in #counter_map. @@ -340,11 +315,6 @@ Subscriptor::list_subscribers(StreamType &stream) const << it.first << '\"' << std::endl; } -// forward declare template specialization -template <> -void -Subscriptor::subscribe(std::atomic *const validity, - const char * id) const; DEAL_II_NAMESPACE_CLOSE #endif diff --git a/source/base/subscriptor.cc b/source/base/subscriptor.cc index 669f71b9092b..3aa98f2d5f7e 100644 --- a/source/base/subscriptor.cc +++ b/source/base/subscriptor.cc @@ -126,10 +126,9 @@ Subscriptor::operator=(Subscriptor &&s) noexcept -template <> void -Subscriptor::subscribe(std::atomic *const validity, - const char * id) const +Subscriptor::subscribe(std::atomic *const validity, + const std::string & id) const { std::lock_guard lock(mutex); @@ -137,7 +136,7 @@ Subscriptor::subscribe(std::atomic *const validity, object_info = &typeid(*this); ++counter; - const char *const name = (id != nullptr) ? id : unknown_subscriber; + const std::string name = (id != "") ? id : unknown_subscriber; map_iterator it = counter_map.find(name); if (it == counter_map.end()) @@ -153,9 +152,9 @@ Subscriptor::subscribe(std::atomic *const validity, void Subscriptor::unsubscribe(std::atomic *const validity, - const char * id) const + const std::string & id) const { - const char *name = (id != nullptr) ? id : unknown_subscriber; + const std::string name = (id != "") ? id : unknown_subscriber; if (counter == 0) { AssertNothrow(counter > 0, ExcNoSubscriber(object_info->name(), name)); diff --git a/tests/base/unsubscribe_subscriptor.debug.output b/tests/base/unsubscribe_subscriptor.debug.output index e0f38759735b..03bd8c6462bf 100644 --- a/tests/base/unsubscribe_subscriptor.debug.output +++ b/tests/base/unsubscribe_subscriptor.debug.output @@ -3,7 +3,7 @@ DEAL::Exception: ExcNoSubscriber(object_info->name(), name) DEAL:: -------------------------------------------------------- An error occurred in file in function - void dealii::Subscriptor::unsubscribe(std::atomic*, const char*) const + void dealii::Subscriptor::unsubscribe(std::atomic*, const string&) const The violated condition was: it != counter_map.end() Additional information: @@ -14,7 +14,7 @@ DEAL::Exception: ExcMessage( "This Subscriptor object does not know anything abo DEAL:: -------------------------------------------------------- An error occurred in file in function - void dealii::Subscriptor::unsubscribe(std::atomic*, const char*) const + void dealii::Subscriptor::unsubscribe(std::atomic*, const string&) const The violated condition was: validity_ptr_it != validity_pointers.end() Additional information: diff --git a/tests/base/unsubscribe_subscriptor.debug.output.clang-6 b/tests/base/unsubscribe_subscriptor.debug.output.clang-6 index 5c2e16e2dafb..41313921d204 100644 --- a/tests/base/unsubscribe_subscriptor.debug.output.clang-6 +++ b/tests/base/unsubscribe_subscriptor.debug.output.clang-6 @@ -3,7 +3,7 @@ DEAL::Exception: ExcNoSubscriber(object_info->name(), name) DEAL:: -------------------------------------------------------- An error occurred in file in function - void dealii::Subscriptor::unsubscribe(std::atomic *const, const char *) const + void dealii::Subscriptor::unsubscribe(std::atomic *const, const std::string &) const The violated condition was: it != counter_map.end() Additional information: @@ -14,7 +14,7 @@ DEAL::Exception: ExcMessage( "This Subscriptor object does not know anything abo DEAL:: -------------------------------------------------------- An error occurred in file in function - void dealii::Subscriptor::unsubscribe(std::atomic *const, const char *) const + void dealii::Subscriptor::unsubscribe(std::atomic *const, const std::string &) const The violated condition was: validity_ptr_it != validity_pointers.end() Additional information: diff --git a/tests/base/unsubscribe_subscriptor.debug.output.intel b/tests/base/unsubscribe_subscriptor.debug.output.intel index 76846bd70c11..4817452f841b 100644 --- a/tests/base/unsubscribe_subscriptor.debug.output.intel +++ b/tests/base/unsubscribe_subscriptor.debug.output.intel @@ -3,7 +3,7 @@ DEAL::Exception: ExcNoSubscriber(object_info->name(), name) DEAL:: -------------------------------------------------------- An error occurred in file in function - void dealii::Subscriptor::unsubscribe(std::atomic *, const char *) const + void dealii::Subscriptor::unsubscribe(std::atomic *, const std::__cxx11::basic_string, std::allocator> &) const The violated condition was: it != counter_map.end() Additional information: @@ -14,7 +14,7 @@ DEAL::Exception: ExcMessage( "This Subscriptor object does not know anything abo DEAL:: -------------------------------------------------------- An error occurred in file in function - void dealii::Subscriptor::unsubscribe(std::atomic *, const char *) const + void dealii::Subscriptor::unsubscribe(std::atomic *, const std::__cxx11::basic_string, std::allocator> &) const The violated condition was: validity_ptr_it != validity_pointers.end() Additional information: From dafa99c41eaa2baac2259159c4f738109be2a234 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 9 Apr 2019 14:11:48 +0200 Subject: [PATCH 401/507] Replace empty string comparison --- include/deal.II/lac/block_matrix_array.h | 2 +- include/deal.II/lac/swappable_vector.templates.h | 12 ++++++------ source/base/data_out_base.cc | 14 +++++++------- source/base/exceptions.cc | 2 +- source/base/parameter_acceptor.cc | 8 ++++---- source/base/parameter_handler.cc | 6 +++--- source/base/path_search.cc | 2 +- source/base/subscriptor.cc | 6 +++--- source/base/table_handler.cc | 4 ++-- source/base/timer.cc | 4 ++-- source/gmsh/utilities.cc | 2 +- source/grid/grid_in.cc | 2 +- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/include/deal.II/lac/block_matrix_array.h b/include/deal.II/lac/block_matrix_array.h index 75fd70b812bd..3f8a10223769 100644 --- a/include/deal.II/lac/block_matrix_array.h +++ b/include/deal.II/lac/block_matrix_array.h @@ -609,7 +609,7 @@ BlockMatrixArray::print_latex(StreamType &out) const std::ostringstream stream; - if (array(m->row, m->col) != "" && m->prefix >= 0) + if (!array(m->row, m->col).empty() && m->prefix >= 0) stream << "+"; if (m->prefix != 1.) stream << m->prefix << 'x'; diff --git a/include/deal.II/lac/swappable_vector.templates.h b/include/deal.II/lac/swappable_vector.templates.h index 54963f8920f5..74b39b7b722f 100644 --- a/include/deal.II/lac/swappable_vector.templates.h +++ b/include/deal.II/lac/swappable_vector.templates.h @@ -39,7 +39,7 @@ SwappableVector::SwappableVector(const SwappableVector &v) , filename() , data_is_preloaded(false) { - Assert(v.filename == "", ExcInvalidCopyOperation()); + Assert(v.filename.empty(), ExcInvalidCopyOperation()); } @@ -54,7 +54,7 @@ SwappableVector::~SwappableVector() // first, before killing the vector // itself - if (filename != "") + if (!filename.empty()) { try { @@ -72,7 +72,7 @@ SwappableVector & SwappableVector::operator=(const SwappableVector &v) { // if necessary, first delete data - if (filename != "") + if (!filename.empty()) kill_file(); // if in MT mode, block all other @@ -97,7 +97,7 @@ SwappableVector::swap_out(const std::string &name) // that has not been deleted in the // meantime, then we kill that file // first - if (filename != "") + if (!filename.empty()) kill_file(); filename = name; @@ -197,7 +197,7 @@ SwappableVector::reload_vector(const bool set_flag) { (void)set_flag; - Assert(filename != "", ExcInvalidFilename(filename)); + Assert(!filename.empty(), ExcInvalidFilename(filename)); Assert(this->size() == 0, ExcSizeNonzero()); std::ifstream tmp_in(filename.c_str()); @@ -233,7 +233,7 @@ SwappableVector::kill_file() // is most probably an error, not? Assert(data_is_preloaded == false, ExcInternalError()); - if (filename != "") + if (!filename.empty()) { int status = std::remove(filename.c_str()); (void)status; diff --git a/source/base/data_out_base.cc b/source/base/data_out_base.cc index 939c0c905042..719909c3dbd2 100644 --- a/source/base/data_out_base.cc +++ b/source/base/data_out_base.cc @@ -5345,7 +5345,7 @@ namespace DataOutBase // underscores unless a vector name has been specified out << "VECTORS "; - if (std::get<2>(nonscalar_data_range) != "") + if (!std::get<2>(nonscalar_data_range).empty()) out << std::get<2>(nonscalar_data_range); else { @@ -5580,7 +5580,7 @@ namespace DataOutBase // underscores unless a vector name has been specified out << " (nonscalar_data_range) != "") + if (!std::get<2>(nonscalar_data_range).empty()) out << std::get<2>(nonscalar_data_range); else { @@ -5811,7 +5811,7 @@ namespace DataOutBase // underscores unless a vector name has been specified out << " (nonscalar_data_range) != "") + if (!std::get<2>(nonscalar_data_range).empty()) out << std::get<2>(nonscalar_data_range); else { @@ -7820,7 +7820,7 @@ DataOutBase::write_filtered_data( // Determine the vector name. Concatenate all the component names with // double underscores unless a vector name has been specified - if (std::get<2>(nonscalar_data_ranges[n_th_vector]) != "") + if (!std::get<2>(nonscalar_data_ranges[n_th_vector]).empty()) { vector_name = std::get<2>(nonscalar_data_ranges[n_th_vector]); } @@ -8565,7 +8565,7 @@ DataOutInterface::validate_dataset_names() const for (const auto &range : ranges) { const std::string &name = std::get<2>(range); - if (name != "") + if (!name.empty()) { Assert(all_names.find(name) == all_names.end(), ExcMessage( @@ -9013,7 +9013,7 @@ namespace DataOutBase while ((header.size() != 0) && (header[header.size() - 1] == ' ')) header.erase(header.size() - 1); } - while ((header == "") && in); + while ((header.empty()) && in); std::ostringstream s; s << "[deal.II intermediate Patch<" << dim << ',' << spacedim << ">]"; diff --git a/source/base/exceptions.cc b/source/base/exceptions.cc index 412b3b008cc9..9d743306cbaf 100644 --- a/source/base/exceptions.cc +++ b/source/base/exceptions.cc @@ -147,7 +147,7 @@ const char * ExceptionBase::what() const noexcept { // If no error c_string was generated so far, do it now: - if (what_str == "") + if (what_str.empty()) { #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE // We have deferred the symbol lookup to this point to avoid costly diff --git a/source/base/parameter_acceptor.cc b/source/base/parameter_acceptor.cc index b239541c403f..da217ac3ca97 100644 --- a/source/base/parameter_acceptor.cc +++ b/source/base/parameter_acceptor.cc @@ -47,8 +47,8 @@ ParameterAcceptor::~ParameterAcceptor() std::string ParameterAcceptor::get_section_name() const { - return (section_name != "" ? section_name : - boost::core::demangle(typeid(*this).name())); + return (!section_name.empty() ? section_name : + boost::core::demangle(typeid(*this).name())); } @@ -60,7 +60,7 @@ ParameterAcceptor::initialize( ParameterHandler & prm) { declare_all_parameters(prm); - if (filename != "") + if (!filename.empty()) { // check the extension of input file if (filename.substr(filename.find_last_of('.') + 1) == "prm") @@ -106,7 +106,7 @@ ParameterAcceptor::initialize( "Invalid extension of parameter file. Please use .prm or .xml")); } - if (output_filename != "") + if (!output_filename.empty()) { std::ofstream outfile(output_filename.c_str()); Assert(outfile, ExcIO()); diff --git a/source/base/parameter_handler.cc b/source/base/parameter_handler.cc index 68e828c745a5..3e9f4b3e2be1 100644 --- a/source/base/parameter_handler.cc +++ b/source/base/parameter_handler.cc @@ -494,8 +494,8 @@ namespace // make sure we have a corresponding entry in the destination // object as well const std::string full_path = - (current_path == "" ? p->first : - current_path + path_separator + p->first); + (current_path.empty() ? p->first : + current_path + path_separator + p->first); const std::string new_value = p->second.get("value"); AssertThrow(destination.get_optional(full_path) && @@ -533,7 +533,7 @@ namespace { // it must be a subsection read_xml_recursively(p->second, - (current_path == "" ? + (current_path.empty() ? p->first : current_path + path_separator + p->first), path_separator, diff --git a/source/base/path_search.cc b/source/base/path_search.cc index 4faee0bd51c8..cf53ddb59030 100644 --- a/source/base/path_search.cc +++ b/source/base/path_search.cc @@ -146,7 +146,7 @@ PathSearch::find(const std::string &filename, // try again with the suffix appended, unless there is // no suffix - if (suffix != "") + if (!suffix.empty()) { real_name = *path + filename + suffix; if (debug > 1) diff --git a/source/base/subscriptor.cc b/source/base/subscriptor.cc index 3aa98f2d5f7e..973e5d2e1f37 100644 --- a/source/base/subscriptor.cc +++ b/source/base/subscriptor.cc @@ -84,7 +84,7 @@ Subscriptor::check_no_subscribers() const noexcept std::string(map_entry.first); } - if (infostring == "") + if (infostring.empty()) infostring = ""; AssertNothrow(counter == 0, @@ -136,7 +136,7 @@ Subscriptor::subscribe(std::atomic *const validity, object_info = &typeid(*this); ++counter; - const std::string name = (id != "") ? id : unknown_subscriber; + const std::string name = (!id.empty()) ? id : unknown_subscriber; map_iterator it = counter_map.find(name); if (it == counter_map.end()) @@ -154,7 +154,7 @@ void Subscriptor::unsubscribe(std::atomic *const validity, const std::string & id) const { - const std::string name = (id != "") ? id : unknown_subscriber; + const std::string name = (!id.empty()) ? id : unknown_subscriber; if (counter == 0) { AssertNothrow(counter > 0, ExcNoSubscriber(object_info->name(), name)); diff --git a/source/base/table_handler.cc b/source/base/table_handler.cc index 6ae95c51ce2d..6342e4f57fc2 100644 --- a/source/base/table_handler.cc +++ b/source/base/table_handler.cc @@ -722,9 +722,9 @@ TableHandler::write_tex(std::ostream &out, const bool with_header) const } out << "\\end{tabular}" << std::endl << "\\end{center}" << std::endl; - if (tex_table_caption != "") + if (!tex_table_caption.empty()) out << "\\caption{" << tex_table_caption << "}" << std::endl; - if (tex_table_label != "") + if (!tex_table_label.empty()) out << "\\label{" << tex_table_label << "}" << std::endl; out << "\\end{table}" << std::endl; if (with_header) diff --git a/source/base/timer.cc b/source/base/timer.cc index 13ee1aa8f70d..119ae4d477bb 100644 --- a/source/base/timer.cc +++ b/source/base/timer.cc @@ -459,7 +459,7 @@ TimerOutput::leave_subsection(const std::string §ion_name) std::lock_guard lock(mutex); - if (section_name != "") + if (!section_name.empty()) { Assert(sections.find(section_name) != sections.end(), ExcMessage("Cannot delete a section that was never created.")); @@ -472,7 +472,7 @@ TimerOutput::leave_subsection(const std::string §ion_name) // if no string is given, exit the last // active section. const std::string actual_section_name = - (section_name == "" ? active_sections.back() : section_name); + (section_name.empty() ? active_sections.back() : section_name); sections[actual_section_name].timer.stop(); sections[actual_section_name].total_wall_time += diff --git a/source/gmsh/utilities.cc b/source/gmsh/utilities.cc index 456e4fe6f845..512196010eef 100644 --- a/source/gmsh/utilities.cc +++ b/source/gmsh/utilities.cc @@ -59,7 +59,7 @@ namespace Gmsh { std::string base_name = prm.output_base_name; char dir_template[] = "ctfbc-XXXXXX"; - if (base_name == "") + if (base_name.empty()) { const char *temp = mkdtemp(dir_template); AssertThrow(temp != nullptr, diff --git a/source/grid/grid_in.cc b/source/grid/grid_in.cc index 28f2907258f8..addc9a384cb5 100644 --- a/source/grid/grid_in.cc +++ b/source/grid/grid_in.cc @@ -382,7 +382,7 @@ GridIn::read_vtk(std::istream &in) set = keyword; break; } - if (set == "") + if (set.empty()) // keep ignoring everything until the next SCALARS // keyword continue; From 0216e3c95260ce37f7a360505ea56cd8434a78db Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 9 Apr 2019 13:50:51 -0400 Subject: [PATCH 402/507] Use references and clean up a bit --- source/base/subscriptor.cc | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/source/base/subscriptor.cc b/source/base/subscriptor.cc index 973e5d2e1f37..9aa36568458e 100644 --- a/source/base/subscriptor.cc +++ b/source/base/subscriptor.cc @@ -136,13 +136,9 @@ Subscriptor::subscribe(std::atomic *const validity, object_info = &typeid(*this); ++counter; - const std::string name = (!id.empty()) ? id : unknown_subscriber; + const std::string &name = id.empty() ? unknown_subscriber : id; - map_iterator it = counter_map.find(name); - if (it == counter_map.end()) - counter_map.insert(map_value_type(name, 1U)); - else - it->second++; + ++counter_map[name]; *validity = true; validity_pointers.push_back(validity); @@ -154,7 +150,8 @@ void Subscriptor::unsubscribe(std::atomic *const validity, const std::string & id) const { - const std::string name = (!id.empty()) ? id : unknown_subscriber; + const std::string &name = id.empty() ? unknown_subscriber : id; + if (counter == 0) { AssertNothrow(counter > 0, ExcNoSubscriber(object_info->name(), name)); From 77fb2394f658eac51d0be277f583ede16b6c2993 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Thu, 11 Apr 2019 15:53:58 +0200 Subject: [PATCH 403/507] Make sure rtree works with mappings that do not preserve vertices. --- doc/news/changes/minor/20190411LucaHeltai-c | 3 + source/grid/grid_tools_cache.cc | 29 +++++-- tests/grid/grid_tools_cache_05.cc | 83 +++++++++++++++++++++ tests/grid/grid_tools_cache_05.output | 10 +++ 4 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 doc/news/changes/minor/20190411LucaHeltai-c create mode 100644 tests/grid/grid_tools_cache_05.cc create mode 100644 tests/grid/grid_tools_cache_05.output 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/source/grid/grid_tools_cache.cc b/source/grid/grid_tools_cache.cc index d1098c69862d..b0e1be61cf35 100644 --- a/source/grid/grid_tools_cache.cc +++ b/source/grid/grid_tools_cache.cc @@ -131,17 +131,36 @@ namespace GridTools std::vector, typename Triangulation::active_cell_iterator>> - boxes(tria->n_active_cells()); - unsigned int i = 0; - for (const auto &cell : tria->active_cell_iterators()) - boxes[i++] = std::make_pair(cell->bounding_box(), cell); + boxes(tria->n_active_cells()); + if (mapping->preserves_vertex_locations()) + { + unsigned int i = 0; + for (const auto &cell : tria->active_cell_iterators()) + boxes[i++] = std::make_pair(cell->bounding_box(), cell); + } + else + { + unsigned int i = 0; + for (const auto &cell : tria->active_cell_iterators()) + { + const auto vertices = mapping->get_vertices(cell); + Point p0 = vertices[0], p1 = vertices[0]; + for (unsigned int j = 1; j < vertices.size(); ++j) + for (unsigned int d = 0; d < spacedim; ++d) + { + p0[d] = std::min(p0[d], vertices[j][d]); + p1[d] = std::max(p1[d], vertices[j][d]); + } + boxes[i++] = + std::make_pair(BoundingBox({p0, p1}), cell); + } + } cell_bounding_boxes_rtree = pack_rtree(boxes); } return cell_bounding_boxes_rtree; } - #ifdef DEAL_II_WITH_NANOFLANN template const KDTree & diff --git a/tests/grid/grid_tools_cache_05.cc b/tests/grid/grid_tools_cache_05.cc new file mode 100644 index 000000000000..c4aef6710636 --- /dev/null +++ b/tests/grid/grid_tools_cache_05.cc @@ -0,0 +1,83 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// test that GridTools::Cache::get_cell_bounding_boxes_rtree() +// works in conjunction with MappingQEulerian + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "../tests.h" + +using namespace dealii; + + +template +void +test() +{ + deallog << "dim=" << dim << std::endl; + + Triangulation triangulation; + GridGenerator::hyper_cube(triangulation, -1, 1); + + FESystem fe(FE_Q(2), dim); + DoFHandler dof_handler(triangulation); + dof_handler.distribute_dofs(fe); + + Vector displacements(dof_handler.n_dofs()); + + displacements = 2.0; + + MappingQEulerian euler(2, dof_handler, displacements); + + GridTools::Cache cache0(triangulation); + GridTools::Cache cache1(triangulation, euler); + + auto &tree0 = cache0.get_cell_bounding_boxes_rtree(); + auto &tree1 = cache1.get_cell_bounding_boxes_rtree(); + + const auto box0 = tree0.begin()->first; + const auto box1 = tree1.begin()->first; + + deallog << "No Mapping : " << box0.get_boundary_points().first << ", " + << box0.get_boundary_points().second << std::endl + << "MappingQEulerian: " << box1.get_boundary_points().first << ", " + << box1.get_boundary_points().second << std::endl; +} + + + +int +main() +{ + initlog(); + + test<1>(); + test<2>(); + test<3>(); +} diff --git a/tests/grid/grid_tools_cache_05.output b/tests/grid/grid_tools_cache_05.output new file mode 100644 index 000000000000..a12320a83c3a --- /dev/null +++ b/tests/grid/grid_tools_cache_05.output @@ -0,0 +1,10 @@ + +DEAL::dim=1 +DEAL::No Mapping : -1.00000, 1.00000 +DEAL::MappingQEulerian: 1.00000, 3.00000 +DEAL::dim=2 +DEAL::No Mapping : -1.00000 -1.00000, 1.00000 1.00000 +DEAL::MappingQEulerian: 1.00000 1.00000, 3.00000 3.00000 +DEAL::dim=3 +DEAL::No Mapping : -1.00000 -1.00000 -1.00000, 1.00000 1.00000 1.00000 +DEAL::MappingQEulerian: 1.00000 1.00000 1.00000, 3.00000 3.00000 3.00000 From 026b280c76c9136610d189fc918f69fb77ff3755 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Thu, 11 Apr 2019 16:47:35 -0600 Subject: [PATCH 404/507] clang-tidy: only debug mode I don't think it makes sense to also compile in release mode for the tidy checks. This change should speed up the CI tester as well. --- contrib/utilities/run_clang_tidy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/utilities/run_clang_tidy.sh b/contrib/utilities/run_clang_tidy.sh index d013f5663947..70dc612c6621 100755 --- a/contrib/utilities/run_clang_tidy.sh +++ b/contrib/utilities/run_clang_tidy.sh @@ -43,7 +43,7 @@ echo "SRC-DIR=$SRC" # enable MPI (to get MPI warnings) # export compile commands (so that run-clang-tidy.py works) -ARGS=("-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" "$@") # for a list of checks, see /.clang-tidy cat "$SRC/.clang-tidy" From 6b040506829cf9336ced4c3aa43fc53eaeb6faf4 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Thu, 11 Apr 2019 15:52:36 +0200 Subject: [PATCH 405/507] Enlarge BoundingBox --- doc/news/changes/minor/20190411LucaHeltai-b | 3 ++ include/deal.II/base/bounding_box.h | 24 +++++++++ tests/base/bounding_box_5.cc | 60 +++++++++++++++++++++ tests/base/bounding_box_5.output | 7 +++ 4 files changed, 94 insertions(+) create mode 100644 doc/news/changes/minor/20190411LucaHeltai-b create mode 100644 tests/base/bounding_box_5.cc create mode 100644 tests/base/bounding_box_5.output 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/include/deal.II/base/bounding_box.h b/include/deal.II/base/bounding_box.h index d4c594c55a63..97acdb873d78 100644 --- a/include/deal.II/base/bounding_box.h +++ b/include/deal.II/base/bounding_box.h @@ -140,6 +140,16 @@ class BoundingBox bool point_inside(const Point &p) const; + /** + * Increase (or decrease) the size of the bounding box by the given 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 +186,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 shrinked this much: the points' " + "order should remain bottom left, top right.")); + } +} + template template diff --git a/tests/base/bounding_box_5.cc b/tests/base/bounding_box_5.cc new file mode 100644 index 000000000000..8f9790337d90 --- /dev/null +++ b/tests/base/bounding_box_5.cc @@ -0,0 +1,60 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// test BoundingBox::extend + +#include + +#include +#include + +#include "../tests.h" + +using namespace dealii; + + +template +void +test() +{ + Point p0, p1; + for (unsigned int d = 0; d < dim; ++d) + p1[d] = 1; + + BoundingBox box({p0, p1}); + + box.extend(.5); + + deallog << "New points: " << box.get_boundary_points().first << ", " + << box.get_boundary_points().second << std::endl; + + + box.extend(-.8); + + deallog << "New points: " << box.get_boundary_points().first << ", " + << box.get_boundary_points().second << std::endl; +} + + + +int +main() +{ + initlog(); + + test<1>(); + test<2>(); + test<3>(); +} diff --git a/tests/base/bounding_box_5.output b/tests/base/bounding_box_5.output new file mode 100644 index 000000000000..837b1d9bd95b --- /dev/null +++ b/tests/base/bounding_box_5.output @@ -0,0 +1,7 @@ + +DEAL::New points: -0.500000, 1.50000 +DEAL::New points: 0.300000, 0.700000 +DEAL::New points: -0.500000 -0.500000, 1.50000 1.50000 +DEAL::New points: 0.300000 0.300000, 0.700000 0.700000 +DEAL::New points: -0.500000 -0.500000 -0.500000, 1.50000 1.50000 1.50000 +DEAL::New points: 0.300000 0.300000 0.300000, 0.700000 0.700000 0.700000 From 9929cda885091f83176c67c214f8be325263fc47 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 12 Apr 2019 13:51:10 +0200 Subject: [PATCH 406/507] Avoid floating point exception in symengine_number_type_01 --- tests/symengine/symengine_number_type_01.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/symengine/symengine_number_type_01.cc b/tests/symengine/symengine_number_type_01.cc index 4b26361e1f57..d67bf54cb7c0 100644 --- a/tests/symengine/symengine_number_type_01.cc +++ b/tests/symengine/symengine_number_type_01.cc @@ -1125,6 +1125,10 @@ main() // No condition is met { +#if defined(DEAL_II_HAVE_FP_EXCEPTIONS) + fedisableexcept(FE_INVALID); +#endif + const double x_val = -1.0; SD::types::substitution_map sub_map; sub_map[x] = SD_number_t(x_val); From a2322195ef5bd9835c804ea60dbd127e47c9fe61 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Fri, 12 Apr 2019 15:07:03 -0600 Subject: [PATCH 407/507] indent --- examples/step-63/step-63.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/step-63/step-63.cc b/examples/step-63/step-63.cc index 3f9717ec8964..06781b27425e 100644 --- a/examples/step-63/step-63.cc +++ b/examples/step-63/step-63.cc @@ -158,7 +158,8 @@ namespace Step63 "true", Patterns::Bool(), "With streamline diffusion: true|false"); - prm.declare_entry("Output","true", + prm.declare_entry("Output", + "true", Patterns::Bool(), "Generate graphical output: true|false"); @@ -658,7 +659,8 @@ namespace Step63 compute_stabilization_delta(cell->diameter(), epsilon, advection_direction, - settings.fe_degree) : 0.0; + 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) From 94a34b46dfbb216a878984b8600ad63b73514440 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Fri, 12 Apr 2019 15:07:36 -0600 Subject: [PATCH 408/507] get rid of static smoother data --- examples/step-63/step-63.cc | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/examples/step-63/step-63.cc b/examples/step-63/step-63.cc index 06781b27425e..c23896f4f53b 100644 --- a/examples/step-63/step-63.cc +++ b/examples/step-63/step-63.cc @@ -452,7 +452,7 @@ namespace Step63 CopyData & copy_data); void assemble_system_and_multigrid(); - std::unique_ptr>> create_smoother(); + void setup_smoother(); void solve(); void refine_grid(); @@ -483,6 +483,12 @@ namespace Step63 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; @@ -797,8 +803,7 @@ namespace Step63 template - std::unique_ptr>> - AdvectionProblem::create_smoother() + void AdvectionProblem::setup_smoother() { if (settings.smoother_type == "SOR") { @@ -812,7 +817,7 @@ namespace Step63 Smoother::AdditionalData(fe.degree == 1 ? 1.0 : 0.62)); smoother->set_steps(2); - return smoother; + mg_smoother = std::move(smoother); } else if (settings.smoother_type == "Jacobi") { @@ -825,15 +830,13 @@ namespace Step63 Smoother::AdditionalData(fe.degree == 1 ? 0.6667 : 0.47)); smoother->set_steps(4); - return smoother; + mg_smoother = std::move(smoother); } else if (settings.smoother_type == "block SOR") { using Smoother = RelaxationBlockSOR, double, Vector>; - // TODO: try and remove static - static MGLevelObject smoother_data; smoother_data.resize(0, triangulation.n_levels() - 1); for (unsigned int level = 0; level < triangulation.n_levels(); ++level) @@ -885,15 +888,13 @@ namespace Step63 Vector>>(); smoother->initialize(mg_matrices, smoother_data); smoother->set_steps(1); - return smoother; + mg_smoother = std::move(smoother); } else if (settings.smoother_type == "block Jacobi") { using Smoother = RelaxationBlockJacobi, double, Vector>; - // TODO: try and remove static - static MGLevelObject smoother_data; smoother_data.resize(0, triangulation.n_levels() - 1); for (unsigned int level = 0; level < triangulation.n_levels(); ++level) @@ -945,7 +946,7 @@ namespace Step63 Vector>>(); smoother->initialize(mg_matrices, smoother_data); smoother->set_steps(2); - return smoother; + mg_smoother = std::move(smoother); } else AssertThrow(false, ExcNotImplemented()); @@ -969,8 +970,7 @@ namespace Step63 MGCoarseGridHouseholder> coarse_grid_solver; coarse_grid_solver.initialize(coarse_matrix); - const std::unique_ptr>> mg_smoother = - create_smoother(); + setup_smoother(); mg_matrix.initialize(mg_matrices); mg_interface_matrix_in.initialize(mg_interface_in); @@ -998,6 +998,8 @@ namespace Step63 << " in " << time.last_wall_time() << " seconds " << std::endl; constraints.distribute(solution); + + mg_smoother.release(); } From 5babb4fcb7adaeeacf258811a97a35ff3c54f43c Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Fri, 12 Apr 2019 15:19:23 -0600 Subject: [PATCH 409/507] change parse_parameter logic --- examples/step-63/step-63.cc | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/examples/step-63/step-63.cc b/examples/step-63/step-63.cc index c23896f4f53b..6bc23c5e79f2 100644 --- a/examples/step-63/step-63.cc +++ b/examples/step-63/step-63.cc @@ -122,7 +122,7 @@ namespace Step63 random }; - bool get_parameters(const std::string &prm_filename); + void get_parameters(const std::string &prm_filename); unsigned int fe_degree; std::string smoother_type; @@ -131,15 +131,8 @@ namespace Step63 bool output; }; - bool Settings::get_parameters(const std::string &prm_filename) + void Settings::get_parameters(const std::string &prm_filename) { - if (prm_filename.size() == 0) - { - std::cerr << "Usage: please pass a .prm file as the first argument" - << std::endl; - return false; - } - ParameterHandler prm; prm.declare_entry("Fe degree", @@ -163,19 +156,15 @@ namespace Step63 Patterns::Bool(), "Generate graphical output: true|false"); - try - { - prm.parse_input(prm_filename); - } - catch (const dealii::PathSearch::ExcFileNotFound &) + if (prm_filename.size() == 0) { - std::cerr << "ERROR: could not parse input from given .prm file" - << prm_filename << "'" << std::endl; - prm.print_parameters(std::cout, ParameterHandler::Text); - return false; + 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"); @@ -191,8 +180,6 @@ namespace Step63 with_streamline_diffusion = prm.get_bool("With streamline diffusion"); output = prm.get_bool("Output"); - - return true; } @@ -1111,8 +1098,7 @@ int main(int argc, char *argv[]) try { Step63::Settings settings; - if (!settings.get_parameters((argc > 1) ? (argv[1]) : "")) - return 0; + settings.get_parameters((argc > 1) ? (argv[1]) : ""); Step63::AdvectionProblem<2> advection_problem_2d(settings); advection_problem_2d.run(); From 8b17cbc4026bce1105f540e8b1dba7d21e7e1c74 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Fri, 12 Apr 2019 15:25:23 -0600 Subject: [PATCH 410/507] edit intro --- examples/step-63/doc/intro.dox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/step-63/doc/intro.dox b/examples/step-63/doc/intro.dox index b8535c110b50..4b90b10a306e 100644 --- a/examples/step-63/doc/intro.dox +++ b/examples/step-63/doc/intro.dox @@ -6,4 +6,4 @@

    Introduction

    Please note: This is work in progress and will be an example for block -smoothers in geometric multigrid. For now, this is just step-16. +smoothers in geometric multigrid. From 8cf6bb0e095132f5244630c7d803461e28c2860f Mon Sep 17 00:00:00 2001 From: David Wells Date: Fri, 12 Apr 2019 22:42:36 -0400 Subject: [PATCH 411/507] Add missing '@ingroup functions' annotations. --- include/deal.II/base/function.h | 3 +++ include/deal.II/base/function_bessel.h | 1 + include/deal.II/base/function_cspline.h | 1 + include/deal.II/base/function_lib.h | 4 ++++ include/deal.II/base/function_spherical.h | 1 + 5 files changed, 10 insertions(+) diff --git a/include/deal.II/base/function.h b/include/deal.II/base/function.h index cb5789440959..49c42d623b8a 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 @@ -770,6 +771,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 @@ -858,6 +860,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_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..665cef4b3c8d 100644 --- a/include/deal.II/base/function_lib.h +++ b/include/deal.II/base/function_lib.h @@ -1133,6 +1133,7 @@ namespace Functions * exponents are of course equally valid. Exponents can't be real when the * bases are negative numbers. * + * @ingroup functions * @author Wolfgang Bangerth, 2006 */ template @@ -1217,6 +1218,7 @@ namespace Functions * @note The use of the related class InterpolatedUniformGridData is * discussed in step-53. * + * @ingroup functions * @author Wolfgang Bangerth, 2013 */ template @@ -1320,6 +1322,7 @@ namespace Functions * * @note The use of this class is discussed in step-53. * + * @ingroup functions * @author Wolfgang Bangerth, 2013 */ template @@ -1386,6 +1389,7 @@ namespace Functions * takes a Table<2,double> to describe the set of exponents and a * Vector to describe the set of coefficients. * + * @ingroup functions * @author Ángel Rodríguez, 2015 */ template diff --git a/include/deal.II/base/function_spherical.h b/include/deal.II/base/function_spherical.h index 9c1b9ee7d21a..9a78f60f0444 100644 --- a/include/deal.II/base/function_spherical.h +++ b/include/deal.II/base/function_spherical.h @@ -38,6 +38,7 @@ namespace Functions * * @note This function is currently only implemented for dim==3 . * + * @ingroup functions * @author Denis Davydov, 2017 */ template From e3109ce2d1e75db170b255b736b044e712830514 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Sun, 14 Apr 2019 18:08:40 -0600 Subject: [PATCH 412/507] Enclose everything in step-61 into its own namespace. --- examples/step-61/step-61.cc | 1600 ++++++++++++++++++----------------- 1 file changed, 809 insertions(+), 791 deletions(-) diff --git a/examples/step-61/step-61.cc b/examples/step-61/step-61.cc index d62b125a7b8c..331876650fb4 100644 --- a/examples/step-61/step-61.cc +++ b/examples/step-61/step-61.cc @@ -13,12 +13,13 @@ * * --------------------------------------------------------------------- - * Author: Zhuoran Wang + * Author: Zhuoran Wang, Colorado State University, 2018 */ // @sect3{Include files} // This program is based on step-7, step-20 and step-51, -// we add these include files. +// so most of the following header files are familiar. We +// need the following: #include #include #include @@ -58,854 +59,870 @@ #include #include -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 +// Our first step, as always, is to put everything related to this tutorial +// program into its own namespace: +namespace Step61 { - return 0; -} - -template -class RightHandSide : public Function -{ -public: - RightHandSide() - : Function() - {} - - virtual double value(const Point & p, - const unsigned int component = 0) const override; -}; + using namespace dealii; -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; -} + // @sect3{The WGDarcyEquation class template} -template -class Solution : public Function -{ -public: - Solution() - : Function(1) - {} - - virtual double value(const Point &p, const unsigned int) const override; -}; + // 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 -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 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 Velocity : public TensorFunction<1, dim> -{ -public: - Velocity() - : TensorFunction<1, dim>() - {} + 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; + } - virtual Tensor<1, dim> value(const Point &p) const override; -}; + template + class Solution : public Function + { + public: + Solution() + : Function(1) + {} -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; -} + virtual double value(const Point &p, + const unsigned int) const override; + }; -// @sect3{WGDarcyEquation class implementation} + 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; + } -// @sect4{WGDarcyEquation::WGDarcyEquation} + template + class Velocity : public TensorFunction<1, dim> + { + public: + Velocity() + : TensorFunction<1, dim>() + {} -// 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. + virtual Tensor<1, dim> value(const Point &p) const override; + }; -// 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) - , + 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; + } - fe(FE_DGQ(0), 1, FE_FaceQ(0), 1) - , dof_handler(triangulation) + // @sect3{WGDarcyEquation class implementation} -{} + // @sect4{WGDarcyEquation::WGDarcyEquation} -// @sect4{WGDarcyEquation::make_grid} + // 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. -// We generate a mesh on the unit square domain and refine it. + // 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) + , -template -void WGDarcyEquation::make_grid() -{ - GridGenerator::hyper_cube(triangulation, 0, 1); - triangulation.refine_global(1); + fe(FE_DGQ(0), 1, FE_FaceQ(0), 1) + , dof_handler(triangulation) - 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} + // @sect4{WGDarcyEquation::make_grid} -// After we create the mesh, we distribute degrees of freedom for the two -// DoFHandler objects. + // We generate a mesh on the unit square domain and refine it. -template -void WGDarcyEquation::setup_system() -{ - dof_handler_rt.distribute_dofs(fe_rt); - dof_handler.distribute_dofs(fe); + template + void WGDarcyEquation::make_grid() + { + GridGenerator::hyper_cube(triangulation, 0, 1); + triangulation.refine_global(1); - std::cout << " Number of flux degrees of freedom: " - << dof_handler_rt.n_dofs() << std::endl; + std::cout << " Number of active cells: " << triangulation.n_active_cells() + << std::endl + << " Total number of cells: " << triangulation.n_cells() + << std::endl; + } - std::cout << " Number of pressure degrees of freedom: " - << dof_handler.n_dofs() << std::endl; + // @sect4{WGDarcyEquation::setup_system} - solution.reinit(dof_handler.n_dofs()); - system_rhs.reinit(dof_handler.n_dofs()); + // After we create the mesh, we distribute degrees of freedom for the two + // DoFHandler objects. + template + void WGDarcyEquation::setup_system() { - 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); + dof_handler_rt.distribute_dofs(fe_rt); + dof_handler.distribute_dofs(fe); - system_matrix.reinit(sparsity_pattern); + std::cout << " Number of flux degrees of freedom: " + << dof_handler_rt.n_dofs() << std::endl; - // solution.reinit(dof_handler.n_dofs()); - // system_rhs.reinit(dof_handler.n_dofs()); -} + std::cout << " Number of pressure degrees of freedom: " + << dof_handler.n_dofs() << std::endl; -// @sect4{WGDarcyEquation::assemble_system} + solution.reinit(dof_handler.n_dofs()); + system_rhs.reinit(dof_handler.n_dofs()); -// 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); - } - } - } - } - } + 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(); + } - // 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); - } -} + // 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); -// @sect4{WGDarcyEquation::solve} + system_matrix.reinit(sparsity_pattern); -// 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); -} + // solution.reinit(dof_handler.n_dofs()); + // system_rhs.reinit(dof_handler.n_dofs()); + } -// @sect4{WGDarcyEquation::process_solution} + // @sect4{WGDarcyEquation::assemble_system} -// 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()); + // 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() { - // 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) + 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); - 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)]); + constraints.distribute_local_to_global( + local_matrix, cell_rhs, local_dof_indices, system_matrix, system_rhs); } } - // 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} + // @sect4{WGDarcyEquation::solve} -// 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. + // 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); + } -// 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. + // @sect4{WGDarcyEquation::process_solution} -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) + // 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()); { - 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) + // 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) { - 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)); - } - } + 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 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); + // 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; + } - // 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)); - } - } - } + // @sect4{WGDarcyEquation::postprocess} - 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); + // 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. - // 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]); - } + // 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. - // 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)); - } - } - } + 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; + } - // 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); - } + // 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; + } - 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::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(); + } -// @sect4{WGDarcyEquation::run} +} // namespace Step61 -// 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(); -} // @sect3{The main function} @@ -914,9 +931,9 @@ int main() { try { - deallog.depth_console(2); - WGDarcyEquation<2> WGDarcyEquationTest; - WGDarcyEquationTest.run(); + dealii::deallog.depth_console(2); + Step61::WGDarcyEquation<2> wg_darcy; + wg_darcy.run(); } catch (std::exception &exc) { @@ -929,6 +946,7 @@ int main() << "Aborting!" << std::endl << "----------------------------------------------------" << std::endl; + return 1; } catch (...) { @@ -940,7 +958,7 @@ int main() << "Aborting!" << std::endl << "----------------------------------------------------" << std::endl; - throw; + return 1; } return 0; From 81f145ea4b679bf549198244e62f64ea14e9d7fb Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Sun, 14 Apr 2019 18:16:58 -0600 Subject: [PATCH 413/507] Update requirements for step-61. --- examples/step-61/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/step-61/CMakeLists.txt b/examples/step-61/CMakeLists.txt index 83a33d091ac2..438736f4746b 100644 --- a/examples/step-61/CMakeLists.txt +++ b/examples/step-61/CMakeLists.txt @@ -23,7 +23,7 @@ SET(TARGET_SRC CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) -FIND_PACKAGE(deal.II 9.0.0 QUIET +FIND_PACKAGE(deal.II 9.1.0 QUIET HINTS ${deal.II_DIR} ${DEAL_II_DIR} ../ ../../ $ENV{DEAL_II_DIR} ) IF(NOT ${deal.II_FOUND}) From 0cfc5f917ebd3de5974453392ff471f4a1ed6ffc Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Mon, 15 Apr 2019 16:00:58 +0200 Subject: [PATCH 414/507] Fix symengine_number_type_01 in Release mode --- tests/symengine/symengine_number_type_01.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/symengine/symengine_number_type_01.cc b/tests/symengine/symengine_number_type_01.cc index d67bf54cb7c0..074e8e86a740 100644 --- a/tests/symengine/symengine_number_type_01.cc +++ b/tests/symengine/symengine_number_type_01.cc @@ -1125,7 +1125,7 @@ main() // No condition is met { -#if defined(DEAL_II_HAVE_FP_EXCEPTIONS) +#if defined(DEBUG) && defined(DEAL_II_HAVE_FP_EXCEPTIONS) fedisableexcept(FE_INVALID); #endif From 32b1158be54c7f493fe7924bb3fe0519a258433f Mon Sep 17 00:00:00 2001 From: tcclevenger Date: Mon, 15 Apr 2019 09:24:06 -0600 Subject: [PATCH 415/507] requested changes --- examples/step-63/step-63.cc | 110 +++++++++--------------------------- 1 file changed, 27 insertions(+), 83 deletions(-) diff --git a/examples/step-63/step-63.cc b/examples/step-63/step-63.cc index 6bc23c5e79f2..5b906c97ff31 100644 --- a/examples/step-63/step-63.cc +++ b/examples/step-63/step-63.cc @@ -372,17 +372,8 @@ namespace Step63 Assert(component == 0, ExcIndexRange(component, 0, 1)); (void)component; - if (std::fabs(p[0] * p[0] + p[1] * p[1] - 0.3 * 0.3) < - 1e-8 // around cylinder - || std::fabs(p[0] + 1) < 1e-8 // x == -1 - || std::fabs(p[1] - 1) < 1e-8 // y == 1 - || (std::fabs(p[1] + 1) < 1e-8 && p[0] < 0.5) // y == -1, x <= 0.5 - ) - { - return 0.0; - } - else 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 + 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; @@ -623,8 +614,7 @@ namespace Step63 ScratchData & scratch_data, CopyData & copy_data) { - const unsigned int level = cell->level(); - copy_data.level = level; + copy_data.level = cell->level(); const unsigned int dofs_per_cell = scratch_data.fe_values.get_fe().dofs_per_cell; @@ -727,8 +717,6 @@ namespace Step63 CopyData(), MeshWorker::assemble_own_cells); - - // Assemble GMG std::vector> boundary_constraints( triangulation.n_global_levels()); for (unsigned int level = 0; level < triangulation.n_global_levels(); @@ -819,11 +807,9 @@ namespace Step63 smoother->set_steps(4); mg_smoother = std::move(smoother); } - else if (settings.smoother_type == "block SOR") + else if (settings.smoother_type == "block SOR" || + settings.smoother_type == "block Jacobi") { - using Smoother = - RelaxationBlockSOR, double, Vector>; - smoother_data.resize(0, triangulation.n_levels() - 1); for (unsigned int level = 0; level < triangulation.n_levels(); ++level) @@ -832,7 +818,8 @@ namespace Step63 dof_handler, level); - smoother_data[level].relaxation = 1.0; + smoother_data[level].relaxation = + (settings.smoother_type == "block SOR" ? 1.0 : 0.25); smoother_data[level].inversion = PreconditionBlockBase::svd; std::vector ordered_indices; @@ -869,71 +856,28 @@ namespace Step63 std::vector>(1, ordered_indices); } - auto smoother = - std_cxx14::make_unique, - Smoother, - Vector>>(); - smoother->initialize(mg_matrices, smoother_data); - smoother->set_steps(1); - mg_smoother = std::move(smoother); - } - else if (settings.smoother_type == "block Jacobi") - { - using Smoother = - RelaxationBlockJacobi, double, Vector>; - - smoother_data.resize(0, triangulation.n_levels() - 1); - - for (unsigned int level = 0; level < triangulation.n_levels(); ++level) + if (settings.smoother_type == "block SOR") { - DoFTools::make_cell_patches(smoother_data[level].block_list, - dof_handler, - level); - - smoother_data[level].relaxation = 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); + 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); } - - auto smoother = - std_cxx14::make_unique, - Smoother, - Vector>>(); - smoother->initialize(mg_matrices, smoother_data); - smoother->set_steps(2); - mg_smoother = std::move(smoother); } else AssertThrow(false, ExcNotImplemented()); From 5cc659cc45992d01dfe56578de879845c0e6a4a5 Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Mon, 15 Apr 2019 21:34:46 +0000 Subject: [PATCH 416/507] Remove unused variables --- include/deal.II/matrix_free/cuda_matrix_free.templates.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/deal.II/matrix_free/cuda_matrix_free.templates.h b/include/deal.II/matrix_free/cuda_matrix_free.templates.h index 86da1001383d..67720c10edd2 100644 --- a/include/deal.II/matrix_free/cuda_matrix_free.templates.h +++ b/include/deal.II/matrix_free/cuda_matrix_free.templates.h @@ -514,11 +514,6 @@ namespace CUDAWrappers constexpr unsigned int cells_per_block = cells_per_block_shmem(dim, Functor::n_dofs_1d - 1); - constexpr unsigned int n_dofs_per_block = - cells_per_block * Functor::n_local_dofs; - constexpr unsigned int n_q_points_per_block = - cells_per_block * Functor::n_q_points; - const unsigned int local_cell = threadIdx.x / Functor::n_dofs_1d; const unsigned int cell = local_cell + cells_per_block * (blockIdx.x + gridDim.x * blockIdx.y); From e2e647c09d14727d2cc5b12949806f59522761b6 Mon Sep 17 00:00:00 2001 From: Bruno Turcksin Date: Mon, 15 Apr 2019 21:35:00 +0000 Subject: [PATCH 417/507] Add missing instantiations --- source/lac/read_write_vector.cc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/source/lac/read_write_vector.cc b/source/lac/read_write_vector.cc index 9d17935bba39..0baf5cd8b4ee 100644 --- a/source/lac/read_write_vector.cc +++ b/source/lac/read_write_vector.cc @@ -39,6 +39,33 @@ namespace LinearAlgebra #endif #undef TEMPL_COPY_CONSTRUCTOR + + template void + ReadWriteVector::import( + const distributed::Vector &, + VectorOperation::values, + const std::shared_ptr &); + + template void + ReadWriteVector::import( + const distributed::Vector &, + VectorOperation::values, + const std::shared_ptr &); +#ifdef DEAL_II_WITH_COMPLEX_VALUES + template void + ReadWriteVector>::import( + const distributed::Vector, ::dealii::MemorySpace::Host> + &, + VectorOperation::values, + const std::shared_ptr &); + + template void + ReadWriteVector>::import( + const distributed::Vector, ::dealii::MemorySpace::Host> + &, + VectorOperation::values, + const std::shared_ptr &); +#endif } // namespace LinearAlgebra DEAL_II_NAMESPACE_CLOSE From d1ed71376b9d7faca6e1321ea745f0e2d848df00 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 18 Apr 2019 21:01:36 +0200 Subject: [PATCH 418/507] Fix configuring with external Boost-1.70.0 --- cmake/modules/FindBOOST.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/modules/FindBOOST.cmake b/cmake/modules/FindBOOST.cmake index 423dcd047ee8..f640f49e8564 100644 --- a/cmake/modules/FindBOOST.cmake +++ b/cmake/modules/FindBOOST.cmake @@ -50,6 +50,10 @@ ENDIF() # temporarily disable ${CMAKE_SOURCE_DIR}/cmake/modules for module lookup LIST(REMOVE_ITEM CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules/) + +# Workaround a CMake compatibility issue with boost-1.70.0 +SET(Boost_NO_BOOST_CMAKE ON) + IF(DEAL_II_WITH_ZLIB) FIND_PACKAGE(Boost ${BOOST_VERSION_REQUIRED} COMPONENTS iostreams serialization system thread @@ -77,7 +81,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) # From ffac3a27160d751fa757d27b7ac9102984d12e03 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Thu, 18 Apr 2019 21:32:20 +0200 Subject: [PATCH 419/507] Add links --- cmake/modules/FindBOOST.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/modules/FindBOOST.cmake b/cmake/modules/FindBOOST.cmake index f640f49e8564..8274a3613ee7 100644 --- a/cmake/modules/FindBOOST.cmake +++ b/cmake/modules/FindBOOST.cmake @@ -51,7 +51,9 @@ ENDIF() # temporarily disable ${CMAKE_SOURCE_DIR}/cmake/modules for module lookup LIST(REMOVE_ITEM CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules/) -# Workaround a CMake compatibility issue with boost-1.70.0 +# 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) From 1a7b598b7a80955c120b51a696367fbb2c9c3dbf Mon Sep 17 00:00:00 2001 From: Benjamin Brands Date: Thu, 18 Apr 2019 22:25:21 +0200 Subject: [PATCH 420/507] add explicit instantiations for shared::Triangulation --- source/grid/grid_tools_dof_handlers.inst.in | 48 +++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/source/grid/grid_tools_dof_handlers.inst.in b/source/grid/grid_tools_dof_handlers.inst.in index 9ef81e67af5d..39c7284ad50d 100644 --- a/source/grid/grid_tools_dof_handlers.inst.in +++ b/source/grid/grid_tools_dof_handlers.inst.in @@ -337,3 +337,51 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) # endif #endif } + +// TODO the text above the last instantiation block implies that this should not +// be necessary... is it? +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { +#if deal_II_dimension <= deal_II_space_dimension +# if deal_II_dimension >= 2 + + namespace GridTools + \{ + template void + collect_periodic_faces< + parallel::shared::Triangulation>( + const parallel::shared::Triangulation &, + const types::boundary_id, + const types::boundary_id, + const int, + std::vector::cell_iterator>> &, + const Tensor<1, + parallel::shared::Triangulation< + deal_II_dimension, + deal_II_space_dimension>::space_dimension> &, + const FullMatrix &); + + template void + collect_periodic_faces< + parallel::shared::Triangulation>( + const parallel::shared::Triangulation &, + const types::boundary_id, + const int, + std::vector::cell_iterator>> &, + const Tensor<1, + parallel::shared::Triangulation< + deal_II_dimension, + deal_II_space_dimension>::space_dimension> &, + const FullMatrix &); + \} +# endif +#endif + } From 0bd307516917cd804b26a7302a4608cfee3ce524 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Thu, 18 Apr 2019 19:35:43 -0500 Subject: [PATCH 421/507] CMake: Clear CMAKE_REQUIRED_FLAGS before calling FindLAPACK CMAKE_REQUIRED_FLAGS is populated by dealii with CXXFLAGS and this should be cleared before calling any function that calls try_compile on a C file. FindLAPACK calls FindTHREADS.cmake which uses try_compile on a C file. --- cmake/configure/configure_1_lapack.cmake | 1 + 1 file changed, 1 insertion(+) 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) # From 01c49cb26b25082af43cdb0ffc7183acf40c4e7c Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sun, 14 Apr 2019 10:56:15 +0200 Subject: [PATCH 422/507] Add some SD-related utility functions --- include/deal.II/differentiation/sd.h | 1 + .../differentiation/sd/symengine_utilities.h | 85 +++++++++++++++++++ .../differentiation/sd/symengine_utilities.cc | 16 ++++ tests/symengine/symengine_utilities_01.cc | 57 +++++++++++++ tests/symengine/symengine_utilities_01.output | 10 +++ 5 files changed, 169 insertions(+) create mode 100644 tests/symengine/symengine_utilities_01.cc create mode 100644 tests/symengine/symengine_utilities_01.output diff --git a/include/deal.II/differentiation/sd.h b/include/deal.II/differentiation/sd.h index 0366a5fbd9c8..e618da464616 100644 --- a/include/deal.II/differentiation/sd.h +++ b/include/deal.II/differentiation/sd.h @@ -24,6 +24,7 @@ # include # include # include +# include DEAL_II_NAMESPACE_OPEN diff --git a/include/deal.II/differentiation/sd/symengine_utilities.h b/include/deal.II/differentiation/sd/symengine_utilities.h index e9f64c57162d..69188a863442 100644 --- a/include/deal.II/differentiation/sd/symengine_utilities.h +++ b/include/deal.II/differentiation/sd/symengine_utilities.h @@ -49,12 +49,97 @@ namespace Differentiation convert_expression_vector_to_basic_vector( const SD::types::symbol_vector &symbol_vector); + /** + * Extract the symbols (key entries) from a substitution map. + * + * @note It is guarenteed that the order of extraction of data into the + * output vector is the same as that for extract_values(). + * That is to say that the unzipped key and value pairs as given by + * extract_symbols() and extract_values() always have a 1:1 + * correspondence. + */ + SD::types::symbol_vector + extract_symbols(const SD::types::substitution_map &substitution_values); + + /** + * Extract the values from a substitution map. + * The value entries will be converted into the @p NumberType given + * as a template parameter to this function via the @p ExpressionType. + * + * @note It is guarenteed that the order of extraction of data into the + * output vector is the same as that for extract_symbols(). + * That is to say that the unzipped key and value pairs as given by + * extract_symbols() and extract_values() always have a 1:1 + * correspondence. + */ + template + std::vector + extract_values(const SD::types::substitution_map &substitution_values); + + /** + * Print the key and value pairs stored in a substitution map. + */ + template + StreamType & + print_substitution_map( + StreamType & stream, + const SD::types::substitution_map &symbol_value_map); + } // namespace Utilities } // namespace SD } // namespace Differentiation +/* -------------------- inline and template functions ------------------ */ + + +# ifndef DOXYGEN + + +namespace Differentiation +{ + namespace SD + { + namespace Utilities + { + template + std::vector + extract_values(const SD::types::substitution_map &substitution_values) + { + std::vector values; + values.reserve(substitution_values.size()); + + for (const auto &entry : substitution_values) + values.push_back( + static_cast(ExpressionType(entry.second))); + + return values; + } + + + template + StreamType & + print_substitution_map( + StreamType & stream, + const SD::types::substitution_map &symbol_value_map) + { + for (const auto &entry : symbol_value_map) + stream << entry.first << " = " << entry.second << "\n"; + + stream << std::flush; + return stream; + } + + } // namespace Utilities + + } // namespace SD +} // namespace Differentiation + + +# endif // DOXYGEN + + DEAL_II_NAMESPACE_CLOSE #endif // DEAL_II_WITH_SYMENGINE diff --git a/source/differentiation/sd/symengine_utilities.cc b/source/differentiation/sd/symengine_utilities.cc index 9697316831f8..3d499a9e4aad 100644 --- a/source/differentiation/sd/symengine_utilities.cc +++ b/source/differentiation/sd/symengine_utilities.cc @@ -52,6 +52,22 @@ namespace Differentiation return symb_vec; } + + SD::types::symbol_vector + extract_symbols(const SD::types::substitution_map &substitution_values) + { + SD::types::symbol_vector symbols; + symbols.reserve(substitution_values.size()); + + for (typename SD::types::substitution_map::const_iterator it = + substitution_values.begin(); + it != substitution_values.end(); + ++it) + symbols.push_back(it->first); + + return symbols; + } + } // namespace Utilities } // namespace SD diff --git a/tests/symengine/symengine_utilities_01.cc b/tests/symengine/symengine_utilities_01.cc new file mode 100644 index 000000000000..00d6efe9c529 --- /dev/null +++ b/tests/symengine/symengine_utilities_01.cc @@ -0,0 +1,57 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Check that substitution map decomposition and printing work as expected + +#include + +#include "../tests.h" + +using namespace dealii; +namespace SD = Differentiation::SD; + + +int +main() +{ + initlog(); + + using SD_number_t = SD::Expression; + + const SD::types::substitution_map sub_map{ + {SD_number_t("c"), SD_number_t(1.0)}, + {SD_number_t("b"), SD_number_t(2)}, + {SD_number_t("a"), SD_number_t(3.0f)}}; + + const SD::types::symbol_vector symbols = + SD::Utilities::extract_symbols(sub_map); + const std::vector values = + SD::Utilities::extract_values(sub_map); + Assert(values.size() == symbols.size(), + ExcDimensionMismatch(values.size(), symbols.size())); + + // Print the map itself (this should be dictionary ordered) + deallog << "Print substitution map" << std::endl; + SD::Utilities::print_substitution_map(deallog, sub_map); + + // Print the extracted symbol-value pairs (the ordering should match that of + // the map) + deallog << "Print extracted symbol-value pairs" << std::endl; + for (unsigned int i = 0; i < symbols.size(); ++i) + deallog << symbols[i] << " = " << values[i] << std::endl; + + deallog << "OK" << std::endl; +} diff --git a/tests/symengine/symengine_utilities_01.output b/tests/symengine/symengine_utilities_01.output new file mode 100644 index 000000000000..ddbe32bbc1aa --- /dev/null +++ b/tests/symengine/symengine_utilities_01.output @@ -0,0 +1,10 @@ + +DEAL::Print substitution map +DEAL::a = 3.0 +b = 2 +c = 1.0 +Print extracted symbol-value pairs +DEAL::a = 3.00000 +DEAL::b = 2.00000 +DEAL::c = 1.00000 +DEAL::OK From 1556051a5cf11199aa5000bc62a04b4da7b984fd Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sun, 14 Apr 2019 10:57:52 +0200 Subject: [PATCH 423/507] Add some SD-related convenience functions for scalar operations. Specifically, these can be used to create a scalar symbol and symbolic function. --- include/deal.II/differentiation/sd.h | 1 + .../sd/symengine_scalar_operations.h | 119 ++++++++++++++++++ source/differentiation/sd/CMakeLists.txt | 1 + .../sd/symengine_scalar_operations.cc | 64 ++++++++++ .../symengine_scalar_operations_01.cc | 55 ++++++++ .../symengine_scalar_operations_01.output | 5 + 6 files changed, 245 insertions(+) create mode 100644 include/deal.II/differentiation/sd/symengine_scalar_operations.h create mode 100644 source/differentiation/sd/symengine_scalar_operations.cc create mode 100644 tests/symengine/symengine_scalar_operations_01.cc create mode 100644 tests/symengine/symengine_scalar_operations_01.output diff --git a/include/deal.II/differentiation/sd.h b/include/deal.II/differentiation/sd.h index e618da464616..2050e6a509df 100644 --- a/include/deal.II/differentiation/sd.h +++ b/include/deal.II/differentiation/sd.h @@ -23,6 +23,7 @@ # include # include # include +# include # include # include diff --git a/include/deal.II/differentiation/sd/symengine_scalar_operations.h b/include/deal.II/differentiation/sd/symengine_scalar_operations.h new file mode 100644 index 000000000000..c920cd7de1b7 --- /dev/null +++ b/include/deal.II/differentiation/sd/symengine_scalar_operations.h @@ -0,0 +1,119 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_differentiation_sd_symengine_scalar_operations_h +#define dealii_differentiation_sd_symengine_scalar_operations_h + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include + +# include +# include + +# include +# include +# include +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + /** + * @name Symbolic variable creation + */ + //@{ + + /** + * Return an Expression representing a scalar symbolic variable + * with the identifier specified by @p symbol. + * + * For example, if the @p symbol is the string `"x"` then the scalar + * symbolic variable that is returned represents the scalar $x$. + * + * @param[in] symbol An indentifier (or name) for the returned symbolic + * variable. + * @return A scalar symbolic variable with the name @p symbol. + * + * @warning It is up to the user to ensure that there is no ambiguity in the + * symbols used within a section of code. + */ + Expression + make_symbol(const std::string &symbol); + + /** + * Return an Expression representing a scalar symbolic function + * with the identifier specified by @p symbol. The function's symbolic + * dependencies are specified by the input @p arguments. + * + * For example, if the @p symbol is the string `"f"`, and the + * arguments to the function that is generated are the + * symbolic variable `x` and the symbolic expression `y+z`, then the + * generic symbolic function that is returned represents $f(x, y+z)$. + * + * @param[in] symbol An indentifier (or name) for the returned symbolic + * function. + * @param[in] arguments A vector of input arguments to the returned + * symbolic function. + * @return A generic symbolic function with the identifier @p symbolic and + * the number of input arguments equal to the length of @p arguments. + * + * @warning It is up to the user to ensure that there is no ambiguity in the + * symbols used within a section of code. + */ + Expression + make_symbolic_function(const std::string & symbol, + const types::symbol_vector &arguments); + + /** + * Return an Expression representing a scalar symbolic function + * with the identifier specified by @p symbol. The function's symbolic + * dependencies are specified by the keys to the input @p arguments map; + * the values stored in the map are ignored. + * + * For example, if the @p symbol is the string `"f"`, and the + * arguments to the function that is generated are the + * symbolic variable `x` and the symbolic expression `y+z`, then the + * generic symbolic function that is returned represents $f(x, y+z)$. + * + * @param[in] symbol An indentifier (or name) for the returned symbolic + * function. + * @param[in] arguments A map of input arguments to the returned + * symbolic function. + * @return A generic symbolic function with the identifier @p symbolic and + * the number of input arguments equal to the length of @p arguments. + * + * @warning It is up to the user to ensure that there is no ambiguity in the + * symbols used within a section of code. + */ + Expression + make_symbolic_function(const std::string & symbol, + const types::substitution_map &arguments); + + //@} + + } // namespace SD +} // namespace Differentiation + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE + +#endif diff --git a/source/differentiation/sd/CMakeLists.txt b/source/differentiation/sd/CMakeLists.txt index 26920f47a919..0cb7b56a5e7e 100644 --- a/source/differentiation/sd/CMakeLists.txt +++ b/source/differentiation/sd/CMakeLists.txt @@ -18,6 +18,7 @@ INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) SET(_src symengine_math.cc symengine_number_types.cc + symengine_scalar_operations.cc symengine_types.cc symengine_utilities.cc ) diff --git a/source/differentiation/sd/symengine_scalar_operations.cc b/source/differentiation/sd/symengine_scalar_operations.cc new file mode 100644 index 000000000000..1757f0dca15a --- /dev/null +++ b/source/differentiation/sd/symengine_scalar_operations.cc @@ -0,0 +1,64 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include +# include +# include +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + /* ------------------------- Symbol creation -----------------------*/ + + + Expression + make_symbol(const std::string &symbol) + { + return Expression(symbol); + } + + + Expression + make_symbolic_function(const std::string & symbol, + const SD::types::symbol_vector &arguments) + { + return Expression(symbol, arguments); + } + + + Expression + make_symbolic_function(const std::string & symbol, + const SD::types::substitution_map &arguments) + { + return make_symbolic_function(symbol, + SD::Utilities::extract_symbols(arguments)); + } + + + } // namespace SD +} // namespace Differentiation + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE diff --git a/tests/symengine/symengine_scalar_operations_01.cc b/tests/symengine/symengine_scalar_operations_01.cc new file mode 100644 index 000000000000..666be3079ecf --- /dev/null +++ b/tests/symengine/symengine_scalar_operations_01.cc @@ -0,0 +1,55 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Check that symbols and symbolic functions can be created using the +// utility functions + +#include + +#include "../tests.h" + +using namespace dealii; +namespace SD = Differentiation::SD; + + +int +main() +{ + initlog(); + + using SD_number_t = SD::Expression; + + const SD::types::substitution_map sub_map{ + {SD_number_t("c"), SD_number_t(1.0)}, + {SD_number_t("b"), SD_number_t(2)}, + {SD_number_t("a"), SD_number_t(3.0f)}}; + + const SD::types::symbol_vector symbols{SD_number_t("c"), + SD_number_t("b"), + SD_number_t("a")}; + + const SD_number_t symb = SD::make_symbol("d"); + const SD_number_t symb_func_1 = SD::make_symbolic_function("f", symbols); + const SD_number_t symb_func_2 = SD::make_symbolic_function("g", sub_map); + + deallog << "Symbol: " << symb << std::endl; + deallog << "Symbolic function (vector of arguments): " << symb_func_1 + << std::endl; + deallog << "Symbolic function (map of arguments): " << symb_func_2 + << std::endl; + + deallog << "OK" << std::endl; +} diff --git a/tests/symengine/symengine_scalar_operations_01.output b/tests/symengine/symengine_scalar_operations_01.output new file mode 100644 index 000000000000..b81239fe9ad9 --- /dev/null +++ b/tests/symengine/symengine_scalar_operations_01.output @@ -0,0 +1,5 @@ + +DEAL::Symbol: d +DEAL::Symbolic function (vector of arguments): f(c, b, a) +DEAL::Symbolic function (map of arguments): g(a, b, c) +DEAL::OK From c74e7b6cede8a01f94ab4ac1b7002b5961b66303 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Sun, 14 Apr 2019 13:09:07 +0200 Subject: [PATCH 424/507] Add some SD-related convenience functions for scalar operations. Specifically, a non-member function for scalar differentiation of an Expression has been added. --- .../sd/symengine_scalar_operations.h | 21 +++++++++ .../sd/symengine_scalar_operations.cc | 9 ++++ .../symengine_scalar_operations_02.cc | 44 +++++++++++++++++++ .../symengine_scalar_operations_02.output | 5 +++ 4 files changed, 79 insertions(+) create mode 100644 tests/symengine/symengine_scalar_operations_02.cc create mode 100644 tests/symengine/symengine_scalar_operations_02.output diff --git a/include/deal.II/differentiation/sd/symengine_scalar_operations.h b/include/deal.II/differentiation/sd/symengine_scalar_operations.h index c920cd7de1b7..15b9dc752922 100644 --- a/include/deal.II/differentiation/sd/symengine_scalar_operations.h +++ b/include/deal.II/differentiation/sd/symengine_scalar_operations.h @@ -109,6 +109,27 @@ namespace Differentiation //@} + /** + * @name Symbolic differentiation + */ + //@{ + + /** + * Return the symbolic result of computing the partial derivative of the + * scalar @p f with respect to the scalar @p x. + * In most use cases the function or variable @f would be called the + * dependent variable, and @p x the independent variable. + * + * @param[in] f A scalar symbolic function or (dependent) variable. + * @param[in] x A scalar symbolic (independent) variable. + * @return The symbolic function or variable representing the result + * $\frac{\partial f}{\partial x}$. + */ + Expression + differentiate(const Expression &f, const Expression &x); + + //@} + } // namespace SD } // namespace Differentiation diff --git a/source/differentiation/sd/symengine_scalar_operations.cc b/source/differentiation/sd/symengine_scalar_operations.cc index 1757f0dca15a..7df4e22cc07a 100644 --- a/source/differentiation/sd/symengine_scalar_operations.cc +++ b/source/differentiation/sd/symengine_scalar_operations.cc @@ -56,6 +56,15 @@ namespace Differentiation } + /* --------------------------- Differentiation ------------------------- */ + + + Expression + differentiate(const Expression &func, const Expression &op) + { + return func.differentiate(op); + } + } // namespace SD } // namespace Differentiation diff --git a/tests/symengine/symengine_scalar_operations_02.cc b/tests/symengine/symengine_scalar_operations_02.cc new file mode 100644 index 000000000000..db2e61af517a --- /dev/null +++ b/tests/symengine/symengine_scalar_operations_02.cc @@ -0,0 +1,44 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Check that scalar differentiation can be performed using the utility +// functions + +#include + +#include "../tests.h" + +using namespace dealii; +namespace SD = Differentiation::SD; + + +int +main() +{ + initlog(); + + using SD_number_t = SD::Expression; + + const SD_number_t x = SD::make_symbol("x"); + const SD_number_t f = 2 * x * x; + const SD_number_t df_dx = SD::differentiate(f, x); + + deallog << "x: " << x << std::endl; + deallog << "f: " << f << std::endl; + deallog << "df_dx: " << df_dx << std::endl; + + deallog << "OK" << std::endl; +} diff --git a/tests/symengine/symengine_scalar_operations_02.output b/tests/symengine/symengine_scalar_operations_02.output new file mode 100644 index 000000000000..91cad5cafa5a --- /dev/null +++ b/tests/symengine/symengine_scalar_operations_02.output @@ -0,0 +1,5 @@ + +DEAL::x: x +DEAL::f: 2*x**2 +DEAL::df_dx: 4*x +DEAL::OK From 0a91cd1a9f9439c7795b1a543ffbc05999525b4c Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Wed, 17 Apr 2019 22:08:09 +0200 Subject: [PATCH 425/507] Add template arguments for symmetric tensor ranks --- cmake/config/template-arguments.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/config/template-arguments.in b/cmake/config/template-arguments.in index 2e1a69bd7618..3370a92a6cbd 100644 --- a/cmake/config/template-arguments.in +++ b/cmake/config/template-arguments.in @@ -266,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; From ab67ed22932f45e353b2c71ad4080e83e85f10d8 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Wed, 17 Apr 2019 22:27:00 +0200 Subject: [PATCH 426/507] Add ProductType for SD::Expression class. This is the first step towards support of SD::Expression within the Tensor and SymmetricTensor classes. --- include/deal.II/differentiation/sd.h | 1 + .../sd/symengine_product_types.h | 121 ++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 include/deal.II/differentiation/sd/symengine_product_types.h diff --git a/include/deal.II/differentiation/sd.h b/include/deal.II/differentiation/sd.h index 2050e6a509df..5039e8a4a2b5 100644 --- a/include/deal.II/differentiation/sd.h +++ b/include/deal.II/differentiation/sd.h @@ -23,6 +23,7 @@ # include # include # include +# include # include # include # include diff --git a/include/deal.II/differentiation/sd/symengine_product_types.h b/include/deal.II/differentiation/sd/symengine_product_types.h new file mode 100644 index 000000000000..06d78aa6c5d2 --- /dev/null +++ b/include/deal.II/differentiation/sd/symengine_product_types.h @@ -0,0 +1,121 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_differentiation_sd_symengine_product_types_h +#define dealii_differentiation_sd_symengine_product_types_h + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + + +# include + +# include + +# include + +# include + + +DEAL_II_NAMESPACE_OPEN + + +template <> +struct EnableIfScalar +{ + typedef Differentiation::SD::Expression type; +}; + + +namespace internal +{ + namespace SD + { + /** + * A more general implementation of product types. + * There are so many permutation of admissible operations + * that getting the compiler to determine the valid + * combinations using template metaprogramming makes + * more sense than manually maintaining the list by + * hand. + * + * This class is a workaround for issue of non-deduction + * of types in template partial specializations that + * would otherwise occur if trying to directly implement + * these as specializations of the ProductTypeImpl class + * itself. + * + * @author Jean-Paul Pelteret, 2019 + */ + template + struct GeneralProductTypeImpl; + + template + struct GeneralProductTypeImpl< + T, + Differentiation::SD::Expression, + typename std::enable_if::value>::type> + { + typedef Differentiation::SD::Expression type; + }; + + template + struct GeneralProductTypeImpl< + T, + Differentiation::SD::Expression, + typename std::enable_if< + boost::is_complex::value && + std::is_arithmetic::value>::type> + { + typedef Differentiation::SD::Expression type; + }; + + } // namespace SD + + + template <> + struct ProductTypeImpl + { + typedef Differentiation::SD::Expression type; + }; + + + template + struct ProductTypeImpl + { + typedef + typename SD::GeneralProductTypeImpl::type + type; + }; + + template + struct ProductTypeImpl + { + typedef + typename SD::GeneralProductTypeImpl::type + type; + }; + +} // namespace internal + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE + +#endif From 606ecdce1d341da8fa2a784c364beb57db346b07 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Wed, 17 Apr 2019 22:28:16 +0200 Subject: [PATCH 427/507] Specialize some functions in the numbers namespace for SD::Expression. Also required for support of SD::Expression within the Tensor and SymmetricTensor classes. --- .../sd/symengine_number_types.h | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/include/deal.II/differentiation/sd/symengine_number_types.h b/include/deal.II/differentiation/sd/symengine_number_types.h index b3a487dcb2c6..23db60cd6ec9 100644 --- a/include/deal.II/differentiation/sd/symengine_number_types.h +++ b/include/deal.II/differentiation/sd/symengine_number_types.h @@ -30,6 +30,7 @@ # include # include # include +# include # include // Number operations @@ -1292,6 +1293,42 @@ namespace Differentiation } // namespace Differentiation +// Specializations from numbers.h +// These are required in order to make the SD::Expression class a compatible +// number for the Tensor and SymmetricTensor classes +namespace numbers +{ + template <> + inline bool + value_is_zero(const Differentiation::SD::Expression &value) + { + if (SymEngine::is_a_Number(value.get_value())) + { + const SymEngine::RCP number_rcp = + SymEngine::rcp_static_cast(value.get_RCP()); + return number_rcp->is_zero(); + } + + return false; + } + + template <> + inline bool + values_are_equal(const Differentiation::SD::Expression &value_1, + const Differentiation::SD::Expression &value_2) + { + return (value_1.get_value().__cmp__(value_2.get_value()) == 0); + } + + template <> + inline bool + value_is_less_than(const Differentiation::SD::Expression &value_1, + const Differentiation::SD::Expression &value_2) + { + return (value_1.get_value().__cmp__(value_2.get_value()) == -1); + } +} // namespace numbers + DEAL_II_NAMESPACE_CLOSE From 50d4e6c1c09ab607fca528aabb8c67cb2592efc4 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Wed, 17 Apr 2019 22:29:31 +0200 Subject: [PATCH 428/507] Add some SD-related convenience functions for tensor operations. Specifically, these can be used to create a tensor symbol and symbolic function. --- include/deal.II/differentiation/sd.h | 1 + .../sd/symengine_number_types.h | 65 +++- .../sd/symengine_tensor_operations.h | 196 +++++++++++ source/differentiation/sd/CMakeLists.txt | 2 + .../sd/symengine_tensor_operations.cc | 313 ++++++++++++++++++ .../sd/symengine_tensor_operations.inst.in | 85 +++++ .../symengine_tensor_operations_01.cc | 112 +++++++ .../symengine_tensor_operations_01.output | 53 +++ 8 files changed, 825 insertions(+), 2 deletions(-) create mode 100644 include/deal.II/differentiation/sd/symengine_tensor_operations.h create mode 100644 source/differentiation/sd/symengine_tensor_operations.cc create mode 100644 source/differentiation/sd/symengine_tensor_operations.inst.in create mode 100644 tests/symengine/symengine_tensor_operations_01.cc create mode 100644 tests/symengine/symengine_tensor_operations_01.output diff --git a/include/deal.II/differentiation/sd.h b/include/deal.II/differentiation/sd.h index 5039e8a4a2b5..44dca06e9e2f 100644 --- a/include/deal.II/differentiation/sd.h +++ b/include/deal.II/differentiation/sd.h @@ -25,6 +25,7 @@ # include # include # include +# include # include # include diff --git a/include/deal.II/differentiation/sd/symengine_number_types.h b/include/deal.II/differentiation/sd/symengine_number_types.h index 23db60cd6ec9..2b4c65330874 100644 --- a/include/deal.II/differentiation/sd/symengine_number_types.h +++ b/include/deal.II/differentiation/sd/symengine_number_types.h @@ -46,6 +46,7 @@ // Differentiation # include +# include # include # include @@ -1296,6 +1297,66 @@ namespace Differentiation // Specializations from numbers.h // These are required in order to make the SD::Expression class a compatible // number for the Tensor and SymmetricTensor classes + +// Forward declarations: +template +class Tensor; + +namespace internal +{ + template <> + struct NumberType + { + static const Differentiation::SD::Expression & + value(const Differentiation::SD::Expression &t) + { + return t; + } + + template < + typename T, + typename = typename std::enable_if::value>::type> + static Differentiation::SD::Expression + value(const T &t) + { + return Differentiation::SD::Expression(t); + } + + template < + typename T, + typename = typename std::enable_if::value>::type> + static Differentiation::SD::Expression + value(T &&t) + { + return Differentiation::SD::Expression(t); + } + + template < + typename T, + typename = typename std::enable_if::value>::type> + static Differentiation::SD::Expression + value(const std::complex &t) + { + return Differentiation::SD::Expression(t); + } + + template + static Differentiation::SD::Expression + value(const Tensor<0, dim, T> &t) + { + return Differentiation::SD::Expression(static_cast(t)); + } + + template + static Differentiation::SD::Expression + value(const Tensor<0, dim, std::complex> &t) + { + return Differentiation::SD::Expression(static_cast>(t)); + } + }; +} // namespace internal + + namespace numbers { template <> @@ -1329,11 +1390,11 @@ namespace numbers } } // namespace numbers -DEAL_II_NAMESPACE_CLOSE - # endif // DOXYGEN +DEAL_II_NAMESPACE_CLOSE + #endif // DEAL_II_WITH_SYMENGINE #endif // dealii_differentiation_sd_symengine_number_types_h diff --git a/include/deal.II/differentiation/sd/symengine_tensor_operations.h b/include/deal.II/differentiation/sd/symengine_tensor_operations.h new file mode 100644 index 000000000000..d8ba72018094 --- /dev/null +++ b/include/deal.II/differentiation/sd/symengine_tensor_operations.h @@ -0,0 +1,196 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +#ifndef dealii_differentiation_sd_symengine_tensor_operations_h +#define dealii_differentiation_sd_symengine_tensor_operations_h + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include +# include + +# include +# include + +# include +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + /** + * @name Symbolic variable creation + */ + //@{ + + /** + * Return a vector of Expressions representing a vectorial symbolic + * variable with the identifier specified by @p symbol. + * + * For example, if the @p symbol is the string `"v"` then the vectorial + * symbolic variable that is returned represents the vector $v$. Each + * component of $v$ is prefixed by the given @p symbol, and has a suffix that + * indicates its component index. + * + * @tparam dim The dimension of the returned tensor. + * @param[in] symbol An indentifier (or name) for the vector of returned + * symbolic variables. + * @return A vector (a rank-1 tensor) of symbolic variables with the name of + * each individual component prefixed by @p symbol. + * + * @warning It is up to the user to ensure that there is no ambiguity in the + * symbols used within a section of code. + */ + template + Tensor<1, dim, Expression> + make_vector_of_symbols(const std::string &symbol); + + /** + * Return a tensor of Expressions representing a tensorial symbolic + * variable with the identifier specified by @p symbol. + * + * For example, if the @p symbol is the string `"T"` then the tensorial + * symbolic variable that is returned represents the vector $T$. Each + * component of $T$ is prefixed by the given @p symbol, and has a suffix that + * indicates its component indices. + * + * @tparam rank The rank of the returned tensor. + * @tparam dim The dimension of the returned tensor. + * @param[in] symbol An indentifier (or name) for the tensor of returned + * symbolic variables. + * @return A tensor of symbolic variables with the name of each individual + * component prefixed by @p symbol. + * + * @warning It is up to the user to ensure that there is no ambiguity in the + * symbols used within a section of code. + */ + template + Tensor + make_tensor_of_symbols(const std::string &symbol); + + /** + * Return a symmetric tensor of Expressions representing a tensorial + * symbolic variable with the identifier specified by @p symbol. + * + * For example, if the @p symbol is the string `"S"` then the tensorial + * symbolic variable that is returned represents the vector $S$. Each + * component of $S$ is prefixed by the given @p symbol, and has a suffix that + * indicates its component indices. + * + * @tparam rank The rank of the returned tensor. + * @tparam dim The dimension of the returned tensor. + * @param[in] symbol An indentifier (or name) for the tensor of returned + * symbolic variables. + * @return A tensor of symbolic variables with the name of each individual + * component prefixed by @p symbol. + * + * @warning It is up to the user to ensure that there is no ambiguity in the + * symbols used within a section of code. + */ + template + SymmetricTensor + make_symmetric_tensor_of_symbols(const std::string &symbol); + + /** + * Return a vector of Expression representing a vectorial symbolic + * function with the identifier specified by @p symbol. The functions' + * symbolic dependencies are specified by the keys to the input + * @p arguments map; the values stored in the map are ignored. + * + * @tparam dim The dimension of the returned tensor. + * @param[in] symbol An indentifier (or name) for the vector of returned + * symbolic functions. + * @param[in] arguments A map of input arguments to the returned + * symbolic functions. + * @return A vector (a rank-1 tensor) of generic symbolic functions with the + * name of each individual component prefixed by @p symbol, a suffix + * that indicates its component index, and the number of input + * arguments equal to the length of @p arguments. + * + * @warning It is up to the user to ensure that there is no ambiguity in the + * symbols used within a section of code. + */ + template + Tensor<1, dim, Expression> + make_vector_of_symbolic_functions(const std::string & symbol, + const types::substitution_map &arguments); + + /** + * Return a tensor of Expression representing a tensorial symbolic + * function with the identifier specified by @p symbol. The functions' + * symbolic dependencies are specified by the keys to the input + * @p arguments map; the values stored in the map are ignored. + * + * @tparam rank The rank of the returned tensor. + * @tparam dim The dimension of the returned tensor. + * @param[in] symbol An indentifier (or name) for the tensor of returned + * symbolic functions. + * @param[in] arguments A map of input arguments to the returned + * symbolic functions. + * @return A tensor of generic symbolic functions with the name of each + * individual component prefixed by @p symbol, a suffix that + * indicates its component indeices, and the number of input + * arguments equal to the length of @p arguments. + * + * @warning It is up to the user to ensure that there is no ambiguity in the + * symbols used within a section of code. + */ + template + Tensor + make_tensor_of_symbolic_functions(const std::string & symbol, + const types::substitution_map &arguments); + + /** + * Return a symmetric tensor of Expression representing a tensorial + * symbolic function with the identifier specified by @p symbol. The + * functions' symbolic dependencies are specified by the keys to the input + * @p arguments map; the values stored in the map are ignored. + * + * @tparam rank The rank of the returned tensor. + * @tparam dim The dimension of the returned tensor. + * @param[in] symbol An indentifier (or name) for the tensor of returned + * symbolic functions. + * @param[in] arguments A map of input arguments to the returned + * symbolic functions. + * @return A symmetric tensor of generic symbolic functions with the name of + * each individual component prefixed by @p symbol, a suffix that + * indicates its component indeices, and the number of input + * arguments equal to the length of @p arguments. + * + * @warning It is up to the user to ensure that there is no ambiguity in the + * symbols used within a section of code. + */ + template + SymmetricTensor + make_symmetric_tensor_of_symbolic_functions( + const std::string & symbol, + const types::substitution_map &arguments); + + //@} + + } // namespace SD +} // namespace Differentiation + + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE + +#endif diff --git a/source/differentiation/sd/CMakeLists.txt b/source/differentiation/sd/CMakeLists.txt index 0cb7b56a5e7e..a0de87e090d6 100644 --- a/source/differentiation/sd/CMakeLists.txt +++ b/source/differentiation/sd/CMakeLists.txt @@ -19,11 +19,13 @@ SET(_src symengine_math.cc symengine_number_types.cc symengine_scalar_operations.cc + symengine_tensor_operations.cc symengine_types.cc symengine_utilities.cc ) SET(_inst + symengine_tensor_operations.inst.in ) FILE(GLOB _header diff --git a/source/differentiation/sd/symengine_tensor_operations.cc b/source/differentiation/sd/symengine_tensor_operations.cc new file mode 100644 index 000000000000..bd2e743623f9 --- /dev/null +++ b/source/differentiation/sd/symengine_tensor_operations.cc @@ -0,0 +1,313 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 - 2017 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. +// +// --------------------------------------------------------------------- + + +#include + +#ifdef DEAL_II_WITH_SYMENGINE + +# include +# include +# include + +# include +# include +# include +# include +# include + +DEAL_II_NAMESPACE_OPEN + +namespace Differentiation +{ + namespace SD + { + // --- Symbolic variable creation --- + + namespace internal + { + namespace + { + template + TableIndices<4> + make_rank_4_tensor_indices(const unsigned int &idx_i, + const unsigned int &idx_j) + { + const TableIndices<2> indices_i( + SymmetricTensor<2, dim>::unrolled_to_component_indices(idx_i)); + const TableIndices<2> indices_j( + SymmetricTensor<2, dim>::unrolled_to_component_indices(idx_j)); + return TableIndices<4>(indices_i[0], + indices_i[1], + indices_j[0], + indices_j[1]); + } + + + template + std::string + make_index_string(const TableIndices &indices) + { + std::string out; + for (unsigned int i = 0; i < rank; ++i) + out += dealii::Utilities::to_string(indices[i]); + return out; + } + + + template + struct Symbol_Tensor; + + + template + struct Symbol_Tensor + { + static Tensor + create(const std::string &sym) + { + Tensor out; + for (unsigned int i = 0; i < out.n_independent_components; ++i) + { + const TableIndices indices( + out.unrolled_to_component_indices(i)); + out[indices] = Expression(sym + std::string("_") + + internal::make_index_string(indices)); + } + return out; + } + }; + + + template + struct Symbol_Tensor<0, dim> + { + static Tensor<0, dim, Expression> + create(const std::string &sym) + { + return make_symbol(sym); + } + }; + + + template + struct Symbol_SymmetricTensor; + + + template + struct Symbol_SymmetricTensor + { + static SymmetricTensor<2, dim, Expression> + create(const std::string &sym) + { + SymmetricTensor out; + for (unsigned int i = 0; i < out.n_independent_components; ++i) + { + const TableIndices indices( + out.unrolled_to_component_indices(i)); + out[indices] = Expression(sym + std::string("_") + + internal::make_index_string(indices)); + } + return out; + } + }; + + + template + struct Symbol_SymmetricTensor<4, dim> + { + static SymmetricTensor<4, dim, Expression> + create(const std::string &sym) + { + SymmetricTensor<4, dim, Expression> out; + for (unsigned int i = 0; + i < SymmetricTensor<2, dim>::n_independent_components; + ++i) + for (unsigned int j = 0; + j < SymmetricTensor<2, dim>::n_independent_components; + ++j) + { + const TableIndices<4> indices = + make_rank_4_tensor_indices(i, j); + out[indices] = + Expression(sym + std::string("_") + + internal::make_index_string(indices)); + } + return out; + } + }; + + + template + struct Symbol_Function_Tensor; + + + template + struct Symbol_Function_Tensor + { + static Tensor + create(const std::string & sym, + const types::substitution_map &arguments) + { + Tensor out; + const types::symbol_vector args = + Utilities::extract_symbols(arguments); + for (unsigned int i = 0; i < out.n_independent_components; ++i) + { + const TableIndices indices( + out.unrolled_to_component_indices(i)); + out[indices] = + Expression(sym + std::string("_") + + internal::make_index_string(indices), + args); + } + return out; + } + }; + + + template + struct Symbol_Function_Tensor<0, dim> + { + static Tensor<0, dim, Expression> + create(const std::string & sym, + const types::substitution_map &arguments) + { + return make_symbolic_function(sym, arguments); + } + }; + + + template + struct Symbol_Function_SymmetricTensor; + + + template + struct Symbol_Function_SymmetricTensor + { + static SymmetricTensor<2, dim, Expression> + create(const std::string & sym, + const types::substitution_map &arguments) + { + SymmetricTensor out; + const types::symbol_vector args = + Utilities::extract_symbols(arguments); + for (unsigned int i = 0; i < out.n_independent_components; ++i) + { + const TableIndices indices( + out.unrolled_to_component_indices(i)); + out[indices] = + Expression(sym + std::string("_") + + internal::make_index_string(indices), + args); + } + return out; + } + }; + + + template + struct Symbol_Function_SymmetricTensor<4, dim> + { + static SymmetricTensor<4, dim, Expression> + create(const std::string & sym, + const types::substitution_map &arguments) + { + SymmetricTensor<4, dim, Expression> out; + const types::symbol_vector args = + Utilities::extract_symbols(arguments); + for (unsigned int i = 0; + i < SymmetricTensor<2, dim>::n_independent_components; + ++i) + for (unsigned int j = 0; + j < SymmetricTensor<2, dim>::n_independent_components; + ++j) + { + const TableIndices<4> indices = + make_rank_4_tensor_indices(i, j); + out[indices] = + Expression(sym + std::string("_") + + internal::make_index_string(indices), + args); + } + return out; + } + }; + } // namespace + } // namespace internal + + + template + Tensor<1, dim, Expression> + make_vector_of_symbols(const std::string &sym) + { + return internal::Symbol_Tensor<1, dim>::create(sym); + } + + + template + Tensor<1, dim, Expression> + make_vector_of_symbolic_functions(const std::string & sym, + const types::substitution_map &arguments) + { + return internal::Symbol_Function_Tensor<1, dim>::create(sym, arguments); + } + + + template + Tensor + make_tensor_of_symbols(const std::string &sym) + { + return internal::Symbol_Tensor::create(sym); + } + + + template + SymmetricTensor + make_symmetric_tensor_of_symbols(const std::string &sym) + { + return internal::Symbol_SymmetricTensor::create(sym); + } + + + template + Tensor + make_tensor_of_symbolic_functions(const std::string & sym, + const types::substitution_map &arguments) + { + return internal::Symbol_Function_Tensor::create(sym, + arguments); + } + + + template + SymmetricTensor + make_symmetric_tensor_of_symbolic_functions( + const std::string & sym, + const types::substitution_map &arguments) + { + return internal::Symbol_Function_SymmetricTensor::create( + sym, arguments); + } + + } // namespace SD +} // namespace Differentiation + +/* --- Explicit instantiations --- */ + +# include "symengine_tensor_operations.inst" + +DEAL_II_NAMESPACE_CLOSE + +#endif // DEAL_II_WITH_SYMENGINE diff --git a/source/differentiation/sd/symengine_tensor_operations.inst.in b/source/differentiation/sd/symengine_tensor_operations.inst.in new file mode 100644 index 000000000000..1a4a80204cbd --- /dev/null +++ b/source/differentiation/sd/symengine_tensor_operations.inst.in @@ -0,0 +1,85 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +for (deal_II_dimension : DIMENSIONS) + { + namespace Differentiation + \{ + namespace SD + \{ + + template Tensor<1, deal_II_dimension, Expression> + make_vector_of_symbols(const std::string &symbol); + + template Tensor<1, deal_II_dimension, Expression> + make_vector_of_symbolic_functions( + const std::string & symbol, + const types::substitution_map &arguments); + + /*--- Rank-0 definitions ---*/ + + template Tensor<0, deal_II_dimension, Expression> + make_tensor_of_symbols<0, deal_II_dimension>(const std::string &symbol); + + template Tensor<0, deal_II_dimension, Expression> + make_tensor_of_symbolic_functions<0, deal_II_dimension>( + const std::string & symbol, + const types::substitution_map &arguments); + \} + \} + } + + +for (rank : RANKS; deal_II_dimension : DIMENSIONS) + { + namespace Differentiation + \{ + namespace SD + \{ + + template Tensor + make_tensor_of_symbols( + const std::string &symbol); + + template Tensor + make_tensor_of_symbolic_functions( + const std::string & symbol, + const types::substitution_map &arguments); + + \} + \} + } + + +for (rank : SYM_RANKS; deal_II_dimension : DIMENSIONS) + { + namespace Differentiation + \{ + namespace SD + \{ + + template SymmetricTensor + make_symmetric_tensor_of_symbols( + const std::string &symbol); + + template SymmetricTensor + make_symmetric_tensor_of_symbolic_functions( + const std::string & symbol, + const types::substitution_map &arguments); + + \} + \} + } diff --git a/tests/symengine/symengine_tensor_operations_01.cc b/tests/symengine/symengine_tensor_operations_01.cc new file mode 100644 index 000000000000..b750d40dbcef --- /dev/null +++ b/tests/symengine/symengine_tensor_operations_01.cc @@ -0,0 +1,112 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Check that symbol tensors and symbolic function tensors can be created +// using the utility functions + +#include + +#include "../tests.h" + +using namespace dealii; +namespace SD = Differentiation::SD; + + +template +void +test() +{ + deallog.push("dim " + Utilities::to_string(dim)); + + using SD_number_t = SD::Expression; + + const Tensor<1, dim, SD_number_t> symb_v = + SD::make_vector_of_symbols("v"); + const Tensor<0, dim, SD_number_t> symb_T0 = + SD::make_tensor_of_symbols<0, dim>("T0"); + const Tensor<1, dim, SD_number_t> symb_T1 = + SD::make_tensor_of_symbols<1, dim>("T1"); + const Tensor<2, dim, SD_number_t> symb_T2 = + SD::make_tensor_of_symbols<2, dim>("T2"); + const Tensor<3, dim, SD_number_t> symb_T3 = + SD::make_tensor_of_symbols<3, dim>("T3"); + const Tensor<4, dim, SD_number_t> symb_T4 = + SD::make_tensor_of_symbols<4, dim>("T4"); + const SymmetricTensor<2, dim, SD_number_t> symb_ST2 = + SD::make_symmetric_tensor_of_symbols<2, dim>("ST2"); + const SymmetricTensor<4, dim, SD_number_t> symb_ST4 = + SD::make_symmetric_tensor_of_symbols<4, dim>("ST4"); + + deallog << "Symbol vector: " << symb_v << std::endl; + deallog << "Symbol tensor (rank-0): " << symb_T0 << std::endl; + deallog << "Symbol tensor (rank-1): " << symb_T1 << std::endl; + deallog << "Symbol tensor (rank-2): " << symb_T2 << std::endl; + deallog << "Symbol tensor (rank-3): " << symb_T3 << std::endl; + deallog << "Symbol tensor (rank-4): " << symb_T4 << std::endl; + deallog << "Symbol symmetric tensor (rank-2): " << symb_ST2 << std::endl; + deallog << "Symbol symmetric tensor (rank-4): " << symb_ST4 << std::endl; + + SD::types::substitution_map sub_map; + sub_map[symb_T0] = 0.0; + for (unsigned int i = 0; i < dim; ++i) + { + sub_map[symb_v[i]] = 0.0; + } + + const Tensor<1, dim, SD_number_t> symb_func_v = + SD::make_vector_of_symbolic_functions("f_v", sub_map); + const Tensor<0, dim, SD_number_t> symb_func_T0 = + SD::make_tensor_of_symbolic_functions<0, dim>("f_T0", sub_map); + const Tensor<1, dim, SD_number_t> symb_func_T1 = + SD::make_tensor_of_symbolic_functions<1, dim>("f_T1", sub_map); + const Tensor<2, dim, SD_number_t> symb_func_T2 = + SD::make_tensor_of_symbolic_functions<2, dim>("f_T2", sub_map); + const Tensor<3, dim, SD_number_t> symb_func_T3 = + SD::make_tensor_of_symbolic_functions<3, dim>("f_T3", sub_map); + const Tensor<4, dim, SD_number_t> symb_func_T4 = + SD::make_tensor_of_symbolic_functions<4, dim>("f_T4", sub_map); + const SymmetricTensor<2, dim, SD_number_t> symb_func_ST2 = + SD::make_symmetric_tensor_of_symbolic_functions<2, dim>("f_ST2", sub_map); + const SymmetricTensor<4, dim, SD_number_t> symb_func_ST4 = + SD::make_symmetric_tensor_of_symbolic_functions<4, dim>("f_ST4", sub_map); + + deallog << "Symbol function vector: " << symb_func_v << std::endl; + deallog << "Symbol function tensor (rank-0): " << symb_func_T0 << std::endl; + deallog << "Symbol function tensor (rank-1): " << symb_func_T1 << std::endl; + deallog << "Symbol function tensor (rank-2): " << symb_func_T2 << std::endl; + deallog << "Symbol function tensor (rank-3): " << symb_func_T3 << std::endl; + deallog << "Symbol function tensor (rank-4): " << symb_func_T4 << std::endl; + deallog << "Symbol function symmetric tensor (rank-2): " << symb_func_ST2 + << std::endl; + deallog << "Symbol function symmetric tensor (rank-4): " << symb_func_ST4 + << std::endl; + + deallog << "OK" << std::endl; + deallog.pop(); +} + + +int +main() +{ + initlog(); + + test<1>(); + test<2>(); + test<3>(); + + deallog << "OK" << std::endl; +} diff --git a/tests/symengine/symengine_tensor_operations_01.output b/tests/symengine/symengine_tensor_operations_01.output new file mode 100644 index 000000000000..ee6a9771745f --- /dev/null +++ b/tests/symengine/symengine_tensor_operations_01.output @@ -0,0 +1,53 @@ + +DEAL:dim 1::Symbol vector: v_0 +DEAL:dim 1::Symbol tensor (rank-0): T0 +DEAL:dim 1::Symbol tensor (rank-1): T1_0 +DEAL:dim 1::Symbol tensor (rank-2): T2_00 +DEAL:dim 1::Symbol tensor (rank-3): T3_000 +DEAL:dim 1::Symbol tensor (rank-4): T4_0000 +DEAL:dim 1::Symbol symmetric tensor (rank-2): ST2_00 +DEAL:dim 1::Symbol symmetric tensor (rank-4): ST4_0000 +DEAL:dim 1::Symbol function vector: f_v_0(T0, v_0) +DEAL:dim 1::Symbol function tensor (rank-0): f_T0(T0, v_0) +DEAL:dim 1::Symbol function tensor (rank-1): f_T1_0(T0, v_0) +DEAL:dim 1::Symbol function tensor (rank-2): f_T2_00(T0, v_0) +DEAL:dim 1::Symbol function tensor (rank-3): f_T3_000(T0, v_0) +DEAL:dim 1::Symbol function tensor (rank-4): f_T4_0000(T0, v_0) +DEAL:dim 1::Symbol function symmetric tensor (rank-2): f_ST2_00(T0, v_0) +DEAL:dim 1::Symbol function symmetric tensor (rank-4): f_ST4_0000(T0, v_0) +DEAL:dim 1::OK +DEAL:dim 2::Symbol vector: v_0 v_1 +DEAL:dim 2::Symbol tensor (rank-0): T0 +DEAL:dim 2::Symbol tensor (rank-1): T1_0 T1_1 +DEAL:dim 2::Symbol tensor (rank-2): T2_00 T2_01 T2_10 T2_11 +DEAL:dim 2::Symbol tensor (rank-3): T3_000 T3_001 T3_010 T3_011 T3_100 T3_101 T3_110 T3_111 +DEAL:dim 2::Symbol tensor (rank-4): T4_0000 T4_0001 T4_0010 T4_0011 T4_0100 T4_0101 T4_0110 T4_0111 T4_1000 T4_1001 T4_1010 T4_1011 T4_1100 T4_1101 T4_1110 T4_1111 +DEAL:dim 2::Symbol symmetric tensor (rank-2): ST2_00 ST2_01 ST2_01 ST2_11 +DEAL:dim 2::Symbol symmetric tensor (rank-4): ST4_0000 ST4_0001 ST4_0001 ST4_0011 ST4_0100 ST4_0101 ST4_0101 ST4_0111 ST4_0100 ST4_0101 ST4_0101 ST4_0111 ST4_1100 ST4_1101 ST4_1101 ST4_1111 +DEAL:dim 2::Symbol function vector: f_v_0(T0, v_0, v_1) f_v_1(T0, v_0, v_1) +DEAL:dim 2::Symbol function tensor (rank-0): f_T0(T0, v_0, v_1) +DEAL:dim 2::Symbol function tensor (rank-1): f_T1_0(T0, v_0, v_1) f_T1_1(T0, v_0, v_1) +DEAL:dim 2::Symbol function tensor (rank-2): f_T2_00(T0, v_0, v_1) f_T2_01(T0, v_0, v_1) f_T2_10(T0, v_0, v_1) f_T2_11(T0, v_0, v_1) +DEAL:dim 2::Symbol function tensor (rank-3): f_T3_000(T0, v_0, v_1) f_T3_001(T0, v_0, v_1) f_T3_010(T0, v_0, v_1) f_T3_011(T0, v_0, v_1) f_T3_100(T0, v_0, v_1) f_T3_101(T0, v_0, v_1) f_T3_110(T0, v_0, v_1) f_T3_111(T0, v_0, v_1) +DEAL:dim 2::Symbol function tensor (rank-4): f_T4_0000(T0, v_0, v_1) f_T4_0001(T0, v_0, v_1) f_T4_0010(T0, v_0, v_1) f_T4_0011(T0, v_0, v_1) f_T4_0100(T0, v_0, v_1) f_T4_0101(T0, v_0, v_1) f_T4_0110(T0, v_0, v_1) f_T4_0111(T0, v_0, v_1) f_T4_1000(T0, v_0, v_1) f_T4_1001(T0, v_0, v_1) f_T4_1010(T0, v_0, v_1) f_T4_1011(T0, v_0, v_1) f_T4_1100(T0, v_0, v_1) f_T4_1101(T0, v_0, v_1) f_T4_1110(T0, v_0, v_1) f_T4_1111(T0, v_0, v_1) +DEAL:dim 2::Symbol function symmetric tensor (rank-2): f_ST2_00(T0, v_0, v_1) f_ST2_01(T0, v_0, v_1) f_ST2_01(T0, v_0, v_1) f_ST2_11(T0, v_0, v_1) +DEAL:dim 2::Symbol function symmetric tensor (rank-4): f_ST4_0000(T0, v_0, v_1) f_ST4_0001(T0, v_0, v_1) f_ST4_0001(T0, v_0, v_1) f_ST4_0011(T0, v_0, v_1) f_ST4_0100(T0, v_0, v_1) f_ST4_0101(T0, v_0, v_1) f_ST4_0101(T0, v_0, v_1) f_ST4_0111(T0, v_0, v_1) f_ST4_0100(T0, v_0, v_1) f_ST4_0101(T0, v_0, v_1) f_ST4_0101(T0, v_0, v_1) f_ST4_0111(T0, v_0, v_1) f_ST4_1100(T0, v_0, v_1) f_ST4_1101(T0, v_0, v_1) f_ST4_1101(T0, v_0, v_1) f_ST4_1111(T0, v_0, v_1) +DEAL:dim 2::OK +DEAL:dim 3::Symbol vector: v_0 v_1 v_2 +DEAL:dim 3::Symbol tensor (rank-0): T0 +DEAL:dim 3::Symbol tensor (rank-1): T1_0 T1_1 T1_2 +DEAL:dim 3::Symbol tensor (rank-2): T2_00 T2_01 T2_02 T2_10 T2_11 T2_12 T2_20 T2_21 T2_22 +DEAL:dim 3::Symbol tensor (rank-3): T3_000 T3_001 T3_002 T3_010 T3_011 T3_012 T3_020 T3_021 T3_022 T3_100 T3_101 T3_102 T3_110 T3_111 T3_112 T3_120 T3_121 T3_122 T3_200 T3_201 T3_202 T3_210 T3_211 T3_212 T3_220 T3_221 T3_222 +DEAL:dim 3::Symbol tensor (rank-4): T4_0000 T4_0001 T4_0002 T4_0010 T4_0011 T4_0012 T4_0020 T4_0021 T4_0022 T4_0100 T4_0101 T4_0102 T4_0110 T4_0111 T4_0112 T4_0120 T4_0121 T4_0122 T4_0200 T4_0201 T4_0202 T4_0210 T4_0211 T4_0212 T4_0220 T4_0221 T4_0222 T4_1000 T4_1001 T4_1002 T4_1010 T4_1011 T4_1012 T4_1020 T4_1021 T4_1022 T4_1100 T4_1101 T4_1102 T4_1110 T4_1111 T4_1112 T4_1120 T4_1121 T4_1122 T4_1200 T4_1201 T4_1202 T4_1210 T4_1211 T4_1212 T4_1220 T4_1221 T4_1222 T4_2000 T4_2001 T4_2002 T4_2010 T4_2011 T4_2012 T4_2020 T4_2021 T4_2022 T4_2100 T4_2101 T4_2102 T4_2110 T4_2111 T4_2112 T4_2120 T4_2121 T4_2122 T4_2200 T4_2201 T4_2202 T4_2210 T4_2211 T4_2212 T4_2220 T4_2221 T4_2222 +DEAL:dim 3::Symbol symmetric tensor (rank-2): ST2_00 ST2_01 ST2_02 ST2_01 ST2_11 ST2_12 ST2_02 ST2_12 ST2_22 +DEAL:dim 3::Symbol symmetric tensor (rank-4): ST4_0000 ST4_0001 ST4_0002 ST4_0001 ST4_0011 ST4_0012 ST4_0002 ST4_0012 ST4_0022 ST4_0100 ST4_0101 ST4_0102 ST4_0101 ST4_0111 ST4_0112 ST4_0102 ST4_0112 ST4_0122 ST4_0200 ST4_0201 ST4_0202 ST4_0201 ST4_0211 ST4_0212 ST4_0202 ST4_0212 ST4_0222 ST4_0100 ST4_0101 ST4_0102 ST4_0101 ST4_0111 ST4_0112 ST4_0102 ST4_0112 ST4_0122 ST4_1100 ST4_1101 ST4_1102 ST4_1101 ST4_1111 ST4_1112 ST4_1102 ST4_1112 ST4_1122 ST4_1200 ST4_1201 ST4_1202 ST4_1201 ST4_1211 ST4_1212 ST4_1202 ST4_1212 ST4_1222 ST4_0200 ST4_0201 ST4_0202 ST4_0201 ST4_0211 ST4_0212 ST4_0202 ST4_0212 ST4_0222 ST4_1200 ST4_1201 ST4_1202 ST4_1201 ST4_1211 ST4_1212 ST4_1202 ST4_1212 ST4_1222 ST4_2200 ST4_2201 ST4_2202 ST4_2201 ST4_2211 ST4_2212 ST4_2202 ST4_2212 ST4_2222 +DEAL:dim 3::Symbol function vector: f_v_0(T0, v_0, v_1, v_2) f_v_1(T0, v_0, v_1, v_2) f_v_2(T0, v_0, v_1, v_2) +DEAL:dim 3::Symbol function tensor (rank-0): f_T0(T0, v_0, v_1, v_2) +DEAL:dim 3::Symbol function tensor (rank-1): f_T1_0(T0, v_0, v_1, v_2) f_T1_1(T0, v_0, v_1, v_2) f_T1_2(T0, v_0, v_1, v_2) +DEAL:dim 3::Symbol function tensor (rank-2): f_T2_00(T0, v_0, v_1, v_2) f_T2_01(T0, v_0, v_1, v_2) f_T2_02(T0, v_0, v_1, v_2) f_T2_10(T0, v_0, v_1, v_2) f_T2_11(T0, v_0, v_1, v_2) f_T2_12(T0, v_0, v_1, v_2) f_T2_20(T0, v_0, v_1, v_2) f_T2_21(T0, v_0, v_1, v_2) f_T2_22(T0, v_0, v_1, v_2) +DEAL:dim 3::Symbol function tensor (rank-3): f_T3_000(T0, v_0, v_1, v_2) f_T3_001(T0, v_0, v_1, v_2) f_T3_002(T0, v_0, v_1, v_2) f_T3_010(T0, v_0, v_1, v_2) f_T3_011(T0, v_0, v_1, v_2) f_T3_012(T0, v_0, v_1, v_2) f_T3_020(T0, v_0, v_1, v_2) f_T3_021(T0, v_0, v_1, v_2) f_T3_022(T0, v_0, v_1, v_2) f_T3_100(T0, v_0, v_1, v_2) f_T3_101(T0, v_0, v_1, v_2) f_T3_102(T0, v_0, v_1, v_2) f_T3_110(T0, v_0, v_1, v_2) f_T3_111(T0, v_0, v_1, v_2) f_T3_112(T0, v_0, v_1, v_2) f_T3_120(T0, v_0, v_1, v_2) f_T3_121(T0, v_0, v_1, v_2) f_T3_122(T0, v_0, v_1, v_2) f_T3_200(T0, v_0, v_1, v_2) f_T3_201(T0, v_0, v_1, v_2) f_T3_202(T0, v_0, v_1, v_2) f_T3_210(T0, v_0, v_1, v_2) f_T3_211(T0, v_0, v_1, v_2) f_T3_212(T0, v_0, v_1, v_2) f_T3_220(T0, v_0, v_1, v_2) f_T3_221(T0, v_0, v_1, v_2) f_T3_222(T0, v_0, v_1, v_2) +DEAL:dim 3::Symbol function tensor (rank-4): f_T4_0000(T0, v_0, v_1, v_2) f_T4_0001(T0, v_0, v_1, v_2) f_T4_0002(T0, v_0, v_1, v_2) f_T4_0010(T0, v_0, v_1, v_2) f_T4_0011(T0, v_0, v_1, v_2) f_T4_0012(T0, v_0, v_1, v_2) f_T4_0020(T0, v_0, v_1, v_2) f_T4_0021(T0, v_0, v_1, v_2) f_T4_0022(T0, v_0, v_1, v_2) f_T4_0100(T0, v_0, v_1, v_2) f_T4_0101(T0, v_0, v_1, v_2) f_T4_0102(T0, v_0, v_1, v_2) f_T4_0110(T0, v_0, v_1, v_2) f_T4_0111(T0, v_0, v_1, v_2) f_T4_0112(T0, v_0, v_1, v_2) f_T4_0120(T0, v_0, v_1, v_2) f_T4_0121(T0, v_0, v_1, v_2) f_T4_0122(T0, v_0, v_1, v_2) f_T4_0200(T0, v_0, v_1, v_2) f_T4_0201(T0, v_0, v_1, v_2) f_T4_0202(T0, v_0, v_1, v_2) f_T4_0210(T0, v_0, v_1, v_2) f_T4_0211(T0, v_0, v_1, v_2) f_T4_0212(T0, v_0, v_1, v_2) f_T4_0220(T0, v_0, v_1, v_2) f_T4_0221(T0, v_0, v_1, v_2) f_T4_0222(T0, v_0, v_1, v_2) f_T4_1000(T0, v_0, v_1, v_2) f_T4_1001(T0, v_0, v_1, v_2) f_T4_1002(T0, v_0, v_1, v_2) f_T4_1010(T0, v_0, v_1, v_2) f_T4_1011(T0, v_0, v_1, v_2) f_T4_1012(T0, v_0, v_1, v_2) f_T4_1020(T0, v_0, v_1, v_2) f_T4_1021(T0, v_0, v_1, v_2) f_T4_1022(T0, v_0, v_1, v_2) f_T4_1100(T0, v_0, v_1, v_2) f_T4_1101(T0, v_0, v_1, v_2) f_T4_1102(T0, v_0, v_1, v_2) f_T4_1110(T0, v_0, v_1, v_2) f_T4_1111(T0, v_0, v_1, v_2) f_T4_1112(T0, v_0, v_1, v_2) f_T4_1120(T0, v_0, v_1, v_2) f_T4_1121(T0, v_0, v_1, v_2) f_T4_1122(T0, v_0, v_1, v_2) f_T4_1200(T0, v_0, v_1, v_2) f_T4_1201(T0, v_0, v_1, v_2) f_T4_1202(T0, v_0, v_1, v_2) f_T4_1210(T0, v_0, v_1, v_2) f_T4_1211(T0, v_0, v_1, v_2) f_T4_1212(T0, v_0, v_1, v_2) f_T4_1220(T0, v_0, v_1, v_2) f_T4_1221(T0, v_0, v_1, v_2) f_T4_1222(T0, v_0, v_1, v_2) f_T4_2000(T0, v_0, v_1, v_2) f_T4_2001(T0, v_0, v_1, v_2) f_T4_2002(T0, v_0, v_1, v_2) f_T4_2010(T0, v_0, v_1, v_2) f_T4_2011(T0, v_0, v_1, v_2) f_T4_2012(T0, v_0, v_1, v_2) f_T4_2020(T0, v_0, v_1, v_2) f_T4_2021(T0, v_0, v_1, v_2) f_T4_2022(T0, v_0, v_1, v_2) f_T4_2100(T0, v_0, v_1, v_2) f_T4_2101(T0, v_0, v_1, v_2) f_T4_2102(T0, v_0, v_1, v_2) f_T4_2110(T0, v_0, v_1, v_2) f_T4_2111(T0, v_0, v_1, v_2) f_T4_2112(T0, v_0, v_1, v_2) f_T4_2120(T0, v_0, v_1, v_2) f_T4_2121(T0, v_0, v_1, v_2) f_T4_2122(T0, v_0, v_1, v_2) f_T4_2200(T0, v_0, v_1, v_2) f_T4_2201(T0, v_0, v_1, v_2) f_T4_2202(T0, v_0, v_1, v_2) f_T4_2210(T0, v_0, v_1, v_2) f_T4_2211(T0, v_0, v_1, v_2) f_T4_2212(T0, v_0, v_1, v_2) f_T4_2220(T0, v_0, v_1, v_2) f_T4_2221(T0, v_0, v_1, v_2) f_T4_2222(T0, v_0, v_1, v_2) +DEAL:dim 3::Symbol function symmetric tensor (rank-2): f_ST2_00(T0, v_0, v_1, v_2) f_ST2_01(T0, v_0, v_1, v_2) f_ST2_02(T0, v_0, v_1, v_2) f_ST2_01(T0, v_0, v_1, v_2) f_ST2_11(T0, v_0, v_1, v_2) f_ST2_12(T0, v_0, v_1, v_2) f_ST2_02(T0, v_0, v_1, v_2) f_ST2_12(T0, v_0, v_1, v_2) f_ST2_22(T0, v_0, v_1, v_2) +DEAL:dim 3::Symbol function symmetric tensor (rank-4): f_ST4_0000(T0, v_0, v_1, v_2) f_ST4_0001(T0, v_0, v_1, v_2) f_ST4_0002(T0, v_0, v_1, v_2) f_ST4_0001(T0, v_0, v_1, v_2) f_ST4_0011(T0, v_0, v_1, v_2) f_ST4_0012(T0, v_0, v_1, v_2) f_ST4_0002(T0, v_0, v_1, v_2) f_ST4_0012(T0, v_0, v_1, v_2) f_ST4_0022(T0, v_0, v_1, v_2) f_ST4_0100(T0, v_0, v_1, v_2) f_ST4_0101(T0, v_0, v_1, v_2) f_ST4_0102(T0, v_0, v_1, v_2) f_ST4_0101(T0, v_0, v_1, v_2) f_ST4_0111(T0, v_0, v_1, v_2) f_ST4_0112(T0, v_0, v_1, v_2) f_ST4_0102(T0, v_0, v_1, v_2) f_ST4_0112(T0, v_0, v_1, v_2) f_ST4_0122(T0, v_0, v_1, v_2) f_ST4_0200(T0, v_0, v_1, v_2) f_ST4_0201(T0, v_0, v_1, v_2) f_ST4_0202(T0, v_0, v_1, v_2) f_ST4_0201(T0, v_0, v_1, v_2) f_ST4_0211(T0, v_0, v_1, v_2) f_ST4_0212(T0, v_0, v_1, v_2) f_ST4_0202(T0, v_0, v_1, v_2) f_ST4_0212(T0, v_0, v_1, v_2) f_ST4_0222(T0, v_0, v_1, v_2) f_ST4_0100(T0, v_0, v_1, v_2) f_ST4_0101(T0, v_0, v_1, v_2) f_ST4_0102(T0, v_0, v_1, v_2) f_ST4_0101(T0, v_0, v_1, v_2) f_ST4_0111(T0, v_0, v_1, v_2) f_ST4_0112(T0, v_0, v_1, v_2) f_ST4_0102(T0, v_0, v_1, v_2) f_ST4_0112(T0, v_0, v_1, v_2) f_ST4_0122(T0, v_0, v_1, v_2) f_ST4_1100(T0, v_0, v_1, v_2) f_ST4_1101(T0, v_0, v_1, v_2) f_ST4_1102(T0, v_0, v_1, v_2) f_ST4_1101(T0, v_0, v_1, v_2) f_ST4_1111(T0, v_0, v_1, v_2) f_ST4_1112(T0, v_0, v_1, v_2) f_ST4_1102(T0, v_0, v_1, v_2) f_ST4_1112(T0, v_0, v_1, v_2) f_ST4_1122(T0, v_0, v_1, v_2) f_ST4_1200(T0, v_0, v_1, v_2) f_ST4_1201(T0, v_0, v_1, v_2) f_ST4_1202(T0, v_0, v_1, v_2) f_ST4_1201(T0, v_0, v_1, v_2) f_ST4_1211(T0, v_0, v_1, v_2) f_ST4_1212(T0, v_0, v_1, v_2) f_ST4_1202(T0, v_0, v_1, v_2) f_ST4_1212(T0, v_0, v_1, v_2) f_ST4_1222(T0, v_0, v_1, v_2) f_ST4_0200(T0, v_0, v_1, v_2) f_ST4_0201(T0, v_0, v_1, v_2) f_ST4_0202(T0, v_0, v_1, v_2) f_ST4_0201(T0, v_0, v_1, v_2) f_ST4_0211(T0, v_0, v_1, v_2) f_ST4_0212(T0, v_0, v_1, v_2) f_ST4_0202(T0, v_0, v_1, v_2) f_ST4_0212(T0, v_0, v_1, v_2) f_ST4_0222(T0, v_0, v_1, v_2) f_ST4_1200(T0, v_0, v_1, v_2) f_ST4_1201(T0, v_0, v_1, v_2) f_ST4_1202(T0, v_0, v_1, v_2) f_ST4_1201(T0, v_0, v_1, v_2) f_ST4_1211(T0, v_0, v_1, v_2) f_ST4_1212(T0, v_0, v_1, v_2) f_ST4_1202(T0, v_0, v_1, v_2) f_ST4_1212(T0, v_0, v_1, v_2) f_ST4_1222(T0, v_0, v_1, v_2) f_ST4_2200(T0, v_0, v_1, v_2) f_ST4_2201(T0, v_0, v_1, v_2) f_ST4_2202(T0, v_0, v_1, v_2) f_ST4_2201(T0, v_0, v_1, v_2) f_ST4_2211(T0, v_0, v_1, v_2) f_ST4_2212(T0, v_0, v_1, v_2) f_ST4_2202(T0, v_0, v_1, v_2) f_ST4_2212(T0, v_0, v_1, v_2) f_ST4_2222(T0, v_0, v_1, v_2) +DEAL:dim 3::OK +DEAL::OK From 8ec9f0051b8a39428a10de13b9147374f1ea7861 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 18 Apr 2019 15:49:59 +0200 Subject: [PATCH 429/507] Add a test to check std::copy and std::swap with vector of Expressions --- tests/symengine/symengine_number_type_03.cc | 56 +++++++++++++++++++ .../symengine/symengine_number_type_03.output | 12 ++++ 2 files changed, 68 insertions(+) create mode 100644 tests/symengine/symengine_number_type_03.cc create mode 100644 tests/symengine/symengine_number_type_03.output diff --git a/tests/symengine/symengine_number_type_03.cc b/tests/symengine/symengine_number_type_03.cc new file mode 100644 index 000000000000..743745db2303 --- /dev/null +++ b/tests/symengine/symengine_number_type_03.cc @@ -0,0 +1,56 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Check that the wrapper for symengine expressions can be use with some +// of the algorithms defined in the standard namespace + +#include + +#include + +#include "../tests.h" + +using namespace dealii; +namespace SD = Differentiation::SD; + +int +main() +{ + initlog(); + + const SD::types::symbol_vector copy_from{SD::Expression(1), + SD::Expression(true), + SD::Expression(2.5), + SD::Expression("a")}; + SD::types::symbol_vector copy_to(copy_from.size()); + + // Mimics Tensor operator= + std::copy(copy_from.begin(), copy_from.end(), copy_to.begin()); + + deallog << "Copy" << std::endl; + for (unsigned int i = 0; i < copy_from.size(); ++i) + deallog << i << ": " << copy_from[i] << " -> " << copy_to[i] << std::endl; + + + SD::types::symbol_vector swap_to; + std::swap(copy_to, swap_to); + + deallog << "Swap" << std::endl; + for (unsigned int i = 0; i < swap_to.size(); ++i) + deallog << i << ": " << swap_to[i] << std::endl; + + deallog << "OK" << std::endl; +} diff --git a/tests/symengine/symengine_number_type_03.output b/tests/symengine/symengine_number_type_03.output new file mode 100644 index 000000000000..acf7106b08f3 --- /dev/null +++ b/tests/symengine/symengine_number_type_03.output @@ -0,0 +1,12 @@ + +DEAL::Copy +DEAL::0: 1 -> 1 +DEAL::1: True -> True +DEAL::2: 2.5 -> 2.5 +DEAL::3: a -> a +DEAL::Swap +DEAL::0: 1 +DEAL::1: True +DEAL::2: 2.5 +DEAL::3: a +DEAL::OK From f6e60230dcc3a6cca62746a38f3c421db7db1345 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Thu, 18 Apr 2019 21:37:26 +0200 Subject: [PATCH 430/507] Add test for operations using symbolic and expressional tensors --- .../symengine_tensor_operations_02.cc | 219 +++++++++++++++ .../symengine_tensor_operations_02.output | 253 ++++++++++++++++++ 2 files changed, 472 insertions(+) create mode 100644 tests/symengine/symengine_tensor_operations_02.cc create mode 100644 tests/symengine/symengine_tensor_operations_02.output diff --git a/tests/symengine/symengine_tensor_operations_02.cc b/tests/symengine/symengine_tensor_operations_02.cc new file mode 100644 index 000000000000..c9e075a8a16d --- /dev/null +++ b/tests/symengine/symengine_tensor_operations_02.cc @@ -0,0 +1,219 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + + +// Check that some of the common tensor operations can be performed with +// tensors of expressions + +#include + +#include + +#include "../tests.h" + +using namespace dealii; +namespace SD = Differentiation::SD; + +template +Tensor<2, dim, NumberType> +make_tensor(const NumberType &val) +{ + Tensor<2, dim, NumberType> out; + for (unsigned int i = 0; i < out.n_independent_components; ++i) + out[out.unrolled_to_component_indices(i)] = NumberType(i) + val; + return out; +} + +template +SymmetricTensor<2, dim, NumberType> +make_symm_tensor(const NumberType &val) +{ + SymmetricTensor<2, dim, NumberType> out; + for (unsigned int i = 0; i < out.n_independent_components; ++i) + out[out.unrolled_to_component_indices(i)] = NumberType(i) + val; + return out; +} + +template +void +test_tensor() +{ + typedef SD::Expression SD_number_t; + typedef Tensor<2, dim, SD_number_t> SD_tensor_t; + typedef SymmetricTensor<2, dim, SD_number_t> SD_symm_tensor_t; + + // --- Values --- + deallog.push("Initialize"); + SD_tensor_t a(make_tensor(NumberType(10))); + SD_tensor_t b(make_tensor(NumberType(10))); + SD_symm_tensor_t as(make_symm_tensor(NumberType(10))); + SD_symm_tensor_t bs(make_symm_tensor(NumberType(10))); + deallog << "a: " << a << std::endl; + deallog << "b: " << b << std::endl; + deallog << "as: " << as << std::endl; + deallog << "bs: " << bs << std::endl; + deallog.pop(); + + deallog.push("Relational operators 1"); + deallog << "a == b: " << (a == b) << std::endl; + deallog << "a != b: " << (a != b) << std::endl; + if (numbers::NumberTraits::is_complex == false) + deallog << "a.norm() < b.norm(): " << (a.norm() < b.norm()) << std::endl; + deallog.pop(); + + deallog.push("Set new values"); + a = make_tensor(NumberType(5)); + b = make_tensor(NumberType(9)); + as = make_symm_tensor(NumberType(5)); + bs = make_symm_tensor(NumberType(7)); + deallog << "a: " << a << std::endl; + deallog << "b: " << b << std::endl; + deallog << "as: " << as << std::endl; + deallog << "bs: " << bs << std::endl; + deallog.pop(); + // + deallog.push("Relational operators 2"); + deallog << "a == b: " << (a == b) << std::endl; + deallog << "a != b: " << (a != b) << std::endl; + if (numbers::NumberTraits::is_complex == false) + deallog << "a.norm() < b.norm(): " << (a.norm() < b.norm()) << std::endl; + deallog.pop(); + + deallog.push("Math operators"); + deallog.push("Tensor"); + deallog << "a+b: " << (a + b) << std::endl; + deallog << "a-b: " << (a - b) << std::endl; + deallog << "a*b: " << (a * b) << std::endl; + deallog.pop(); + deallog.push("SymmetricTensor"); + deallog << "as+bs: " << (as + bs) << std::endl; + deallog << "as-bs: " << (as - bs) << std::endl; + deallog << "as*bs: " << (as * bs) << std::endl; + const SD_tensor_t as_ns = as; + deallog << "as: " << as << std::endl; + deallog << "as_ns: " << as_ns << std::endl; + const SD_tensor_t as_ns2(as); + deallog << "as+b: " << (as + b) << std::endl; + deallog << "as-b: " << (as - b) << std::endl; + deallog << "as*b: " << (static_cast(as) * b) << std::endl; + deallog.pop(); + deallog.pop(); + + // --- Normal numbers --- + deallog.push("Copy constructor"); + SD_tensor_t c(a); // Copy constructor + SD_symm_tensor_t cs(as); // Copy constructor + deallog << "c: " << c << std::endl; + deallog << "cs: " << cs << std::endl; + deallog.pop(); + + deallog.push("Math operators"); // including those with arithmetic numbers + const NumberType s(2); + deallog.push("Tensor"); + c += b; + deallog << "c+=b: " << c << std::endl; + c *= s; + deallog << "c*=s: " << c << std::endl; + c -= b; + deallog << "c-=b: " << c << std::endl; + c /= s; + deallog << "c/=s: " << c << std::endl; + deallog.pop(); + deallog.push("SymmetricTensor"); + cs += bs; + deallog << "cs+=bs: " << cs << std::endl; + cs *= s; + deallog << "cs*=s: " << cs << std::endl; + cs -= bs; + deallog << "cs-=bs: " << cs << std::endl; + cs /= s; + deallog << "cs/=s: " << cs << std::endl; + deallog.pop(); + deallog.pop(); + + // --- Symbols --- + deallog.push("Symbols"); + const SD_number_t y("y"); + const SD_tensor_t x(SD::make_tensor_of_symbols<2, dim>("x")); + const SD_symm_tensor_t z(SD::make_symmetric_tensor_of_symbols<2, dim>("z")); + deallog << "x: " << x << std::endl; + deallog << "y: " << y << std::endl; + deallog << "z: " << z << std::endl; + deallog.pop(); + + deallog.push("Math operators"); // including those with arithmetic numbers + deallog.push("Tensor"); + c += x; + deallog << "c+=x: " << c << std::endl; + c *= y; + deallog << "c*=y: " << c << std::endl; + c *= s; + deallog << "c*=s: " << c << std::endl; + c -= x; + deallog << "c-=x: " << c << std::endl; + c /= y; + deallog << "c/=y: " << c << std::endl; + c /= s; + deallog << "c/=s: " << c << std::endl; + deallog.pop(); + deallog.push("SymmetricTensor"); + cs += z; + deallog << "cs+=z: " << cs << std::endl; + cs *= y; + deallog << "cs*=y: " << cs << std::endl; + cs *= s; + deallog << "cs*=s: " << cs << std::endl; + cs -= z; + deallog << "cs-=z: " << cs << std::endl; + cs /= y; + deallog << "cs/=y: " << cs << std::endl; + cs /= s; + deallog << "cs/=s: " << cs << std::endl; + deallog.pop(); + deallog.pop(); + + deallog << "OK" << std::endl; +} + + +int +main() +{ + initlog(); + + const int dim = 2; + + deallog.push("Integer"); + test_tensor(); + deallog.pop(); + + deallog.push("Float"); + test_tensor(); + deallog.pop(); + + deallog.push("Double"); + test_tensor(); + deallog.pop(); + + deallog.push("Complex float"); + test_tensor>(); + deallog.pop(); + + deallog.push("Complex double"); + test_tensor>(); + deallog.pop(); + + deallog << "OK" << std::endl; +} diff --git a/tests/symengine/symengine_tensor_operations_02.output b/tests/symengine/symengine_tensor_operations_02.output new file mode 100644 index 000000000000..03cfc71826c6 --- /dev/null +++ b/tests/symengine/symengine_tensor_operations_02.output @@ -0,0 +1,253 @@ + +DEAL:Integer:Initialize::a: 10 11 12 13 +DEAL:Integer:Initialize::b: 10 11 12 13 +DEAL:Integer:Initialize::as: 10 12 12 11 +DEAL:Integer:Initialize::bs: 10 12 12 11 +DEAL:Integer:Relational operators 1::a == b: 1 +DEAL:Integer:Relational operators 1::a != b: 0 +DEAL:Integer:Relational operators 1::a.norm() < b.norm(): False +DEAL:Integer:Set new values::a: 5 6 7 8 +DEAL:Integer:Set new values::b: 9 10 11 12 +DEAL:Integer:Set new values::as: 5 7 7 6 +DEAL:Integer:Set new values::bs: 7 9 9 8 +DEAL:Integer:Relational operators 2::a == b: 0 +DEAL:Integer:Relational operators 2::a != b: 1 +DEAL:Integer:Relational operators 2::a.norm() < b.norm(): sqrt(174) < sqrt(446) +DEAL:Integer:Math operators:Tensor::a+b: 14 16 18 20 +DEAL:Integer:Math operators:Tensor::a-b: -4 -4 -4 -4 +DEAL:Integer:Math operators:Tensor::a*b: 111 122 151 166 +DEAL:Integer:Math operators:SymmetricTensor::as+bs: 12 16 16 14 +DEAL:Integer:Math operators:SymmetricTensor::as-bs: -2 -2 -2 -2 +DEAL:Integer:Math operators:SymmetricTensor::as*bs: 209 +DEAL:Integer:Math operators:SymmetricTensor::as: 5 7 7 6 +DEAL:Integer:Math operators:SymmetricTensor::as_ns: 5 7 7 6 +DEAL:Integer:Math operators:SymmetricTensor::as+b: 14 17 18 18 +DEAL:Integer:Math operators:SymmetricTensor::as-b: -4 -3 -4 -6 +DEAL:Integer:Math operators:SymmetricTensor::as*b: 122 134 129 142 +DEAL:Integer:Copy constructor::c: 5 6 7 8 +DEAL:Integer:Copy constructor::cs: 5 7 7 6 +DEAL:Integer:Math operators:Tensor::c+=b: 14 16 18 20 +DEAL:Integer:Math operators:Tensor::c*=s: 28 32 36 40 +DEAL:Integer:Math operators:Tensor::c-=b: 19 22 25 28 +DEAL:Integer:Math operators:Tensor::c/=s: 19/2 11 25/2 14 +DEAL:Integer:Math operators:SymmetricTensor::cs+=bs: 12 16 16 14 +DEAL:Integer:Math operators:SymmetricTensor::cs*=s: 24 32 32 28 +DEAL:Integer:Math operators:SymmetricTensor::cs-=bs: 17 23 23 20 +DEAL:Integer:Math operators:SymmetricTensor::cs/=s: 17/2 23/2 23/2 10 +DEAL:Integer:Symbols::x: x_00 x_01 x_10 x_11 +DEAL:Integer:Symbols::y: y +DEAL:Integer:Symbols::z: z_00 z_01 z_01 z_11 +DEAL:Integer:Math operators:Tensor::c+=x: 19/2 + x_00 11 + x_01 25/2 + x_10 14 + x_11 +DEAL:Integer:Math operators:Tensor::c*=y: y*(19/2 + x_00) y*(11 + x_01) y*(25/2 + x_10) y*(14 + x_11) +DEAL:Integer:Math operators:Tensor::c*=s: 2*y*(19/2 + x_00) 2*y*(11 + x_01) 2*y*(25/2 + x_10) 2*y*(14 + x_11) +DEAL:Integer:Math operators:Tensor::c-=x: -x_00 + 2*y*(19/2 + x_00) -x_01 + 2*y*(11 + x_01) -x_10 + 2*y*(25/2 + x_10) -x_11 + 2*y*(14 + x_11) +DEAL:Integer:Math operators:Tensor::c/=y: (-x_00 + 2*y*(19/2 + x_00))/y (-x_01 + 2*y*(11 + x_01))/y (-x_10 + 2*y*(25/2 + x_10))/y (-x_11 + 2*y*(14 + x_11))/y +DEAL:Integer:Math operators:Tensor::c/=s: (1/2)*(-x_00 + 2*y*(19/2 + x_00))/y (1/2)*(-x_01 + 2*y*(11 + x_01))/y (1/2)*(-x_10 + 2*y*(25/2 + x_10))/y (1/2)*(-x_11 + 2*y*(14 + x_11))/y +DEAL:Integer:Math operators:SymmetricTensor::cs+=z: 17/2 + z_00 23/2 + z_01 23/2 + z_01 10 + z_11 +DEAL:Integer:Math operators:SymmetricTensor::cs*=y: y*(17/2 + z_00) y*(23/2 + z_01) y*(23/2 + z_01) y*(10 + z_11) +DEAL:Integer:Math operators:SymmetricTensor::cs*=s: 2*y*(17/2 + z_00) 2*y*(23/2 + z_01) 2*y*(23/2 + z_01) 2*y*(10 + z_11) +DEAL:Integer:Math operators:SymmetricTensor::cs-=z: -z_00 + 2*y*(17/2 + z_00) -z_01 + 2*y*(23/2 + z_01) -z_01 + 2*y*(23/2 + z_01) -z_11 + 2*y*(10 + z_11) +DEAL:Integer:Math operators:SymmetricTensor::cs/=y: (-z_00 + 2*y*(17/2 + z_00))/y (-z_01 + 2*y*(23/2 + z_01))/y (-z_01 + 2*y*(23/2 + z_01))/y (-z_11 + 2*y*(10 + z_11))/y +DEAL:Integer:Math operators:SymmetricTensor::cs/=s: (1/2)*(-z_00 + 2*y*(17/2 + z_00))/y (1/2)*(-z_01 + 2*y*(23/2 + z_01))/y (1/2)*(-z_01 + 2*y*(23/2 + z_01))/y (1/2)*(-z_11 + 2*y*(10 + z_11))/y +DEAL:Integer::OK +DEAL:Float:Initialize::a: 10.0 11.0 12.0 13.0 +DEAL:Float:Initialize::b: 10.0 11.0 12.0 13.0 +DEAL:Float:Initialize::as: 10.0 12.0 12.0 11.0 +DEAL:Float:Initialize::bs: 10.0 12.0 12.0 11.0 +DEAL:Float:Relational operators 1::a == b: 1 +DEAL:Float:Relational operators 1::a != b: 0 +DEAL:Float:Relational operators 1::a.norm() < b.norm(): False +DEAL:Float:Set new values::a: 5.0 6.0 7.0 8.0 +DEAL:Float:Set new values::b: 9.0 10.0 11.0 12.0 +DEAL:Float:Set new values::as: 5.0 7.0 7.0 6.0 +DEAL:Float:Set new values::bs: 7.0 9.0 9.0 8.0 +DEAL:Float:Relational operators 2::a == b: 0 +DEAL:Float:Relational operators 2::a != b: 1 +DEAL:Float:Relational operators 2::a.norm() < b.norm(): True +DEAL:Float:Math operators:Tensor::a+b: 14.0 16.0 18.0 20.0 +DEAL:Float:Math operators:Tensor::a-b: -4.0 -4.0 -4.0 -4.0 +DEAL:Float:Math operators:Tensor::a*b: 111.0 122.0 151.0 166.0 +DEAL:Float:Math operators:SymmetricTensor::as+bs: 12.0 16.0 16.0 14.0 +DEAL:Float:Math operators:SymmetricTensor::as-bs: -2.0 -2.0 -2.0 -2.0 +DEAL:Float:Math operators:SymmetricTensor::as*bs: 209.0 +DEAL:Float:Math operators:SymmetricTensor::as: 5.0 7.0 7.0 6.0 +DEAL:Float:Math operators:SymmetricTensor::as_ns: 5.0 7.0 7.0 6.0 +DEAL:Float:Math operators:SymmetricTensor::as+b: 14.0 17.0 18.0 18.0 +DEAL:Float:Math operators:SymmetricTensor::as-b: -4.0 -3.0 -4.0 -6.0 +DEAL:Float:Math operators:SymmetricTensor::as*b: 122.0 134.0 129.0 142.0 +DEAL:Float:Copy constructor::c: 5.0 6.0 7.0 8.0 +DEAL:Float:Copy constructor::cs: 5.0 7.0 7.0 6.0 +DEAL:Float:Math operators:Tensor::c+=b: 14.0 16.0 18.0 20.0 +DEAL:Float:Math operators:Tensor::c*=s: 28.0 32.0 36.0 40.0 +DEAL:Float:Math operators:Tensor::c-=b: 19.0 22.0 25.0 28.0 +DEAL:Float:Math operators:Tensor::c/=s: 9.5 11.0 12.5 14.0 +DEAL:Float:Math operators:SymmetricTensor::cs+=bs: 12.0 16.0 16.0 14.0 +DEAL:Float:Math operators:SymmetricTensor::cs*=s: 24.0 32.0 32.0 28.0 +DEAL:Float:Math operators:SymmetricTensor::cs-=bs: 17.0 23.0 23.0 20.0 +DEAL:Float:Math operators:SymmetricTensor::cs/=s: 8.5 11.5 11.5 10.0 +DEAL:Float:Symbols::x: x_00 x_01 x_10 x_11 +DEAL:Float:Symbols::y: y +DEAL:Float:Symbols::z: z_00 z_01 z_01 z_11 +DEAL:Float:Math operators:Tensor::c+=x: 9.5 + x_00 11.0 + x_01 12.5 + x_10 14.0 + x_11 +DEAL:Float:Math operators:Tensor::c*=y: y*(9.5 + x_00) y*(11.0 + x_01) y*(12.5 + x_10) y*(14.0 + x_11) +DEAL:Float:Math operators:Tensor::c*=s: 2.0*y*(9.5 + x_00) 2.0*y*(11.0 + x_01) 2.0*y*(12.5 + x_10) 2.0*y*(14.0 + x_11) +DEAL:Float:Math operators:Tensor::c-=x: -x_00 + 2.0*y*(9.5 + x_00) -x_01 + 2.0*y*(11.0 + x_01) -x_10 + 2.0*y*(12.5 + x_10) -x_11 + 2.0*y*(14.0 + x_11) +DEAL:Float:Math operators:Tensor::c/=y: (-x_00 + 2.0*y*(9.5 + x_00))/y (-x_01 + 2.0*y*(11.0 + x_01))/y (-x_10 + 2.0*y*(12.5 + x_10))/y (-x_11 + 2.0*y*(14.0 + x_11))/y +DEAL:Float:Math operators:Tensor::c/=s: 0.5*(-x_00 + 2.0*y*(9.5 + x_00))/y 0.5*(-x_01 + 2.0*y*(11.0 + x_01))/y 0.5*(-x_10 + 2.0*y*(12.5 + x_10))/y 0.5*(-x_11 + 2.0*y*(14.0 + x_11))/y +DEAL:Float:Math operators:SymmetricTensor::cs+=z: 8.5 + z_00 11.5 + z_01 11.5 + z_01 10.0 + z_11 +DEAL:Float:Math operators:SymmetricTensor::cs*=y: y*(8.5 + z_00) y*(11.5 + z_01) y*(11.5 + z_01) y*(10.0 + z_11) +DEAL:Float:Math operators:SymmetricTensor::cs*=s: 2.0*y*(8.5 + z_00) 2.0*y*(11.5 + z_01) 2.0*y*(11.5 + z_01) 2.0*y*(10.0 + z_11) +DEAL:Float:Math operators:SymmetricTensor::cs-=z: -z_00 + 2.0*y*(8.5 + z_00) -z_01 + 2.0*y*(11.5 + z_01) -z_01 + 2.0*y*(11.5 + z_01) -z_11 + 2.0*y*(10.0 + z_11) +DEAL:Float:Math operators:SymmetricTensor::cs/=y: (-z_00 + 2.0*y*(8.5 + z_00))/y (-z_01 + 2.0*y*(11.5 + z_01))/y (-z_01 + 2.0*y*(11.5 + z_01))/y (-z_11 + 2.0*y*(10.0 + z_11))/y +DEAL:Float:Math operators:SymmetricTensor::cs/=s: 0.5*(-z_00 + 2.0*y*(8.5 + z_00))/y 0.5*(-z_01 + 2.0*y*(11.5 + z_01))/y 0.5*(-z_01 + 2.0*y*(11.5 + z_01))/y 0.5*(-z_11 + 2.0*y*(10.0 + z_11))/y +DEAL:Float::OK +DEAL:Double:Initialize::a: 10.0 11.0 12.0 13.0 +DEAL:Double:Initialize::b: 10.0 11.0 12.0 13.0 +DEAL:Double:Initialize::as: 10.0 12.0 12.0 11.0 +DEAL:Double:Initialize::bs: 10.0 12.0 12.0 11.0 +DEAL:Double:Relational operators 1::a == b: 1 +DEAL:Double:Relational operators 1::a != b: 0 +DEAL:Double:Relational operators 1::a.norm() < b.norm(): False +DEAL:Double:Set new values::a: 5.0 6.0 7.0 8.0 +DEAL:Double:Set new values::b: 9.0 10.0 11.0 12.0 +DEAL:Double:Set new values::as: 5.0 7.0 7.0 6.0 +DEAL:Double:Set new values::bs: 7.0 9.0 9.0 8.0 +DEAL:Double:Relational operators 2::a == b: 0 +DEAL:Double:Relational operators 2::a != b: 1 +DEAL:Double:Relational operators 2::a.norm() < b.norm(): True +DEAL:Double:Math operators:Tensor::a+b: 14.0 16.0 18.0 20.0 +DEAL:Double:Math operators:Tensor::a-b: -4.0 -4.0 -4.0 -4.0 +DEAL:Double:Math operators:Tensor::a*b: 111.0 122.0 151.0 166.0 +DEAL:Double:Math operators:SymmetricTensor::as+bs: 12.0 16.0 16.0 14.0 +DEAL:Double:Math operators:SymmetricTensor::as-bs: -2.0 -2.0 -2.0 -2.0 +DEAL:Double:Math operators:SymmetricTensor::as*bs: 209.0 +DEAL:Double:Math operators:SymmetricTensor::as: 5.0 7.0 7.0 6.0 +DEAL:Double:Math operators:SymmetricTensor::as_ns: 5.0 7.0 7.0 6.0 +DEAL:Double:Math operators:SymmetricTensor::as+b: 14.0 17.0 18.0 18.0 +DEAL:Double:Math operators:SymmetricTensor::as-b: -4.0 -3.0 -4.0 -6.0 +DEAL:Double:Math operators:SymmetricTensor::as*b: 122.0 134.0 129.0 142.0 +DEAL:Double:Copy constructor::c: 5.0 6.0 7.0 8.0 +DEAL:Double:Copy constructor::cs: 5.0 7.0 7.0 6.0 +DEAL:Double:Math operators:Tensor::c+=b: 14.0 16.0 18.0 20.0 +DEAL:Double:Math operators:Tensor::c*=s: 28.0 32.0 36.0 40.0 +DEAL:Double:Math operators:Tensor::c-=b: 19.0 22.0 25.0 28.0 +DEAL:Double:Math operators:Tensor::c/=s: 9.5 11.0 12.5 14.0 +DEAL:Double:Math operators:SymmetricTensor::cs+=bs: 12.0 16.0 16.0 14.0 +DEAL:Double:Math operators:SymmetricTensor::cs*=s: 24.0 32.0 32.0 28.0 +DEAL:Double:Math operators:SymmetricTensor::cs-=bs: 17.0 23.0 23.0 20.0 +DEAL:Double:Math operators:SymmetricTensor::cs/=s: 8.5 11.5 11.5 10.0 +DEAL:Double:Symbols::x: x_00 x_01 x_10 x_11 +DEAL:Double:Symbols::y: y +DEAL:Double:Symbols::z: z_00 z_01 z_01 z_11 +DEAL:Double:Math operators:Tensor::c+=x: 9.5 + x_00 11.0 + x_01 12.5 + x_10 14.0 + x_11 +DEAL:Double:Math operators:Tensor::c*=y: y*(9.5 + x_00) y*(11.0 + x_01) y*(12.5 + x_10) y*(14.0 + x_11) +DEAL:Double:Math operators:Tensor::c*=s: 2.0*y*(9.5 + x_00) 2.0*y*(11.0 + x_01) 2.0*y*(12.5 + x_10) 2.0*y*(14.0 + x_11) +DEAL:Double:Math operators:Tensor::c-=x: -x_00 + 2.0*y*(9.5 + x_00) -x_01 + 2.0*y*(11.0 + x_01) -x_10 + 2.0*y*(12.5 + x_10) -x_11 + 2.0*y*(14.0 + x_11) +DEAL:Double:Math operators:Tensor::c/=y: (-x_00 + 2.0*y*(9.5 + x_00))/y (-x_01 + 2.0*y*(11.0 + x_01))/y (-x_10 + 2.0*y*(12.5 + x_10))/y (-x_11 + 2.0*y*(14.0 + x_11))/y +DEAL:Double:Math operators:Tensor::c/=s: 0.5*(-x_00 + 2.0*y*(9.5 + x_00))/y 0.5*(-x_01 + 2.0*y*(11.0 + x_01))/y 0.5*(-x_10 + 2.0*y*(12.5 + x_10))/y 0.5*(-x_11 + 2.0*y*(14.0 + x_11))/y +DEAL:Double:Math operators:SymmetricTensor::cs+=z: 8.5 + z_00 11.5 + z_01 11.5 + z_01 10.0 + z_11 +DEAL:Double:Math operators:SymmetricTensor::cs*=y: y*(8.5 + z_00) y*(11.5 + z_01) y*(11.5 + z_01) y*(10.0 + z_11) +DEAL:Double:Math operators:SymmetricTensor::cs*=s: 2.0*y*(8.5 + z_00) 2.0*y*(11.5 + z_01) 2.0*y*(11.5 + z_01) 2.0*y*(10.0 + z_11) +DEAL:Double:Math operators:SymmetricTensor::cs-=z: -z_00 + 2.0*y*(8.5 + z_00) -z_01 + 2.0*y*(11.5 + z_01) -z_01 + 2.0*y*(11.5 + z_01) -z_11 + 2.0*y*(10.0 + z_11) +DEAL:Double:Math operators:SymmetricTensor::cs/=y: (-z_00 + 2.0*y*(8.5 + z_00))/y (-z_01 + 2.0*y*(11.5 + z_01))/y (-z_01 + 2.0*y*(11.5 + z_01))/y (-z_11 + 2.0*y*(10.0 + z_11))/y +DEAL:Double:Math operators:SymmetricTensor::cs/=s: 0.5*(-z_00 + 2.0*y*(8.5 + z_00))/y 0.5*(-z_01 + 2.0*y*(11.5 + z_01))/y 0.5*(-z_01 + 2.0*y*(11.5 + z_01))/y 0.5*(-z_11 + 2.0*y*(10.0 + z_11))/y +DEAL:Double::OK +DEAL:Complex float:Initialize::a: 10.0 + 0.0*I 11.0 + 0.0*I 12.0 + 0.0*I 13.0 + 0.0*I +DEAL:Complex float:Initialize::b: 10.0 + 0.0*I 11.0 + 0.0*I 12.0 + 0.0*I 13.0 + 0.0*I +DEAL:Complex float:Initialize::as: 10.0 + 0.0*I 12.0 + 0.0*I 12.0 + 0.0*I 11.0 + 0.0*I +DEAL:Complex float:Initialize::bs: 10.0 + 0.0*I 12.0 + 0.0*I 12.0 + 0.0*I 11.0 + 0.0*I +DEAL:Complex float:Relational operators 1::a == b: 1 +DEAL:Complex float:Relational operators 1::a != b: 0 +DEAL:Complex float:Set new values::a: 5.0 + 0.0*I 6.0 + 0.0*I 7.0 + 0.0*I 8.0 + 0.0*I +DEAL:Complex float:Set new values::b: 9.0 + 0.0*I 10.0 + 0.0*I 11.0 + 0.0*I 12.0 + 0.0*I +DEAL:Complex float:Set new values::as: 5.0 + 0.0*I 7.0 + 0.0*I 7.0 + 0.0*I 6.0 + 0.0*I +DEAL:Complex float:Set new values::bs: 7.0 + 0.0*I 9.0 + 0.0*I 9.0 + 0.0*I 8.0 + 0.0*I +DEAL:Complex float:Relational operators 2::a == b: 0 +DEAL:Complex float:Relational operators 2::a != b: 1 +DEAL:Complex float:Math operators:Tensor::a+b: 14.0 + 0.0*I 16.0 + 0.0*I 18.0 + 0.0*I 20.0 + 0.0*I +DEAL:Complex float:Math operators:Tensor::a-b: -4.0 + 0.0*I -4.0 + 0.0*I -4.0 + 0.0*I -4.0 + 0.0*I +DEAL:Complex float:Math operators:Tensor::a*b: 111.0 + 0.0*I 122.0 + 0.0*I 151.0 + 0.0*I 166.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::as+bs: 12.0 + 0.0*I 16.0 + 0.0*I 16.0 + 0.0*I 14.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::as-bs: -2.0 + 0.0*I -2.0 + 0.0*I -2.0 + 0.0*I -2.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::as*bs: 209.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::as: 5.0 + 0.0*I 7.0 + 0.0*I 7.0 + 0.0*I 6.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::as_ns: 5.0 + 0.0*I 7.0 + 0.0*I 7.0 + 0.0*I 6.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::as+b: 14.0 + 0.0*I 17.0 + 0.0*I 18.0 + 0.0*I 18.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::as-b: -4.0 + 0.0*I -3.0 + 0.0*I -4.0 + 0.0*I -6.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::as*b: 122.0 + 0.0*I 134.0 + 0.0*I 129.0 + 0.0*I 142.0 + 0.0*I +DEAL:Complex float:Copy constructor::c: 5.0 + 0.0*I 6.0 + 0.0*I 7.0 + 0.0*I 8.0 + 0.0*I +DEAL:Complex float:Copy constructor::cs: 5.0 + 0.0*I 7.0 + 0.0*I 7.0 + 0.0*I 6.0 + 0.0*I +DEAL:Complex float:Math operators:Tensor::c+=b: 14.0 + 0.0*I 16.0 + 0.0*I 18.0 + 0.0*I 20.0 + 0.0*I +DEAL:Complex float:Math operators:Tensor::c*=s: 28.0 + 0.0*I 32.0 + 0.0*I 36.0 + 0.0*I 40.0 + 0.0*I +DEAL:Complex float:Math operators:Tensor::c-=b: 19.0 + 0.0*I 22.0 + 0.0*I 25.0 + 0.0*I 28.0 + 0.0*I +DEAL:Complex float:Math operators:Tensor::c/=s: 9.5 + 0.0*I 11.0 + 0.0*I 12.5 + 0.0*I 14.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::cs+=bs: 12.0 + 0.0*I 16.0 + 0.0*I 16.0 + 0.0*I 14.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::cs*=s: 24.0 + 0.0*I 32.0 + 0.0*I 32.0 + 0.0*I 28.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::cs-=bs: 17.0 + 0.0*I 23.0 + 0.0*I 23.0 + 0.0*I 20.0 + 0.0*I +DEAL:Complex float:Math operators:SymmetricTensor::cs/=s: 8.5 + 0.0*I 11.5 + 0.0*I 11.5 + 0.0*I 10.0 + 0.0*I +DEAL:Complex float:Symbols::x: x_00 x_01 x_10 x_11 +DEAL:Complex float:Symbols::y: y +DEAL:Complex float:Symbols::z: z_00 z_01 z_01 z_11 +DEAL:Complex float:Math operators:Tensor::c+=x: 9.5 + 0.0*I + x_00 11.0 + 0.0*I + x_01 12.5 + 0.0*I + x_10 14.0 + 0.0*I + x_11 +DEAL:Complex float:Math operators:Tensor::c*=y: y*(9.5 + 0.0*I + x_00) y*(11.0 + 0.0*I + x_01) y*(12.5 + 0.0*I + x_10) y*(14.0 + 0.0*I + x_11) +DEAL:Complex float:Math operators:Tensor::c*=s: (2.0 + 0.0*I)*y*(9.5 + 0.0*I + x_00) (2.0 + 0.0*I)*y*(11.0 + 0.0*I + x_01) (2.0 + 0.0*I)*y*(12.5 + 0.0*I + x_10) (2.0 + 0.0*I)*y*(14.0 + 0.0*I + x_11) +DEAL:Complex float:Math operators:Tensor::c-=x: -x_00 + (2.0 + 0.0*I)*y*(9.5 + 0.0*I + x_00) -x_01 + (2.0 + 0.0*I)*y*(11.0 + 0.0*I + x_01) -x_10 + (2.0 + 0.0*I)*y*(12.5 + 0.0*I + x_10) -x_11 + (2.0 + 0.0*I)*y*(14.0 + 0.0*I + x_11) +DEAL:Complex float:Math operators:Tensor::c/=y: (-x_00 + (2.0 + 0.0*I)*y*(9.5 + 0.0*I + x_00))/y (-x_01 + (2.0 + 0.0*I)*y*(11.0 + 0.0*I + x_01))/y (-x_10 + (2.0 + 0.0*I)*y*(12.5 + 0.0*I + x_10))/y (-x_11 + (2.0 + 0.0*I)*y*(14.0 + 0.0*I + x_11))/y +DEAL:Complex float:Math operators:Tensor::c/=s: (0.5 + 0.0*I)*(-x_00 + (2.0 + 0.0*I)*y*(9.5 + 0.0*I + x_00))/y (0.5 + 0.0*I)*(-x_01 + (2.0 + 0.0*I)*y*(11.0 + 0.0*I + x_01))/y (0.5 + 0.0*I)*(-x_10 + (2.0 + 0.0*I)*y*(12.5 + 0.0*I + x_10))/y (0.5 + 0.0*I)*(-x_11 + (2.0 + 0.0*I)*y*(14.0 + 0.0*I + x_11))/y +DEAL:Complex float:Math operators:SymmetricTensor::cs+=z: 8.5 + 0.0*I + z_00 11.5 + 0.0*I + z_01 11.5 + 0.0*I + z_01 10.0 + 0.0*I + z_11 +DEAL:Complex float:Math operators:SymmetricTensor::cs*=y: y*(8.5 + 0.0*I + z_00) y*(11.5 + 0.0*I + z_01) y*(11.5 + 0.0*I + z_01) y*(10.0 + 0.0*I + z_11) +DEAL:Complex float:Math operators:SymmetricTensor::cs*=s: (2.0 + 0.0*I)*y*(8.5 + 0.0*I + z_00) (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01) (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01) (2.0 + 0.0*I)*y*(10.0 + 0.0*I + z_11) +DEAL:Complex float:Math operators:SymmetricTensor::cs-=z: -z_00 + (2.0 + 0.0*I)*y*(8.5 + 0.0*I + z_00) -z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01) -z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01) -z_11 + (2.0 + 0.0*I)*y*(10.0 + 0.0*I + z_11) +DEAL:Complex float:Math operators:SymmetricTensor::cs/=y: (-z_00 + (2.0 + 0.0*I)*y*(8.5 + 0.0*I + z_00))/y (-z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01))/y (-z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01))/y (-z_11 + (2.0 + 0.0*I)*y*(10.0 + 0.0*I + z_11))/y +DEAL:Complex float:Math operators:SymmetricTensor::cs/=s: (0.5 + 0.0*I)*(-z_00 + (2.0 + 0.0*I)*y*(8.5 + 0.0*I + z_00))/y (0.5 + 0.0*I)*(-z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01))/y (0.5 + 0.0*I)*(-z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01))/y (0.5 + 0.0*I)*(-z_11 + (2.0 + 0.0*I)*y*(10.0 + 0.0*I + z_11))/y +DEAL:Complex float::OK +DEAL:Complex double:Initialize::a: 10.0 + 0.0*I 11.0 + 0.0*I 12.0 + 0.0*I 13.0 + 0.0*I +DEAL:Complex double:Initialize::b: 10.0 + 0.0*I 11.0 + 0.0*I 12.0 + 0.0*I 13.0 + 0.0*I +DEAL:Complex double:Initialize::as: 10.0 + 0.0*I 12.0 + 0.0*I 12.0 + 0.0*I 11.0 + 0.0*I +DEAL:Complex double:Initialize::bs: 10.0 + 0.0*I 12.0 + 0.0*I 12.0 + 0.0*I 11.0 + 0.0*I +DEAL:Complex double:Relational operators 1::a == b: 1 +DEAL:Complex double:Relational operators 1::a != b: 0 +DEAL:Complex double:Set new values::a: 5.0 + 0.0*I 6.0 + 0.0*I 7.0 + 0.0*I 8.0 + 0.0*I +DEAL:Complex double:Set new values::b: 9.0 + 0.0*I 10.0 + 0.0*I 11.0 + 0.0*I 12.0 + 0.0*I +DEAL:Complex double:Set new values::as: 5.0 + 0.0*I 7.0 + 0.0*I 7.0 + 0.0*I 6.0 + 0.0*I +DEAL:Complex double:Set new values::bs: 7.0 + 0.0*I 9.0 + 0.0*I 9.0 + 0.0*I 8.0 + 0.0*I +DEAL:Complex double:Relational operators 2::a == b: 0 +DEAL:Complex double:Relational operators 2::a != b: 1 +DEAL:Complex double:Math operators:Tensor::a+b: 14.0 + 0.0*I 16.0 + 0.0*I 18.0 + 0.0*I 20.0 + 0.0*I +DEAL:Complex double:Math operators:Tensor::a-b: -4.0 + 0.0*I -4.0 + 0.0*I -4.0 + 0.0*I -4.0 + 0.0*I +DEAL:Complex double:Math operators:Tensor::a*b: 111.0 + 0.0*I 122.0 + 0.0*I 151.0 + 0.0*I 166.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::as+bs: 12.0 + 0.0*I 16.0 + 0.0*I 16.0 + 0.0*I 14.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::as-bs: -2.0 + 0.0*I -2.0 + 0.0*I -2.0 + 0.0*I -2.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::as*bs: 209.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::as: 5.0 + 0.0*I 7.0 + 0.0*I 7.0 + 0.0*I 6.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::as_ns: 5.0 + 0.0*I 7.0 + 0.0*I 7.0 + 0.0*I 6.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::as+b: 14.0 + 0.0*I 17.0 + 0.0*I 18.0 + 0.0*I 18.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::as-b: -4.0 + 0.0*I -3.0 + 0.0*I -4.0 + 0.0*I -6.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::as*b: 122.0 + 0.0*I 134.0 + 0.0*I 129.0 + 0.0*I 142.0 + 0.0*I +DEAL:Complex double:Copy constructor::c: 5.0 + 0.0*I 6.0 + 0.0*I 7.0 + 0.0*I 8.0 + 0.0*I +DEAL:Complex double:Copy constructor::cs: 5.0 + 0.0*I 7.0 + 0.0*I 7.0 + 0.0*I 6.0 + 0.0*I +DEAL:Complex double:Math operators:Tensor::c+=b: 14.0 + 0.0*I 16.0 + 0.0*I 18.0 + 0.0*I 20.0 + 0.0*I +DEAL:Complex double:Math operators:Tensor::c*=s: 28.0 + 0.0*I 32.0 + 0.0*I 36.0 + 0.0*I 40.0 + 0.0*I +DEAL:Complex double:Math operators:Tensor::c-=b: 19.0 + 0.0*I 22.0 + 0.0*I 25.0 + 0.0*I 28.0 + 0.0*I +DEAL:Complex double:Math operators:Tensor::c/=s: 9.5 + 0.0*I 11.0 + 0.0*I 12.5 + 0.0*I 14.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::cs+=bs: 12.0 + 0.0*I 16.0 + 0.0*I 16.0 + 0.0*I 14.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::cs*=s: 24.0 + 0.0*I 32.0 + 0.0*I 32.0 + 0.0*I 28.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::cs-=bs: 17.0 + 0.0*I 23.0 + 0.0*I 23.0 + 0.0*I 20.0 + 0.0*I +DEAL:Complex double:Math operators:SymmetricTensor::cs/=s: 8.5 + 0.0*I 11.5 + 0.0*I 11.5 + 0.0*I 10.0 + 0.0*I +DEAL:Complex double:Symbols::x: x_00 x_01 x_10 x_11 +DEAL:Complex double:Symbols::y: y +DEAL:Complex double:Symbols::z: z_00 z_01 z_01 z_11 +DEAL:Complex double:Math operators:Tensor::c+=x: 9.5 + 0.0*I + x_00 11.0 + 0.0*I + x_01 12.5 + 0.0*I + x_10 14.0 + 0.0*I + x_11 +DEAL:Complex double:Math operators:Tensor::c*=y: y*(9.5 + 0.0*I + x_00) y*(11.0 + 0.0*I + x_01) y*(12.5 + 0.0*I + x_10) y*(14.0 + 0.0*I + x_11) +DEAL:Complex double:Math operators:Tensor::c*=s: (2.0 + 0.0*I)*y*(9.5 + 0.0*I + x_00) (2.0 + 0.0*I)*y*(11.0 + 0.0*I + x_01) (2.0 + 0.0*I)*y*(12.5 + 0.0*I + x_10) (2.0 + 0.0*I)*y*(14.0 + 0.0*I + x_11) +DEAL:Complex double:Math operators:Tensor::c-=x: -x_00 + (2.0 + 0.0*I)*y*(9.5 + 0.0*I + x_00) -x_01 + (2.0 + 0.0*I)*y*(11.0 + 0.0*I + x_01) -x_10 + (2.0 + 0.0*I)*y*(12.5 + 0.0*I + x_10) -x_11 + (2.0 + 0.0*I)*y*(14.0 + 0.0*I + x_11) +DEAL:Complex double:Math operators:Tensor::c/=y: (-x_00 + (2.0 + 0.0*I)*y*(9.5 + 0.0*I + x_00))/y (-x_01 + (2.0 + 0.0*I)*y*(11.0 + 0.0*I + x_01))/y (-x_10 + (2.0 + 0.0*I)*y*(12.5 + 0.0*I + x_10))/y (-x_11 + (2.0 + 0.0*I)*y*(14.0 + 0.0*I + x_11))/y +DEAL:Complex double:Math operators:Tensor::c/=s: (0.5 + 0.0*I)*(-x_00 + (2.0 + 0.0*I)*y*(9.5 + 0.0*I + x_00))/y (0.5 + 0.0*I)*(-x_01 + (2.0 + 0.0*I)*y*(11.0 + 0.0*I + x_01))/y (0.5 + 0.0*I)*(-x_10 + (2.0 + 0.0*I)*y*(12.5 + 0.0*I + x_10))/y (0.5 + 0.0*I)*(-x_11 + (2.0 + 0.0*I)*y*(14.0 + 0.0*I + x_11))/y +DEAL:Complex double:Math operators:SymmetricTensor::cs+=z: 8.5 + 0.0*I + z_00 11.5 + 0.0*I + z_01 11.5 + 0.0*I + z_01 10.0 + 0.0*I + z_11 +DEAL:Complex double:Math operators:SymmetricTensor::cs*=y: y*(8.5 + 0.0*I + z_00) y*(11.5 + 0.0*I + z_01) y*(11.5 + 0.0*I + z_01) y*(10.0 + 0.0*I + z_11) +DEAL:Complex double:Math operators:SymmetricTensor::cs*=s: (2.0 + 0.0*I)*y*(8.5 + 0.0*I + z_00) (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01) (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01) (2.0 + 0.0*I)*y*(10.0 + 0.0*I + z_11) +DEAL:Complex double:Math operators:SymmetricTensor::cs-=z: -z_00 + (2.0 + 0.0*I)*y*(8.5 + 0.0*I + z_00) -z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01) -z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01) -z_11 + (2.0 + 0.0*I)*y*(10.0 + 0.0*I + z_11) +DEAL:Complex double:Math operators:SymmetricTensor::cs/=y: (-z_00 + (2.0 + 0.0*I)*y*(8.5 + 0.0*I + z_00))/y (-z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01))/y (-z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01))/y (-z_11 + (2.0 + 0.0*I)*y*(10.0 + 0.0*I + z_11))/y +DEAL:Complex double:Math operators:SymmetricTensor::cs/=s: (0.5 + 0.0*I)*(-z_00 + (2.0 + 0.0*I)*y*(8.5 + 0.0*I + z_00))/y (0.5 + 0.0*I)*(-z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01))/y (0.5 + 0.0*I)*(-z_01 + (2.0 + 0.0*I)*y*(11.5 + 0.0*I + z_01))/y (0.5 + 0.0*I)*(-z_11 + (2.0 + 0.0*I)*y*(10.0 + 0.0*I + z_11))/y +DEAL:Complex double::OK +DEAL::OK From 6b4ecb1b86adb780c6ef54819f97304ce3635923 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Sun, 21 Apr 2019 21:38:04 -0600 Subject: [PATCH 431/507] Mark two function references better. --- include/deal.II/distributed/tria.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/deal.II/distributed/tria.h b/include/deal.II/distributed/tria.h index 04b212427be6..f373f7145f7c 100644 --- a/include/deal.II/distributed/tria.h +++ b/include/deal.II/distributed/tria.h @@ -1177,7 +1177,7 @@ namespace parallel * @return A vector of unsigned integers representing the weight or * computational load of every cell after the refinement/coarsening/ * repartition cycle. Note that the number of entries does not need to - * be equal to either n_active_cells or n_locally_owned_active_cells, + * be equal to either n_active_cells() or n_locally_owned_active_cells(), * because the triangulation is not updated yet. The weights are sorted * in the order that p4est will encounter them while iterating over * them. From daad233e194283efa1a980d7b9acef537cdad821 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Mon, 22 Apr 2019 08:32:49 -0600 Subject: [PATCH 432/507] Clarify a piece of documentation. --- include/deal.II/numerics/error_estimator.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/deal.II/numerics/error_estimator.h b/include/deal.II/numerics/error_estimator.h index a9b3fa4a6087..44f767ccfe7d 100644 --- a/include/deal.II/numerics/error_estimator.h +++ b/include/deal.II/numerics/error_estimator.h @@ -117,10 +117,12 @@ namespace hp * contributions of the faces (which are the integrated square of the jumps * times some factor) of each cell and take the square root. * - * The integration is done using a quadrature formula on the face. For linear - * trial functions (FEQ1), QGauss (with two points) or even the QMidpoint rule - * will suffice. For higher order elements, it is necessary to utilize higher - * order quadrature formulae as well. + * The integration is done using a quadrature formula on the face + * provided by the caller of the estimate() functions declared by this + * class. For linear trial functions (FE_Q(1)), QGauss with two points + * or even the QMidpoint rule might actually suffice. For higher order + * elements, it is necessary to utilize higher order quadrature + * formulae with `fe.degree+1` Gauss points. * * We store the contribution of each face in a @p map, as provided by the C++ * standard library, with the iterator pointing to that face being the key From 34e5510daf3021aa1601a0946faaa14eba197617 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Mon, 22 Apr 2019 14:16:05 -0500 Subject: [PATCH 433/507] SparsityPattern: Fix copy from DynamicSparsityPattern --- source/lac/sparsity_pattern.cc | 36 +++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/source/lac/sparsity_pattern.cc b/source/lac/sparsity_pattern.cc index 7a084e8c5b55..0f46463aed06 100644 --- a/source/lac/sparsity_pattern.cc +++ b/source/lac/sparsity_pattern.cc @@ -489,13 +489,39 @@ SparsityPattern::copy_from(const SparsityPattern &sp) void SparsityPattern::copy_from(const DynamicSparsityPattern &dsp) { - const bool do_diag_optimize = (dsp.n_rows() == dsp.n_cols()); + const bool do_diag_optimize = (dsp.n_rows() == dsp.n_cols()); + const auto &row_index_set = dsp.row_index_set(); + std::vector row_lengths(dsp.n_rows()); - for (size_type i = 0; i < dsp.n_rows(); ++i) + + if (row_index_set.size() == 0) { - row_lengths[i] = dsp.row_length(i); - if (do_diag_optimize && !dsp.exists(i, i)) - ++row_lengths[i]; + for (size_type i = 0; i < dsp.n_rows(); ++i) + { + row_lengths[i] = dsp.row_length(i); + if (do_diag_optimize && !dsp.exists(i, i)) + ++row_lengths[i]; + } + } + else + { + for (size_type i = 0; i < dsp.n_rows(); ++i) + { + if (row_index_set.is_element(i)) + { + row_lengths[i] = dsp.row_length(i); + if (do_diag_optimize && !dsp.exists(i, i)) + ++row_lengths[i]; + } + else + { + // If the row i is not stored in the DynamicSparsityPattern we + // nevertheless need to allocate 1 entry per row for the + // "diagonal optimization". (We store a pointer to the next row + // in place of the repeated index i for the diagonal element.) + row_lengths[i] = do_diag_optimize ? 1 : 0; + } + } } reinit(dsp.n_rows(), dsp.n_cols(), row_lengths); From 09e3944c6e653dbed77210ec8842dba96de27f1a Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Mon, 15 Apr 2019 11:30:30 -0500 Subject: [PATCH 434/507] add a test --- tests/sparsity/dynamic_sparsity_pattern_21.cc | 40 +++++++++++++++++++ .../dynamic_sparsity_pattern_21.output | 2 + 2 files changed, 42 insertions(+) create mode 100644 tests/sparsity/dynamic_sparsity_pattern_21.cc create mode 100644 tests/sparsity/dynamic_sparsity_pattern_21.output diff --git a/tests/sparsity/dynamic_sparsity_pattern_21.cc b/tests/sparsity/dynamic_sparsity_pattern_21.cc new file mode 100644 index 000000000000..cd217ae249da --- /dev/null +++ b/tests/sparsity/dynamic_sparsity_pattern_21.cc @@ -0,0 +1,40 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2004 - 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. +// +// --------------------------------------------------------------------- + +// Check DynamicSparsityPattern::exists() with supplied rowindex by copying +// to a static SparsityPattern. + +#include +#include + +#include "../tests.h" + +int +main() +{ + initlog(); + + const unsigned int n_dofs = 2; + IndexSet index_set(n_dofs); + index_set.add_index(1); + + DynamicSparsityPattern dsp(n_dofs, n_dofs, index_set); + SparsityPattern sp; + sp.copy_from(dsp); + + deallog << "OK" << std::endl; + + return 0; +} diff --git a/tests/sparsity/dynamic_sparsity_pattern_21.output b/tests/sparsity/dynamic_sparsity_pattern_21.output new file mode 100644 index 000000000000..0fd8fc12f0b4 --- /dev/null +++ b/tests/sparsity/dynamic_sparsity_pattern_21.output @@ -0,0 +1,2 @@ + +DEAL::OK From aae1a0580b896086c557856b9eafa6d5534d5351 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Mon, 22 Apr 2019 14:18:45 -0500 Subject: [PATCH 435/507] avoid a segmentation fault --- source/lac/dynamic_sparsity_pattern.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/lac/dynamic_sparsity_pattern.cc b/source/lac/dynamic_sparsity_pattern.cc index cb93d1a37d08..b96163570f1b 100644 --- a/source/lac/dynamic_sparsity_pattern.cc +++ b/source/lac/dynamic_sparsity_pattern.cc @@ -360,6 +360,11 @@ DynamicSparsityPattern::exists(const size_type i, const size_type j) const Assert(j < cols, ExcIndexRange(j, 0, cols)); Assert(rowset.size() == 0 || rowset.is_element(i), ExcInternalError()); + // Avoid a segmentation fault in below code if the row index happens to + // not be present in the IndexSet rowset: + if (!(rowset.size() == 0 || rowset.is_element(i))) + return false; + if (!have_entries) return false; From 1cbb7e8d5ae8d8b1b72e57eea4b1604027d44d9e Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Mon, 22 Apr 2019 14:32:19 -0500 Subject: [PATCH 436/507] improve error message --- source/lac/dynamic_sparsity_pattern.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/lac/dynamic_sparsity_pattern.cc b/source/lac/dynamic_sparsity_pattern.cc index b96163570f1b..5631edc66191 100644 --- a/source/lac/dynamic_sparsity_pattern.cc +++ b/source/lac/dynamic_sparsity_pattern.cc @@ -358,7 +358,11 @@ DynamicSparsityPattern::exists(const size_type i, const size_type j) const { Assert(i < rows, ExcIndexRange(i, 0, rows)); Assert(j < cols, ExcIndexRange(j, 0, cols)); - Assert(rowset.size() == 0 || rowset.is_element(i), ExcInternalError()); + Assert( + rowset.size() == 0 || rowset.is_element(i), + ExcMessage( + "The row IndexSet does not contain the index i. This sparsity pattern " + "object cannot know whether the entry (i, j) exists or not.")); // Avoid a segmentation fault in below code if the row index happens to // not be present in the IndexSet rowset: From 08182a4b05e9107dba58fef96ec892eeffb6c889 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Fri, 19 Apr 2019 10:17:13 +0200 Subject: [PATCH 437/507] Mapping::get_center() --- doc/news/changes/minor/20190411LucaHeltai | 4 + include/deal.II/fe/mapping.h | 26 ++++++ source/fe/mapping.cc | 25 ++++++ tests/mappings/mapping_q_eulerian_12.cc | 96 +++++++++++++++++++++ tests/mappings/mapping_q_eulerian_12.output | 10 +++ 5 files changed, 161 insertions(+) create mode 100644 doc/news/changes/minor/20190411LucaHeltai create mode 100644 tests/mappings/mapping_q_eulerian_12.cc create mode 100644 tests/mappings/mapping_q_eulerian_12.output 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/include/deal.II/fe/mapping.h b/include/deal.II/fe/mapping.h index 21bec9ebc2a3..c1c60aac8ba7 100644 --- a/include/deal.II/fe/mapping.h +++ b/include/deal.II/fe/mapping.h @@ -336,6 +336,32 @@ class Mapping : public Subscriptor get_vertices( const typename Triangulation::cell_iterator &cell) const; + /** + * Return the mapped center of a cell. + * + * If you are using a (bi-,tri-)linear mapping that preserves vertex + * locations, this function simply returns the value also produced by + * `cell->center()`. However, there are also mappings that add displacements + * or choose completely different locations, e.g., MappingQEulerian, + * MappingQ1Eulerian, or MappingFEField. + * + * By default, this function returns the average of the vertex locations + * returned by the the get_vertices() method. If the parameter + * @p map_center_of_reference_cell is set to true, than a more expensive + * algorithm is used, that returns the mapped center of the reference cell, + * obtained by the transform_unit_to_real_cell() method. + * + * @param[in] cell The cell for which you want to compute the center + * @param[in] map_center_of_reference_cell A flag that switches the algorithm + * for the computation of the cell center from vertex averages to + * transform_unit_to_real_cell() applied to the center of the reference cell + * + * @author Luca Heltai, 2019. + */ + virtual Point + get_center(const typename Triangulation::cell_iterator &cell, + const bool map_center_of_reference_cell = false) const; + /** * Return whether the mapping preserves vertex locations. In other words, * this function returns whether the mapped location of the reference cell diff --git a/source/fe/mapping.cc b/source/fe/mapping.cc index 60d57958000e..97a7a38f2364 100644 --- a/source/fe/mapping.cc +++ b/source/fe/mapping.cc @@ -36,6 +36,31 @@ Mapping::get_vertices( +template +Point +Mapping::get_center( + const typename Triangulation::cell_iterator &cell, + const bool map_center_of_reference_cell) const +{ + if (map_center_of_reference_cell) + { + Point reference_center; + for (unsigned int d = 0; d < dim; ++d) + reference_center[d] = .5; + return transform_unit_to_real_cell(cell, reference_center); + } + else + { + const auto vertices = get_vertices(cell); + Point center; + for (const auto &v : vertices) + center += v; + return center / GeometryInfo::vertices_per_cell; + } +} + + + template Point Mapping::project_real_point_to_unit_point_on_face( diff --git a/tests/mappings/mapping_q_eulerian_12.cc b/tests/mappings/mapping_q_eulerian_12.cc new file mode 100644 index 000000000000..e8626585c506 --- /dev/null +++ b/tests/mappings/mapping_q_eulerian_12.cc @@ -0,0 +1,96 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// test that MappingQEulerian knows how to compute centers of cells + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include "../tests.h" + +using namespace dealii; + + +template +class Displacement : public Function +{ +public: + Displacement() + : Function(dim) + {} + + double + value(const Point &p, const unsigned int component) const + { + return p[component] * p[0] / 2; + } +}; + + +template +void +test() +{ + deallog << "dim=" << dim << std::endl; + + Triangulation triangulation; + GridGenerator::hyper_cube(triangulation, -1, 1); + + FESystem fe(FE_Q(2), dim); + DoFHandler dof_handler(triangulation); + dof_handler.distribute_dofs(fe); + + Vector displacements(dof_handler.n_dofs()); + + VectorTools::interpolate(dof_handler, Displacement(), displacements); + + MappingQEulerian euler(2, dof_handler, displacements); + + // now the actual test + for (const auto &cell : dof_handler.active_cell_iterators()) + { + deallog << "Center: [" << cell->center() << "], with mapping [" + << euler.get_center(cell) << "]" << std::endl; + deallog << "Center: [" << cell->center() << "], with mapping + flag [" + << euler.get_center(cell, true) << "]" << std::endl; + } +} + + + +int +main() +{ + initlog(1); + + test<1>(); + test<2>(); + test<3>(); +} diff --git a/tests/mappings/mapping_q_eulerian_12.output b/tests/mappings/mapping_q_eulerian_12.output new file mode 100644 index 000000000000..eb04a22389ae --- /dev/null +++ b/tests/mappings/mapping_q_eulerian_12.output @@ -0,0 +1,10 @@ + +DEAL::dim=1 +DEAL::Center: [0.00000], with mapping [0.500000] +DEAL::Center: [0.00000], with mapping + flag [0.00000] +DEAL::dim=2 +DEAL::Center: [0.00000 0.00000], with mapping [0.500000 0.00000] +DEAL::Center: [0.00000 0.00000], with mapping + flag [0.00000 0.00000] +DEAL::dim=3 +DEAL::Center: [0.00000 0.00000 0.00000], with mapping [0.500000 0.00000 0.00000] +DEAL::Center: [0.00000 0.00000 0.00000], with mapping + flag [0.00000 0.00000 0.00000] From 440455f0d9a13cff2a67735a3b418192d9e111f4 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 23 Apr 2019 11:22:12 +0200 Subject: [PATCH 438/507] Fix documentation of extend + spelling. --- include/deal.II/base/bounding_box.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/deal.II/base/bounding_box.h b/include/deal.II/base/bounding_box.h index 97acdb873d78..bfb85c5e79ee 100644 --- a/include/deal.II/base/bounding_box.h +++ b/include/deal.II/base/bounding_box.h @@ -141,7 +141,8 @@ class BoundingBox point_inside(const Point &p) const; /** - * Increase (or decrease) the size of the bounding box by the given amount. + * Increase (or decrease) the size of the bounding box by the given amount, + * in both directions in all coordinate directions. * * 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 @@ -195,7 +196,7 @@ BoundingBox::extend(const Number &amount) 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 shrinked this much: the points' " + ExcMessage("Bounding Box can't be shrunk this much: the points' " "order should remain bottom left, top right.")); } } From 92003f37ac757ffbb8ebb002519975fe6cb08428 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 23 Apr 2019 14:46:08 +0200 Subject: [PATCH 439/507] Improved documentation. --- include/deal.II/base/bounding_box.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/deal.II/base/bounding_box.h b/include/deal.II/base/bounding_box.h index bfb85c5e79ee..8922fa6b3676 100644 --- a/include/deal.II/base/bounding_box.h +++ b/include/deal.II/base/bounding_box.h @@ -141,8 +141,10 @@ class BoundingBox point_inside(const Point &p) const; /** - * Increase (or decrease) the size of the bounding box by the given amount, - * in both directions in all coordinate directions. + * 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 From 772651e912cf3caf2394fddbef1cabb58ad2f832 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Thu, 18 Apr 2019 09:31:50 +0200 Subject: [PATCH 440/507] Modify FunctionCutOff to support integration to one. --- doc/news/changes/minor/20190418LucaHeltai | 3 + include/deal.II/base/function_lib.h | 50 ++++++++- source/base/function_lib_cutoff.cc | 131 ++++++++++++++++++---- tests/function_cutoff_01.cc | 120 ++++++++++++++++++++ tests/function_cutoff_01.output | 64 +++++++++++ 5 files changed, 339 insertions(+), 29 deletions(-) create mode 100644 doc/news/changes/minor/20190418LucaHeltai create mode 100644 tests/function_cutoff_01.cc create mode 100644 tests/function_cutoff_01.output 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/include/deal.II/base/function_lib.h b/include/deal.II/base/function_lib.h index 665cef4b3c8d..3769444c3e74 100644 --- a/include/deal.II/base/function_lib.h +++ b/include/deal.II/base/function_lib.h @@ -912,8 +912,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 on the radius of the supporting ball. + * * @ingroup functions - * @author Guido Kanschat, 2002 + * @author Guido Kanschat, 2002, Luca Heltai, 2019. */ template class CutOffFunctionBase : public Function @@ -930,12 +934,17 @@ namespace Functions * * If an argument select is given and not -1, the cut-off * function will be non-zero for this component only. + * + * If the argument @p integrate_to_one is set to true, then the value of + * the function is rescaled whenever a new radius is set. */ CutOffFunctionBase( const double radius = 1., const Point = 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); /** * Move the center of the ball to new point p. @@ -949,6 +958,18 @@ namespace Functions void new_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; + protected: /** * Center of the integration ball. @@ -965,6 +986,22 @@ namespace Functions * in all components. */ const unsigned int selected; + + /** + * Flag that controls wether we rescale the value when the radius changes. + */ + const 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; }; @@ -992,7 +1029,8 @@ namespace Functions const double radius = 1., const Point = 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); /** * Function value at one point. @@ -1040,7 +1078,8 @@ namespace Functions const double radius = 1., const Point = 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); /** * Function value at one point. @@ -1089,7 +1128,8 @@ namespace Functions const double radius = 1., const Point = Point(), const unsigned int n_components = 1, - const unsigned int select = CutOffFunctionBase::no_component); + const unsigned int select = CutOffFunctionBase::no_component, + bool integrate_to_one = false); /** * Function value at one point. diff --git a/source/base/function_lib_cutoff.cc b/source/base/function_lib_cutoff.cc index b35fcc42d9ec..71ba7b7834fc 100644 --- a/source/base/function_lib_cutoff.cc +++ b/source/base/function_lib_cutoff.cc @@ -27,15 +27,25 @@ DEAL_II_NAMESPACE_OPEN namespace Functions { template - CutOffFunctionBase::CutOffFunctionBase(const double r, - const Point p, - const unsigned int n_components, - const unsigned int select) + CutOffFunctionBase::CutOffFunctionBase( + const double r, + const Point p, + const unsigned int n_components, + const unsigned int select, + const bool integrate_to_one, + const double unitary_integral_value) : Function(n_components) , center(p) , radius(r) , selected(select) - {} + , integrate_to_one(integrate_to_one) + , unitary_integral_value(unitary_integral_value) + , rescaling(integrate_to_one ? 1. / (unitary_integral_value * + Utilities::fixed_power(radius)) : + 1.0) + { + Assert(r > 0, ExcMessage("You must specify a radius > 0.")); + } template @@ -46,22 +56,68 @@ namespace Functions } + + template + const Point & + CutOffFunctionBase::get_center() const + { + return center; + } + + + template void CutOffFunctionBase::new_radius(const double r) { radius = r; + Assert(r > 0, ExcMessage("You must specify a radius > 0.")); + if (integrate_to_one) + rescaling = + 1. / (unitary_integral_value * Utilities::fixed_power(radius)); + else + rescaling = 1.0; + } + + + + template + double + CutOffFunctionBase::get_radius() const + { + return radius; } + ////////////////////////////////////////////////////////////////////// + namespace + { + double integral_Linfty[] = {2.0, + 3.14159265358979323846264338328, + 4.18879020478639098461685784437}; + double integral_W1[] = {1.0, + 1.04719755119659774615421446109, + 1.04719755119659774615421446109}; + + double integral_Cinfty[] = {1.20690032243787617533623799633, + 1.26811216112759608094632335664, + 1.1990039070192139033798473858}; + } // namespace + template CutOffFunctionLinfty::CutOffFunctionLinfty( const double r, const Point p, const unsigned int n_components, - const unsigned int select) - : CutOffFunctionBase(r, p, n_components, select) + const unsigned int select, + const bool integrate_to_one) + : CutOffFunctionBase(r, + p, + n_components, + select, + integrate_to_one, + integral_Linfty[dim - 1]) {} @@ -72,7 +128,7 @@ namespace Functions { if (this->selected == CutOffFunctionBase::no_component || component == this->selected) - return ((this->center.distance(p) < this->radius) ? 1. : 0.); + return ((this->center.distance(p) < this->radius) ? this->rescaling : 0.); return 0.; } @@ -92,7 +148,9 @@ namespace Functions if (this->selected == CutOffFunctionBase::no_component || component == this->selected) for (unsigned int k = 0; k < values.size(); ++k) - values[k] = (this->center.distance(points[k]) < this->radius) ? 1. : 0.; + values[k] = (this->center.distance(points[k]) < this->radius) ? + this->rescaling : + 0.; else std::fill(values.begin(), values.end(), 0.); } @@ -109,8 +167,9 @@ namespace Functions for (unsigned int k = 0; k < values.size(); ++k) { - const double val = - (this->center.distance(points[k]) < this->radius) ? 1. : 0.; + const double val = (this->center.distance(points[k]) < this->radius) ? + this->rescaling : + 0.; if (this->selected == CutOffFunctionBase::no_component) values[k] = val; else @@ -121,13 +180,18 @@ namespace Functions } } - template CutOffFunctionW1::CutOffFunctionW1(const double r, const Point p, const unsigned int n_components, - const unsigned int select) - : CutOffFunctionBase(r, p, n_components, select) + const unsigned int select, + const bool integrate_to_one) + : CutOffFunctionBase(r, + p, + n_components, + select, + integrate_to_one, + integral_W1[dim - 1]) {} @@ -140,7 +204,9 @@ namespace Functions component == this->selected) { const double d = this->center.distance(p); - return ((d < this->radius) ? (this->radius - d) : 0.); + return ((d < this->radius) ? + (this->radius - d) / this->radius * this->rescaling : + 0.); } return 0.; } @@ -160,7 +226,9 @@ namespace Functions for (unsigned int i = 0; i < values.size(); ++i) { const double d = this->center.distance(points[i]); - values[i] = ((d < this->radius) ? (this->radius - d) : 0.); + values[i] = ((d < this->radius) ? + (this->radius - d) / this->radius * this->rescaling : + 0.); } else std::fill(values.begin(), values.end(), 0.); @@ -179,8 +247,11 @@ namespace Functions for (unsigned int k = 0; k < values.size(); ++k) { - const double d = this->center.distance(points[k]); - const double val = (d < this->radius) ? (this->radius - d) : 0.; + const double d = this->center.distance(points[k]); + const double val = + (d < this->radius) ? + (this->radius - d) / this->radius * this->rescaling : + 0.; if (this->selected == CutOffFunctionBase::no_component) values[k] = val; else @@ -197,8 +268,14 @@ namespace Functions const double r, const Point p, const unsigned int n_components, - const unsigned int select) - : CutOffFunctionBase(r, p, n_components, select) + const unsigned int select, + bool integrate_to_one) + : CutOffFunctionBase(r, + p, + n_components, + select, + integrate_to_one, + integral_Cinfty[dim - 1]) {} @@ -215,7 +292,7 @@ namespace Functions if (d >= r) return 0.; const double e = -r * r / (r * r - d * d); - return ((e < -50) ? 0. : numbers::E * std::exp(e)); + return ((e < -50) ? 0. : numbers::E * std::exp(e) * this->rescaling); } return 0.; } @@ -244,7 +321,8 @@ namespace Functions else { const double e = -r * r / (r * r - d * d); - values[i] = (e < -50) ? 0. : numbers::E * std::exp(e); + values[i] = + (e < -50) ? 0. : numbers::E * std::exp(e) * this->rescaling; } } else @@ -270,7 +348,7 @@ namespace Functions { const double e = -r * r / (r * r - d * d); if (e > -50) - val = numbers::E * std::exp(e); + val = numbers::E * std::exp(e) * this->rescaling; } if (this->selected == CutOffFunctionBase::no_component) @@ -298,11 +376,16 @@ namespace Functions return ((e < -50) ? Point() : (p - this->center) / d * (-2.0 * r * r / std::pow(-r * r + d * d, 2.0) * d * - std::exp(e))); + std::exp(e)) * + this->rescaling); } // explicit instantiations + template class CutOffFunctionBase<1>; + template class CutOffFunctionBase<2>; + template class CutOffFunctionBase<3>; + template class CutOffFunctionLinfty<1>; template class CutOffFunctionLinfty<2>; template class CutOffFunctionLinfty<3>; diff --git a/tests/function_cutoff_01.cc b/tests/function_cutoff_01.cc new file mode 100644 index 000000000000..428660863091 --- /dev/null +++ b/tests/function_cutoff_01.cc @@ -0,0 +1,120 @@ +// --------------------------------------------------------------------- +// +// 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. +// +// --------------------------------------------------------------------- + +// Test the functionality of the CutOffFunction with integrate_to_one = true + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include "../tests.h" + +using namespace Functions; + +template +struct Domain +{ + Domain() + : fe(1) + , dh(tria) + , quad(5) + { + deallog << "Testing dim = " << dim << std::endl; + GridGenerator::hyper_cube(tria, -2, 2); + tria.refine_global(5 - dim); + dh.distribute_dofs(fe); + zero.reinit(dh.n_dofs()); + cell_integral.reinit(tria.n_active_cells()); + } + + template + void + integrate(const Function &fun) + { + deallog << "Integrating " << Utilities::type_to_string(fun) + << " -2,2 cube: "; + + VectorTools::integrate_difference( + dh, zero, fun, cell_integral, quad, VectorTools::L1_norm); + const double integral = + VectorTools::compute_global_error(tria, + cell_integral, + VectorTools::L1_norm); + + deallog << integral << std::endl; + } + + Triangulation tria; + FE_Q fe; + DoFHandler dh; + Vector zero; + Vector cell_integral; + QGauss quad; +}; + +template class TestCutOffFunction> +void +test() +{ + static Domain domain; + TestCutOffFunction fun(1., + Point(), + 1, + Functions::CutOffFunctionBase::no_component, + /*integrate_to_one = */ true); + deallog << "Center: " << fun.get_center() << std::endl + << "Radius: " << fun.get_radius() << std::endl; + + domain.integrate(fun); + + Point new_center; + for (unsigned int i = 0; i < dim; ++i) + new_center[i] = .5; + + fun.new_center(new_center); + fun.new_radius(.5); + + deallog << "Center: " << fun.get_center() << std::endl + << "Radius: " << fun.get_radius() << std::endl; + + domain.integrate(fun); +} + +int +main() +{ + initlog(1); + + test<1, Functions::CutOffFunctionLinfty>(); + test<2, Functions::CutOffFunctionLinfty>(); + test<3, Functions::CutOffFunctionLinfty>(); + + test<1, Functions::CutOffFunctionW1>(); + test<2, Functions::CutOffFunctionW1>(); + test<3, Functions::CutOffFunctionW1>(); + + test<1, Functions::CutOffFunctionCinfty>(); + test<2, Functions::CutOffFunctionCinfty>(); + test<3, Functions::CutOffFunctionCinfty>(); +} diff --git a/tests/function_cutoff_01.output b/tests/function_cutoff_01.output new file mode 100644 index 000000000000..2554c237b72e --- /dev/null +++ b/tests/function_cutoff_01.output @@ -0,0 +1,64 @@ + +DEAL::Testing dim = 1 +DEAL::Center: 0.00000 +DEAL::Radius: 1.00000 +DEAL::Integrating dealii::Functions::CutOffFunctionLinfty<1> -2,2 cube: 1.00000 +DEAL::Center: 0.500000 +DEAL::Radius: 0.500000 +DEAL::Integrating dealii::Functions::CutOffFunctionLinfty<1> -2,2 cube: 1.00000 +DEAL::Testing dim = 2 +DEAL::Center: 0.00000 0.00000 +DEAL::Radius: 1.00000 +DEAL::Integrating dealii::Functions::CutOffFunctionLinfty<2> -2,2 cube: 0.993980 +DEAL::Center: 0.500000 0.500000 +DEAL::Radius: 0.500000 +DEAL::Integrating dealii::Functions::CutOffFunctionLinfty<2> -2,2 cube: 1.02445 +DEAL::Testing dim = 3 +DEAL::Center: 0.00000 0.00000 0.00000 +DEAL::Radius: 1.00000 +DEAL::Integrating dealii::Functions::CutOffFunctionLinfty<3> -2,2 cube: 1.00850 +DEAL::Center: 0.500000 0.500000 0.500000 +DEAL::Radius: 0.500000 +DEAL::Integrating dealii::Functions::CutOffFunctionLinfty<3> -2,2 cube: 0.958427 +DEAL::Testing dim = 1 +DEAL::Center: 0.00000 +DEAL::Radius: 1.00000 +DEAL::Integrating dealii::Functions::CutOffFunctionW1<1> -2,2 cube: 1.00000 +DEAL::Center: 0.500000 +DEAL::Radius: 0.500000 +DEAL::Integrating dealii::Functions::CutOffFunctionW1<1> -2,2 cube: 1.00000 +DEAL::Testing dim = 2 +DEAL::Center: 0.00000 0.00000 +DEAL::Radius: 1.00000 +DEAL::Integrating dealii::Functions::CutOffFunctionW1<2> -2,2 cube: 1.00030 +DEAL::Center: 0.500000 0.500000 +DEAL::Radius: 0.500000 +DEAL::Integrating dealii::Functions::CutOffFunctionW1<2> -2,2 cube: 1.00316 +DEAL::Testing dim = 3 +DEAL::Center: 0.00000 0.00000 0.00000 +DEAL::Radius: 1.00000 +DEAL::Integrating dealii::Functions::CutOffFunctionW1<3> -2,2 cube: 1.00445 +DEAL::Center: 0.500000 0.500000 0.500000 +DEAL::Radius: 0.500000 +DEAL::Integrating dealii::Functions::CutOffFunctionW1<3> -2,2 cube: 1.03922 +DEAL::Testing dim = 1 +DEAL::Center: 0.00000 +DEAL::Radius: 1.00000 +DEAL::Integrating dealii::Functions::CutOffFunctionCinfty<1> -2,2 cube: 1.00002 +DEAL::Center: 0.500000 +DEAL::Radius: 0.500000 +DEAL::Integrating dealii::Functions::CutOffFunctionCinfty<1> -2,2 cube: 0.999735 +DEAL::Testing dim = 2 +DEAL::Center: 0.00000 0.00000 +DEAL::Radius: 1.00000 +DEAL::Integrating dealii::Functions::CutOffFunctionCinfty<2> -2,2 cube: 0.999958 +DEAL::Center: 0.500000 0.500000 +DEAL::Radius: 0.500000 +DEAL::Integrating dealii::Functions::CutOffFunctionCinfty<2> -2,2 cube: 0.998842 +DEAL::Testing dim = 3 +DEAL::Center: 0.00000 0.00000 0.00000 +DEAL::Radius: 1.00000 +DEAL::Integrating dealii::Functions::CutOffFunctionCinfty<3> -2,2 cube: 0.999614 +DEAL::Center: 0.500000 0.500000 0.500000 +DEAL::Radius: 0.500000 +DEAL::Integrating dealii::Functions::CutOffFunctionCinfty<3> -2,2 cube: 1.00165 From 96c4a2a8b98e10a20be9336e7df7e45e32792ae4 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Thu, 18 Apr 2019 15:48:51 +0200 Subject: [PATCH 441/507] Deprecate new_* in favour of set_* --- include/deal.II/base/function_lib.h | 22 ++++++++++++++++++++-- source/base/function_lib_cutoff.cc | 18 ++++++++++++++++++ tests/{ => base}/function_cutoff_01.cc | 4 ++-- tests/{ => base}/function_cutoff_01.output | 0 4 files changed, 40 insertions(+), 4 deletions(-) rename tests/{ => base}/function_cutoff_01.cc (98%) rename tests/{ => base}/function_cutoff_01.output (100%) diff --git a/include/deal.II/base/function_lib.h b/include/deal.II/base/function_lib.h index 3769444c3e74..0b36b2d4e32d 100644 --- a/include/deal.II/base/function_lib.h +++ b/include/deal.II/base/function_lib.h @@ -948,16 +948,34 @@ namespace Functions /** * 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. + */ + void + set_center(const Point &p); + + /** + * Set the radius of the ball to @p r + * + * @deprecated Use set_radius() instead. + */ + void + set_radius(const double r); + /** * Return the center stored in this object. */ diff --git a/source/base/function_lib_cutoff.cc b/source/base/function_lib_cutoff.cc index 71ba7b7834fc..e1fa60fc532b 100644 --- a/source/base/function_lib_cutoff.cc +++ b/source/base/function_lib_cutoff.cc @@ -51,6 +51,15 @@ namespace Functions template void CutOffFunctionBase::new_center(const Point &p) + { + set_center(p); + } + + + + template + void + CutOffFunctionBase::set_center(const Point &p) { center = p; } @@ -69,6 +78,15 @@ namespace Functions template void CutOffFunctionBase::new_radius(const double r) + { + set_radius(r); + } + + + + template + void + CutOffFunctionBase::set_radius(const double r) { radius = r; Assert(r > 0, ExcMessage("You must specify a radius > 0.")); diff --git a/tests/function_cutoff_01.cc b/tests/base/function_cutoff_01.cc similarity index 98% rename from tests/function_cutoff_01.cc rename to tests/base/function_cutoff_01.cc index 428660863091..c51ac0f79747 100644 --- a/tests/function_cutoff_01.cc +++ b/tests/base/function_cutoff_01.cc @@ -92,8 +92,8 @@ test() for (unsigned int i = 0; i < dim; ++i) new_center[i] = .5; - fun.new_center(new_center); - fun.new_radius(.5); + fun.set_center(new_center); + fun.set_radius(.5); deallog << "Center: " << fun.get_center() << std::endl << "Radius: " << fun.get_radius() << std::endl; diff --git a/tests/function_cutoff_01.output b/tests/base/function_cutoff_01.output similarity index 100% rename from tests/function_cutoff_01.output rename to tests/base/function_cutoff_01.output From 454a08167dbc5d67dc43a6d91e1993e7b8405c07 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Thu, 18 Apr 2019 19:57:37 +0200 Subject: [PATCH 442/507] Added FunctionCutOffTensorProduct. --- include/deal.II/base/function_lib.h | 109 +++++++++++++++++++++++- source/base/function_lib_cutoff.cc | 79 ++++++++++++++++++ tests/base/function_cutoff_02.cc | 120 +++++++++++++++++++++++++++ tests/base/function_cutoff_02.output | 64 ++++++++++++++ 4 files changed, 369 insertions(+), 3 deletions(-) create mode 100644 tests/base/function_cutoff_02.cc create mode 100644 tests/base/function_cutoff_02.output diff --git a/include/deal.II/base/function_lib.h b/include/deal.II/base/function_lib.h index 0b36b2d4e32d..ff38a07bc863 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 @@ -946,6 +947,11 @@ namespace Functions 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. * @@ -965,7 +971,7 @@ namespace Functions /** * Set the center of the ball to the point @p p. */ - void + virtual void set_center(const Point &p); /** @@ -973,7 +979,7 @@ namespace Functions * * @deprecated Use set_radius() instead. */ - void + virtual void set_radius(const double r); /** @@ -988,6 +994,12 @@ namespace Functions double get_radius() const; + /** + * Return a boolean indicating if this function integrates to one. + */ + bool + integrates_to_one() const; + protected: /** * Center of the integration ball. @@ -1008,7 +1020,7 @@ namespace Functions /** * Flag that controls wether we rescale the value when the radius changes. */ - const bool integrate_to_one; + bool integrate_to_one; /** * The reference integral value. Derived classes should specify what their @@ -1023,6 +1035,76 @@ namespace Functions }; + /** + * 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 objet of type + * @tparam CutOffFunctionBaseType<1>. + */ + template