From a009b73ab3351dc1f8f58bbb3b171267f6a91227 Mon Sep 17 00:00:00 2001 From: Roy Stogner Date: Mon, 4 May 2026 15:12:18 -0500 Subject: [PATCH 1/2] Make IntRange compatible with Threads --- include/utils/int_range.h | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/include/utils/int_range.h b/include/utils/int_range.h index b967afa3736..de25e823c52 100644 --- a/include/utils/int_range.h +++ b/include/utils/int_range.h @@ -61,7 +61,7 @@ class IntRange using pointer = T; using reference = T&; - iterator (T i) : _i(i) {} + explicit iterator (T i) : _i(i) {} T operator* () const { return _i; } @@ -78,6 +78,20 @@ class IntRange return returnval; } + template + void operator+= (T2 n) + { + _i += cast_int(n); + } + + template + iterator operator+ (T2 n) const + { + iterator returnval(_i); + returnval += n; + return returnval; + } + bool operator== (const iterator & j) const { return ( _i == j._i ); @@ -92,21 +106,40 @@ class IntRange T _i; }; + typedef typename IntRange::iterator const_iterator; + template IntRange(U begin, V end) : _begin(cast_int(begin)), _end(cast_int(end)) {} + // Signature needed for use in threads_pthread.h + IntRange(const IntRange &, + const const_iterator & begin, + const const_iterator & end) : + _begin(begin), + _end(end) + {} + iterator begin() const { return _begin; } iterator end () const { return _end; } + std::size_t size () const + { return *_end - *_begin; } + private: iterator _begin, _end; }; +template +typename IntRange::iterator operator+ (T2 n, typename IntRange::iterator i) +{ + return i + n; +} + /** * Helper function that returns an IntRange representing From a0b79383beb6fb4e07a99e05d6243531cae04431 Mon Sep 17 00:00:00 2001 From: Roy Stogner Date: Mon, 4 May 2026 15:13:18 -0500 Subject: [PATCH 2/2] Try using threads in l2_norm_diff This request turned out to be harder than it should have been, but if it works then there's a ton of other opportunities that ought to be much easier to make threaded now that IntRange has been fixed up to do that more easily. --- src/numerics/numeric_vector.C | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/numerics/numeric_vector.C b/src/numerics/numeric_vector.C index a66cda1ec68..36e68236f40 100644 --- a/src/numerics/numeric_vector.C +++ b/src/numerics/numeric_vector.C @@ -617,13 +617,34 @@ Real NumericVector::l2_norm_diff (const NumericVector & v) const { libmesh_assert(this->compatible(v)); - Real norm = 0; - for (const auto i : make_range(this->first_local_index(), this->last_local_index())) - norm += TensorTools::norm_sq((*this)(i) - v(i)); + struct Differ { + const NumericVector & v1, & v2; + Real norm_sq; - this->comm().sum(norm); + Differ (const NumericVector & v1in, + const NumericVector & v2in) : + v1(v1in), v2(v2in), norm_sq(0) {} - return std::sqrt(norm); + Differ (Differ & other, Threads::split) : + v1(other.v1), v2(other.v2), norm_sq(0) {} + + void operator()(const IntRange & index_range) { + for (const auto i : index_range) + norm_sq += TensorTools::norm_sq(v1(i) - v2(i)); + } + + void join(const Differ & other) { + norm_sq += other.norm_sq; + } + }; + + Differ differ(*this, v); + + Threads::parallel_reduce(make_range(this->first_local_index(), this->last_local_index()), differ); + + this->comm().sum(differ.norm_sq); + + return std::sqrt(differ.norm_sq); }