40 const T *
const constraints,
41 T *
const outputScalarField,
42 const bool useCotanWeights,
44 const double logAlpha)
const {
46#ifdef TTK_ENABLE_EIGEN
48#ifdef TTK_ENABLE_OPENMP
49 Eigen::setNbThreads(threadNumber_);
52 if(constraintNumber < 1) {
53 this->printErr(
"Cannot solve Laplace problem with no boundary constraints");
57 using SpMat = Eigen::SparseMatrix<T>;
58 using SpVec = Eigen::SparseVector<T>;
59 using TripletType = Eigen::Triplet<T>;
63 const auto vertexNumber = triangulation.getNumberOfVertices();
64 const auto edgeNumber = triangulation.getNumberOfEdges();
69 switch(solvingMethod) {
70 case SolvingMethodUserType::AUTO:
71 res = findBestSolver(vertexNumber, edgeNumber);
73 case SolvingMethodUserType::CHOLESKY:
74 res = SolvingMethodType::CHOLESKY;
76 case SolvingMethodUserType::ITERATIVE:
77 res = SolvingMethodType::ITERATIVE;
83 auto sm = findSolvingMethod();
84 std::string begMsg{
"Beginning computation... ("};
86 begMsg.append(
"cotan weights, ");
88 begMsg.append(
"discrete laplacian, ");
90 if(sm == SolvingMethodType::ITERATIVE) {
91 begMsg.append(
"iterative method)");
93 begMsg.append(
"Cholesky method)");
99 std::set<SimplexId> uniqueIdentifiersSet;
100 for(
SimplexId i = 0; i < constraintNumber; ++i) {
101 uniqueIdentifiersSet.insert(sources[i]);
105 std::vector<std::pair<SimplexId, T>> idValues{};
107 for(
const auto id : uniqueIdentifiersSet) {
108 for(
SimplexId j = 0; j < constraintNumber; ++j) {
109 if(
id == sources[j]) {
110 idValues.emplace_back(
id, constraints[j]);
117 size_t const uniqueConstraintNumber = idValues.size();
121 if(useCotanWeights) {
122 Laplacian::cotanWeights<T>(lap, *
this, triangulation);
124 Laplacian::discreteLaplacian<T>(lap, *
this, triangulation);
128 SpVec constraintsMat(vertexNumber);
129 for(
const auto &pair : idValues) {
131 constraintsMat.coeffRef(pair.first) = pair.second;
135 SpMat penalty(vertexNumber, vertexNumber);
139 std::vector<TripletType> triplets;
140 triplets.reserve(uniqueConstraintNumber);
141 for(
const auto &pair : idValues) {
142 triplets.emplace_back(TripletType(pair.first, pair.first, alpha));
144#ifndef __clang_analyzer__
145 penalty.setFromTriplets(triplets.begin(), triplets.end());
152 case SolvingMethodType::CHOLESKY:
153 res = solve<SpMat, SpVec, Eigen::SimplicialCholesky<SpMat>>(
154 lap, penalty, constraintsMat, sol);
156 case SolvingMethodType::ITERATIVE:
157 res = solve<SpMat, SpVec,
158 Eigen::ConjugateGradient<SpMat, Eigen::Upper | Eigen::Lower>>(
159 lap, penalty, constraintsMat, sol);
163 auto info =
static_cast<Eigen::ComputationInfo
>(res);
165 case Eigen::ComputationInfo::NumericalIssue:
168 case Eigen::ComputationInfo::NoConvergence:
171 case Eigen::ComputationInfo::InvalidInput:
179 Eigen::Matrix<T, Eigen::Dynamic, 1> solDense(sol);
182#ifdef TTK_ENABLE_OPENMP
183#pragma omp parallel for num_threads(threadNumber_)
185 for(
SimplexId i = 0; i < vertexNumber; ++i) {
187 outputScalarField[i] = -solDense(i, 0);
203 std::vector<std::string>{
204 "Eigen support disabled, computation skipped!",
205 "Please re-compile TTK with Eigen support to enable this feature."},
int execute(const TriangulationType &triangulation, const SimplexId constraintNumber, const SimplexId *const sources, const T *const constraints, T *const outputScalarField, const bool useCotanWeights=true, const SolvingMethodUserType solvingMethod=SolvingMethodUserType::AUTO, const double logAlpha=5.0) const