83 const std::vector<Real>& vsetIn,
const Real L[3],
int N,
int sw,
84 const Sdf& sdf,
int maxNewton, Real tol, Real reg = Real(1e-6),
85 Real damp = Real(1),
bool verbose =
false) {
86 using peclet::core::Index;
87 using peclet::core::MemSpace;
88 using MView = peclet::core::View<double>;
89 const Real Larr[3] = {L[0], L[1], L[2]};
91 Kokkos::View<Real*, MemSpace> dpos(
"ot.pos", 3 * N), dw(
"ot.w", N);
92 Kokkos::deep_copy(dpos, Kokkos::View<const Real*, Kokkos::HostSpace>(pos.data(), 3 * N));
93 Kokkos::View<long*, MemSpace> gd;
95 peclet::core::solver::MomentumSolver solver;
96 solver.setJacobi(2, 0.7);
99 for (
int i = 0; i < N; ++i)
100 sumVset += vsetIn[i];
104 auto evaluate = [&](
const std::vector<Real>& wv, std::vector<double>& vol,
double& maxErr,
105 double& meanErr,
double& resL2,
long& nEmpty,
double& scale) {
106 Kokkos::deep_copy(dw, Kokkos::View<const Real*, Kokkos::HostSpace>(wv.data(), N));
107 auto res = buildTessellation<Real, true, Sdf>(dpos, dw, N, Larr, sw, N, gd, sdf,
112 for (
int i = 0; i < N; ++i) {
117 scale = (sumVset > 0) ? sumV / sumVset : 1.0;
121 for (
int i = 0; i < N; ++i) {
122 const double e = std::fabs(vol[i] - vsetIn[i] * scale);
123 maxErr = std::max(maxErr, e);
128 resL2 = std::sqrt(s2);
133 std::vector<double> vol;
134 double maxErr, meanErr, resL2, scale;
136 auto res = evaluate(weight, vol, maxErr, meanErr, resL2, nEmpty, scale);
138 for (
int it = 0; it < maxNewton; ++it) {
144 std::printf(
" [ot] iter %2d maxVolErr=%.3e meanVolErr=%.3e nEmpty=%ld\n", it, maxErr,
157 const int nFacets = (int)nbr.size();
158 std::vector<double> diag(N, 0.0), coef, r(N);
159 std::vector<Index> start(N + 1, 0), fnbr;
160 coef.reserve(nFacets);
161 fnbr.reserve(nFacets);
163 for (
int i = 0; i < N; ++i) {
164 start[i] = (Index)fnbr.size();
165 const int fend = off[i] + cnt[i];
166 for (
int f = off[i]; f < fend && f < nFacets; ++f) {
167 const long j = (long)nbr[f];
170 const double Aij = std::sqrt(area[3 * f] * area[3 * f] + area[3 * f + 1] * area[3 * f + 1] +
171 area[3 * f + 2] * area[3 * f + 2]);
172 const double dij = std::sqrt(conn[3 * f] * conn[3 * f] + conn[3 * f + 1] * conn[3 * f + 1] +
173 conn[3 * f + 2] * conn[3 * f + 2]);
174 if (dij <= 0.0 || Aij <= 0.0)
176 const double w = Aij / (2.0 * dij);
179 fnbr.push_back((Index)j);
183 start[N] = (Index)fnbr.size();
185 if (verbose && it == 0) {
189 for (
int f = off[c]; f < off[c] + cnt[c] && f < nFacets; ++f) {
190 const long j = (long)nbr[f];
193 const double Aij = std::sqrt(area[3 * f] * area[3 * f] + area[3 * f + 1] * area[3 * f + 1] +
194 area[3 * f + 2] * area[3 * f + 2]);
195 const double dij = std::sqrt(conn[3 * f] * conn[3 * f] + conn[3 * f + 1] * conn[3 * f + 1] +
196 conn[3 * f + 2] * conn[3 * f + 2]);
198 Acf = -Aij / (2 * dij);
202 const double dd = 1e-6;
203 std::vector<Real> wp = weight;
205 std::vector<double> vp;
208 evaluate(wp, vp, a, b, cq, ne, sq);
209 const double fd = (vp[c] - vol[c]) / dd;
210 std::printf(
" FD dV_%d/dw_%ld: analytic=%.4e fd=%.4e (dV_c/dw_c analytic=%.4e)\n", c,
211 jn, Acf, fd, diag[c]);
215 const double eps = reg * (sumDiag / N);
216 for (
int i = 0; i < N; ++i) {
218 r[i] = vsetIn[i] * scale - vol[i];
223 for (Index f = start[0]; f < start[1]; ++f)
228 peclet::core::solver::MomentumOp op;
230 op.diag = peclet::core::toDevice(diag,
"ot.diag");
231 op.faceStart = peclet::core::toDevice(start,
"ot.start");
232 op.faceNbr = peclet::core::toDevice(fnbr,
"ot.nbr");
233 op.faceCoef = peclet::core::toDevice(coef,
"ot.coef");
234 MView db(
"ot.rhs", N), ddw(
"ot.dw", N);
235 Kokkos::deep_copy(db, Kokkos::View<const double*, Kokkos::HostSpace>(r.data(), N));
236 Kokkos::deep_copy(ddw, 0.0);
237 auto sr = solver.solveBiCGStab(op, ddw, MView(db), 2000, 1e-10);
241 for (
int i = 0; i < N; ++i)
242 dwnorm = std::max(dwnorm, std::fabs(dwv[i]));
243 std::printf(
" solve: %d iters res0=%.2e res=%.2e |dw|inf=%.3e\n", sr.iters, sr.res0,
253 std::vector<Real> wtry(N);
254 std::vector<double> volT;
255 double maxErrT, meanErrT, resL2T, scaleT;
258 auto probe = [&](
double alpha,
double& dd) ->
bool {
259 for (
int i = 0; i < N; ++i)
260 wtry[i] = weight[i] + (Real)(alpha * dwv[i]);
261 resT = evaluate(wtry, volT, maxErrT, meanErrT, resL2T, nEmptyT, scaleT);
263 for (
int i = 0; i < N; ++i)
264 dd += (volT[i] - vsetIn[i] * scaleT) * dwv[i];
268 double aHi = damp, ddHi = 0;
269 bool feasHi = probe(aHi, ddHi);
270 for (
int g = 0; !feasHi && aHi > 1e-6 && g < 40; ++g) {
272 feasHi = probe(aHi, ddHi);
279 for (
int b = 0; b < 24; ++b) {
280 const double aMid = 0.5 * (aLo + aHi);
282 const bool feas = probe(aMid, ddMid);
283 if (feas && ddMid < 0.0)
303 std::printf(
" accepted alpha=%.4f resL2=%.4e\n", aAcc, resL2);