2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as
4 * published by the Free Software Foundation, either version 3 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * @file ParallelIIEstimator.ih
19 * @author Bastien Doignies
20 * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), INSA-Lyon, France
24 * Header file for module ParallelEstimator.ih
26 * This file is part of the DGtal library.
36 template<class TEstimator, typename TSplitter>
37 template<class... Args>
38 ParallelIIEstimator<TEstimator, TSplitter>::
39 ParallelIIEstimator(Splitter splitter, int32_t nbThread, Args&&... args)
40 : mySplitter(std::move(splitter))
43 nbThread = std::max(1, omp_get_max_threads());
45 // Note: We can not use std::vector constructor or resize
46 // because it will copy the estimator but it can have shared
48 // We rather build a new one in a loop by calling the constructor
49 // implictely with emplace_back
50 myEstimators.reserve(nbThread);
51 for (int i = 0; i < nbThread; ++i)
52 myEstimators.emplace_back(std::forward<Args>(args)...);
55 template<class TEstimator, typename TSplitter>
56 void ParallelIIEstimator<TEstimator, TSplitter>::clear()
58 for (auto& estim : myEstimators)
62 template<class TEstimator, typename TSplitter>
63 typename ParallelIIEstimator<TEstimator, TSplitter>::Scalar
64 ParallelIIEstimator<TEstimator, TSplitter>::h() const { return myEstimators[0].h(); }
66 template<class TEstimator, typename TSplitter>
67 void ParallelIIEstimator<TEstimator, TSplitter>::attach(
69 ConstAlias<PointPredicate> pp)
74 myPointPredicate = pp;
77 template<class TEstimator, typename TSplitter>
78 void ParallelIIEstimator<TEstimator, TSplitter>::setParams(double dRadius)
83 template<class TEstimator, typename TSplitter>
84 bool ParallelIIEstimator<TEstimator, TSplitter>::isValid() const
87 for (const auto& estim : myEstimators)
88 valid = valid && estim.isValid();
93 template<class TEstimator, typename TSplitter>
94 template<typename ItA, typename ItB>
95 void ParallelIIEstimator<TEstimator, TSplitter>::init(double h_, ItA, ItB)
100 template<class TEstimator, typename TSplitter>
101 template<typename It>
102 typename ParallelIIEstimator<TEstimator, TSplitter>::Quantity
103 ParallelIIEstimator<TEstimator, TSplitter>::eval(It it)
105 if (!myEstimators[0].isValid())
107 auto ite = it; ite++;
108 myEstimators[0].init(myH, it, ite);
113 .value = myEstimators[0].eval(it)
117 template<class TEstimator, typename TSplitter>
118 template<typename It, typename Oit>
119 Oit ParallelIIEstimator<TEstimator, TSplitter>::eval(It itb, It ite, Oit rslt)
121 Domain mainDomain(myKSpace->lowerBound(), myKSpace->upperBound());
122 std::vector<SplitInfo<Domain>> domains = mySplitter(mainDomain, myEstimators.size());
124 using Result = std::pair<Surfel, std::optional<EstimatorQuantity>>;
125 std::deque<Result> result;
126 std::vector<std::vector<Result*>> resultLocation(domains.size());
127 for ( auto it = itb; it != ite; ++it )
129 result.push_back( { *it, std::nullopt } );
130 Result* current = &result.back();
132 for (unsigned int j = 0; j < domains.size(); ++j)
134 // Should be true for only one of the domain. The break ensure
135 // each surfel belongs to one and only one domain, meaning there
136 // will be no concurrent write afterward
137 if (domains[j].domain.isInside(myKSpace->interiorVoxel(*it)))
139 resultLocation[j].push_back( current );
145 #pragma omp parallel for
146 for (uint32_t i = 0; i < domains.size(); ++i)
148 auto surfels = resultLocation[i] | std::views::transform([](const auto* kv) -> const Surfel&
152 auto values = resultLocation[i] | std::views::transform([](auto* kv) -> std::optional<EstimatorQuantity>&
157 auto& estim = myEstimators[i];
159 estim.attach(*myKSpace, *myPointPredicate);
160 estim.setParams(myRadius);
162 estim.init(myH, surfels.begin(), surfels.end());
163 estim.eval(surfels.begin(), surfels.end(), values.begin());
166 for (const auto& entry : result)
168 assert(entry.second.has_value());
169 *rslt++ = *entry.second;
175 template<class TEstimator, typename TSplitter>
177 ParallelIIEstimator<TEstimator, TSplitter>::selfDisplay( std::ostream & out ) const
179 out << "[ParallelIIEstimator Estim=";
180 myEstimators[0].selfDisplay(out);