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::amr::MomentumSolver<21> solver;
96 solver.setJacobi(2, 0.7);
99 for (
int i = 0; i < N; ++i) sumVset += vsetIn[i];
103 auto evaluate = [&](
const std::vector<Real>& wv, std::vector<double>& vol,
double& maxErr,
104 double& meanErr,
double& resL2,
long& nEmpty,
double& scale) {
105 Kokkos::deep_copy(dw, Kokkos::View<const Real*, Kokkos::HostSpace>(wv.data(), N));
106 auto res = buildTessellation<Real, true, Sdf>(dpos, dw, N, Larr, sw, N, gd, sdf,
111 for (
int i = 0; i < N; ++i) {
113 if (vol[i] <= 0.0) ++nEmpty;
115 scale = (sumVset > 0) ? sumV / sumVset : 1.0;
119 for (
int i = 0; i < N; ++i) {
120 const double e = std::fabs(vol[i] - vsetIn[i] * scale);
121 maxErr = std::max(maxErr, e);
126 resL2 = std::sqrt(s2);
131 std::vector<double> vol;
132 double maxErr, meanErr, resL2, scale;
134 auto res = evaluate(weight, vol, maxErr, meanErr, resL2, nEmpty, scale);
136 for (
int it = 0; it < maxNewton; ++it) {
142 std::printf(
" [ot] iter %2d maxVolErr=%.3e meanVolErr=%.3e nEmpty=%ld\n", it, maxErr, meanErr,
155 const int nFacets = (int)nbr.size();
156 std::vector<double> diag(N, 0.0), coef, r(N);
157 std::vector<Index> start(N + 1, 0), fnbr;
158 coef.reserve(nFacets);
159 fnbr.reserve(nFacets);
161 for (
int i = 0; i < N; ++i) {
162 start[i] = (Index)fnbr.size();
163 const int fend = off[i] + cnt[i];
164 for (
int f = off[i]; f < fend && f < nFacets; ++f) {
165 const long j = (long)nbr[f];
166 if (j < 0 || j >= N)
continue;
167 const double Aij = std::sqrt(area[3 * f] * area[3 * f] + area[3 * f + 1] * area[3 * f + 1] +
168 area[3 * f + 2] * area[3 * f + 2]);
169 const double dij = std::sqrt(conn[3 * f] * conn[3 * f] + conn[3 * f + 1] * conn[3 * f + 1] +
170 conn[3 * f + 2] * conn[3 * f + 2]);
171 if (dij <= 0.0 || Aij <= 0.0)
continue;
172 const double w = Aij / (2.0 * dij);
175 fnbr.push_back((Index)j);
179 start[N] = (Index)fnbr.size();
181 if (verbose && it == 0) {
185 for (
int f = off[c]; f < off[c] + cnt[c] && f < nFacets; ++f) {
186 const long j = (long)nbr[f];
187 if (j < 0 || j >= N)
continue;
188 const double Aij = std::sqrt(area[3 * f] * area[3 * f] + area[3 * f + 1] * area[3 * f + 1] +
189 area[3 * f + 2] * area[3 * f + 2]);
190 const double dij = std::sqrt(conn[3 * f] * conn[3 * f] + conn[3 * f + 1] * conn[3 * f + 1] +
191 conn[3 * f + 2] * conn[3 * f + 2]);
193 Acf = -Aij / (2 * dij);
197 const double dd = 1e-6;
198 std::vector<Real> wp = weight;
200 std::vector<double> vp;
203 evaluate(wp, vp, a, b, cq, ne, sq);
204 const double fd = (vp[c] - vol[c]) / dd;
205 std::printf(
" FD dV_%d/dw_%ld: analytic=%.4e fd=%.4e (dV_c/dw_c analytic=%.4e)\n", c,
206 jn, Acf, fd, diag[c]);
210 const double eps = reg * (sumDiag / N);
211 for (
int i = 0; i < N; ++i) {
213 r[i] = vsetIn[i] * scale - vol[i];
218 for (Index f = start[0]; f < start[1]; ++f) coef[f] = 0.0;
222 peclet::core::amr::MomentumOp op;
224 op.diag = peclet::core::toDevice(diag,
"ot.diag");
225 op.faceStart = peclet::core::toDevice(start,
"ot.start");
226 op.faceNbr = peclet::core::toDevice(fnbr,
"ot.nbr");
227 op.faceCoef = peclet::core::toDevice(coef,
"ot.coef");
228 MView db(
"ot.rhs", N), ddw(
"ot.dw", N);
229 Kokkos::deep_copy(db, Kokkos::View<const double*, Kokkos::HostSpace>(r.data(), N));
230 Kokkos::deep_copy(ddw, 0.0);
231 auto sr = solver.solveBiCGStab(op, ddw, MView(db), 2000, 1e-10);
235 for (
int i = 0; i < N; ++i) dwnorm = std::max(dwnorm, std::fabs(dwv[i]));
236 std::printf(
" solve: %d iters res0=%.2e res=%.2e |dw|inf=%.3e\n", sr.iters, sr.res0,
245 std::vector<Real> wtry(N);
246 std::vector<double> volT;
247 double maxErrT, meanErrT, resL2T, scaleT;
250 auto probe = [&](
double alpha,
double& dd) ->
bool {
251 for (
int i = 0; i < N; ++i) wtry[i] = weight[i] + (Real)(alpha * dwv[i]);
252 resT = evaluate(wtry, volT, maxErrT, meanErrT, resL2T, nEmptyT, scaleT);
254 for (
int i = 0; i < N; ++i) dd += (volT[i] - vsetIn[i] * scaleT) * dwv[i];
258 double aHi = damp, ddHi = 0;
259 bool feasHi = probe(aHi, ddHi);
260 for (
int g = 0; !feasHi && aHi > 1e-6 && g < 40; ++g) {
262 feasHi = probe(aHi, ddHi);
268 for (
int b = 0; b < 24; ++b) {
269 const double aMid = 0.5 * (aLo + aHi);
271 const bool feas = probe(aMid, ddMid);
272 if (feas && ddMid < 0.0)
279 if (aAcc <= 0.0)
break;
290 if (verbose) std::printf(
" accepted alpha=%.4f resL2=%.4e\n", aAcc, resL2);