#include #include #include #include #include #include #include #include #include #include "bernstein.hpp" #include "quadrature_multipoly.hpp" #include "binomial.hpp" #include "real.hpp" #include "uvector.hpp" #include "vector" #include "xarray.hpp" #include using namespace algoim; // Driver method which takes a functor phi defining a single polynomial in the reference // rectangle [xmin, xmax]^N, of Bernstein degree P, along with an integrand function, // and performances a q-refinement convergence study, comparing the computed integral // with the given exact answers, for 1 <= q <= qMax. template void qConv1(const Phi& phi, real xmin, real xmax, uvector P, const F& integrand, int qMax, real volume_exact, real surf_exact) { // Construct Bernstein polynomial by mapping [0,1] onto bounding box [xmin,xmax] xarray phipoly(nullptr, P); algoim_spark_alloc(real, phipoly); bernstein::bernsteinInterpolate([&](const uvector& x) { return phi(xmin + x * (xmax - xmin)); }, phipoly); // Build quadrature hierarchy ImplicitPolyQuadrature ipquad(phipoly); // Functional to evaluate volume and surface integrals of given integrand real volume, surf; auto compute = [&](int q) { volume = 0.0; surf = 0.0; // compute volume integral over {phi < 0} using AutoMixed strategy ipquad.integrate(AutoMixed, q, [&](const uvector& x, real w) { if (bernstein::evalBernsteinPoly(phipoly, x) < 0) volume += w * integrand(xmin + x * (xmax - xmin)); }); // compute surface integral over {phi == 0} using AutoMixed strategy ipquad.integrate_surf(AutoMixed, q, [&](const uvector& x, real w, const uvector& wn) { surf += w * integrand(xmin + x * (xmax - xmin)); }); // scale appropriately volume *= pow(xmax - xmin, N); surf *= pow(xmax - xmin, N - 1); }; // Compute results for all q and output in a convergence table for (int q = 1; q <= qMax; ++q) { compute(q); std::cout << q << ' ' << volume << ' ' << surf << ' ' << std::abs(volume - volume_exact) / volume_exact << ' ' << std::abs(surf - surf_exact) / surf_exact << std::endl; } } enum BoolOp { Union, Intersection, Difference }; // Driver method which takes two phi functors defining two polynomials in the reference // rectangle [xmin, xmax]^N, each of of Bernstein degree P, builds a quadrature scheme with the // given q, and outputs it for visualisation in a set of VTP XML files template void qConvMultiPloy(const F1& fphi1, const F2& fphi2, real xmin, real xmax, const uvector& P, const F& integrand, int q, BoolOp op) { // Construct phi by mapping [0,1] onto bounding box [xmin,xmax] xarray phi1(nullptr, P), phi2(nullptr, P); algoim_spark_alloc(real, phi1, phi2); bernstein::bernsteinInterpolate([&](const uvector& x) { return fphi1(xmin + x * (xmax - xmin)); }, phi1); bernstein::bernsteinInterpolate([&](const uvector& x) { return fphi2(xmin + x * (xmax - xmin)); }, phi2); // Build quadrature hierarchy ImplicitPolyQuadrature ipquad(phi1, phi2); // ImplicitPolyQuadrature ipquad(phi1); // Functional to evaluate volume and surface integrals of given integrand real volume, surf; auto compute = [&](int q) { volume = 0.0; surf = 0.0; // compute volume integral over {phi < 0} using AutoMixed strategy ipquad.integrate(AutoMixed, q, [&](const uvector& x, real w) { if (op == Union) { if (bernstein::evalBernsteinPoly(phi1, x) < 0 || bernstein::evalBernsteinPoly(phi2, x) < 0) volume += w * integrand(xmin + x * (xmax - xmin)); } else if (op == Intersection) { if (bernstein::evalBernsteinPoly(phi1, x) < 0 && bernstein::evalBernsteinPoly(phi2, x) < 0) volume += w * integrand(xmin + x * (xmax - xmin)); } else if (op == Difference) { if (bernstein::evalBernsteinPoly(phi1, x) < 0 && bernstein::evalBernsteinPoly(phi2, x) > 0) volume += w * integrand(xmin + x * (xmax - xmin)); } // if (bernstein::evalBernsteinPoly(phi1, x) < 0) volume += w * integrand(xmin + x * (xmax - xmin)); }); // compute surface integral over {phi == 0} using AutoMixed strategy ipquad.integrate_surf(AutoMixed, q, [&](const uvector& x, real w, const uvector& wn) { surf += w * integrand(xmin + x * (xmax - xmin)); }); // scale appropriately volume *= pow(xmax - xmin, N); surf *= pow(xmax - xmin, N - 1); }; compute(q); std::cout << "q volume: " << volume << std::endl; } template void qConvMultiPloy2(real xmin, real xmax, const uvector& P, const F& integrand, int q, std::string qfile) { // Construct phi by mapping [0,1] onto bounding box [xmin,xmax] // bernstein::bernsteinInterpolate([&](const uvector& x) { return fphi1(xmin + x * (xmax - xmin)); }, phi1); // bernstein::bernsteinInterpolate([&](const uvector& x) { return fphi2(xmin + x * (xmax - xmin)); }, phi2); std::vector> phis; // 大量sphere for (int i = 0; i < 100; i++) { real centerX = 1.0 - rand() % 20 / 10.0, centerY = 1.0 - rand() % 20 / 10.0, centerZ = 1.0 - rand() % 20 / 10.0; real r = 0.1 + rand() % 9 / 10.0; auto fphi = [&](const uvector& xx) { real x = xx(0) - centerX; real y = xx(1) - centerY; real z = xx(2) - centerZ; return x * x + y * y + z * z - r * r; }; xarray phi(nullptr, P); algoim_spark_alloc(real, phi); bernstein::bernsteinInterpolate([&](const uvector& x) { return fphi(xmin + x * (xmax - xmin)); }, phi); } auto t = std::chrono::system_clock::now(); ImplicitPolyQuadrature ipquad(phis); // Build quadrature hierarchy // ImplicitPolyQuadrature ipquad(phi1, phi2); // ImplicitPolyQuadrature ipquad(phi1); // Functional to evaluate volume and surface integrals of given integrand real volume, surf; auto compute = [&](int q) { volume = 0.0; surf = 0.0; // compute volume integral over {phi < 0} using AutoMixed strategy ipquad.integrate(AutoMixed, q, [&](const uvector& x, real w) { // if (bernstein::evalBernsteinPoly(phi1, x) < 0 && bernstein::evalBernsteinPoly(phi2, x) < 0) volume += w * // integrand(xmin + x * (xmax - xmin)); if (bernstein::evalBernsteinPoly(phi1, x) < 0) volume += w * integrand(xmin // + x * (xmax - xmin)); volume += w * integrand(xmin + x * (xmax - xmin)); }); // compute surface integral over {phi == 0} using AutoMixed strategy // ipquad.integrate_surf(AutoMixed, q, [&](const uvector& x, real w, const uvector& wn) { // surf += w * integrand(xmin + x * (xmax - xmin)); // }); // scale appropriately volume *= pow(xmax - xmin, N); surf *= pow(xmax - xmin, N - 1); }; compute(q); auto tAfter = std::chrono::system_clock::now(); std::chrono::duration elapsed_seconds = tAfter - t; std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n"; std::cout << "q volume: " << volume << std::endl; } void fromCommon2Bernstein() {} void testMultiPolys() { // Visusalisation of a 2D implicitly-defined domain involving the intersection of two polynomials; this example // corresponds to the top-left example of Figure 15, https://doi.org/10.1016/j.jcp.2021.110720 if (true) { auto phi0 = [](const uvector& xx) { real x = xx(0); real y = xx(1); real z = xx(2); return x * x + y * y + z * z - 1; }; auto phi1 = [](const uvector& xx) { // real x = xx(0); // real y = xx(1); // real z = xx(2); // return x * x + y * y + z * z - 1; real x = xx(0); real y = xx(1); real z = xx(2); return x * y * z; }; // auto phi0 = [](const uvector& xx) { // real x = xx(0) * 2 - 1; // real y = xx(1) * 2 - 1; // return 0.014836540349115947 + 0.7022484024095262 * y + 0.09974561176434385 * y * y // + x * (0.6863910464417281 + 0.03805619999999999 * y - 0.09440658332756446 * y * y) // + x * x * (0.19266932968830816 - 0.2325190091204104 * y + 0.2957473125000001 * y * y); // }; // auto phi1 = [](const uvector& xx) { // real x = xx(0) * 2 - 1; // real y = xx(1) * 2 - 1; // return -0.18792528379702625 + 0.6713882473904913 * y + 0.3778666084723582 * y * y // + x * x * (-0.14480813208127946 + 0.0897755603159206 * y - 0.141199875 * y * y) // + x * (-0.6169311810674598 - 0.19449299999999994 * y - 0.005459163675646665 * y * y); // }; auto integrand = [](const uvector& x) { return 1.0; }; // qConvMultiPloy<3>(phi0, phi1, -1.0, 1.0, 3, integrand, 3, "exampleC"); qConvMultiPloy2<3>(-1.0, 1.0, 3, integrand, 10, "exampleC"); } } template void power2BernsteinTensorProduct(const xarray& phiPower, xarray& phiBernsetin) { for (auto i = phiPower.loop(); ~i; ++i) { // phi.l(i) = powerFactors.l(i); real factorBase = phiPower.l(i); if (factorBase == 0) continue; auto traverseRange = phiPower.ext() - i(); std::vector> decompFactors(N, std::vector(max(traverseRange), 0.)); for (int dim = 0; dim < N; ++dim) { // Sigma size_t nDim = phiPower.ext()(dim) - 1; const real* binomNDim = Binomial::row(nDim); for (int j = i(dim); j <= nDim; ++j) { const real* binomJ = Binomial::row(j); decompFactors[dim][j - i(dim)] = binomJ[i(dim)] / binomNDim[i(dim)]; } } xarray subgrid(nullptr, traverseRange); // algoim_spark_alloc(real, subgrid); for (auto ii = subgrid.loop(); ~ii; ++ii) { real factor = factorBase; for (int dim = 0; dim < N; ++dim) { factor *= decompFactors[dim][ii(dim)]; } phiBernsetin.m(i() + ii()) += factor; } } } template real powerEvaluation(const xarray& phi, const uvector& x) { real res = 0; for (auto i = phi.loop(); ~i; ++i) { real item = phi.l(i); auto exps = i(); for (int dim = 0; dim < N; ++dim) { item *= pow(x(dim), exps(dim)); } res += item; } return res; } auto xarray2StdVector(const xarray& array) { auto ext = array.ext(); std::vector>> v(ext(0), std::vector>(ext(1), std::vector(ext(2), 0))); for (int i = 0; i < ext(0); ++i) { for (int j = 0; j < ext(1); ++j) { for (int k = 0; k < ext(2); ++k) { v[i][j][k] = array.m(uvector(i, j, k)); } } } return v; } template void qConvBernstein(const xarray& phi, real xmin, real xmax, const F& integrand, int q, const std::vector>& halfFaces) { uvector testX(0., 0., 0.5); real testEvalBernstein = bernstein::evalBernsteinPoly(phi, testX); auto vec1 = xarray2StdVector(phi); std::cout << "eval bernstein without interpolation:" << testEvalBernstein << std::endl; // Build quadrature hierarchy ImplicitPolyQuadrature ipquad(phi); // ImplicitPolyQuadrature ipquad(phi1); // Functional to evaluate volume and surface integrals of given integrand real volume; auto compute = [&](int q) { volume = 0.0; // compute volume integral over {phi < 0} using AutoMixed strategy if (!halfFaces.empty()) { ipquad.integrate(AutoMixed, q, [&](const uvector& x, real w) { if (bernstein::evalBernsteinPoly(phi, x) >= 0) return; bool in = true; for (int i = 0; i < halfFaces.size(); ++i) { uvector factors(halfFaces[i][0], halfFaces[i][1], halfFaces[i][2]); if (prod(factors * x) + halfFaces[i][3] < 0) { in = false; break; } } if (in) volume += w * integrand(xmin + x * (xmax - xmin)); }); } else ipquad.integrate(AutoMixed, q, [&](const uvector& x, real w) { if (bernstein::evalBernsteinPoly(phi, x) < 0) volume += w * integrand(xmin + x * (xmax - xmin)); }); // scale appropriately volume *= pow(xmax - xmin, N); }; compute(q); std::cout << "q volume: " << volume << std::endl; } template void xarrayInit(xarray& arr) { for (auto i = arr.loop(); ~i; ++i) { arr.l(i) = 0; } } void testSpherePowerDirectly() { // a_x(x-c_x)^2 + a_y(y-c_y)^2 + a_z(x-c_z)^2 - r^2 uvector xmin = -1, xmax = 1; uvector range = xmax - xmin; assert(all(range != 0)); // uvector k = 1 / range; // uvector bias = -k * xmin; uvector k = range; uvector bias = xmin; real a[3] = {1, 1, 1}; real c[3] = {0, 0, 0}; real r = 1; uvector ext = 3; xarray phiPower(nullptr, ext), phiBernstein(nullptr, ext); algoim_spark_alloc(real, phiPower, phiBernstein); xarrayInit(phiPower); xarrayInit(phiBernstein); auto v = xarray2StdVector(phiPower); auto vv = xarray2StdVector(phiBernstein); for (int dim = 0; dim < 3; ++dim) { uvector idx = 0; phiPower.m(idx) += a[dim] * (bias(dim) - c[dim]) * (bias(dim) - c[dim]); idx(dim) = 1; phiPower.m(idx) = 2 * a[dim] * k(dim) * (bias(dim) - c[dim]); idx(dim) = 2; phiPower.m(idx) = a[dim] * k(dim) * k(dim); } phiPower.m(0) -= r * r; auto integrand = [](const uvector& x) { return 1.0; }; power2BernsteinTensorProduct(phiPower, phiBernstein); v = xarray2StdVector(phiPower); uvector testX(0., 0., 0.5); real testEval = powerEvaluation(phiPower, testX); std::cout << "eval power:" << testEval << std::endl; real testEvalBernstein = bernstein::evalBernsteinPoly(phiBernstein, testX); auto vec = xarray2StdVector(phiBernstein); std::cout << "eval bernstein:" << testEval << std::endl; qConvBernstein(phiBernstein, -1, 1, integrand, 10, {}); } void testCylinderPowerDirectly() { // a_x(x-c_x)^2 + a_y(y-c_y)^2 + a_z(x-c_z)^2 - r^2 uvector xmin = -1, xmax = 1; uvector range = xmax - xmin; assert(all(range != 0)); // uvector k = 1 / range; // uvector bias = -k * xmin; uvector k = range; uvector bias = xmin; real c[3] = {0, 0, 0}; real r = 1, h = 1; uvector ext = 3; xarray phiPower(nullptr, ext), phiBernstein(nullptr, ext); algoim_spark_alloc(real, phiPower, phiBernstein); xarrayInit(phiPower); xarrayInit(phiBernstein); auto v = xarray2StdVector(phiPower); auto vv = xarray2StdVector(phiBernstein); real top = c[2] + h * 0.5, bottom = c[2] - h * 0.5; phiPower.m(uvector(2, 0, 2)) = -1; phiPower.m(uvector(0, 2, 2)) = -1; phiPower.m(uvector(0, 0, 2)) = r * r; phiPower.m(uvector(2, 0, 1)) = top + bottom; phiPower.m(uvector(0, 2, 1)) = top + bottom; phiPower.m(uvector(0, 0, 1)) = -(bottom + top) * r * r; phiPower.m(uvector(1, 0, 0)) = -bottom * top; phiPower.m(uvector(0, 1, 0)) = -bottom * top; phiPower.m(uvector(0, 0, 0)) = bottom * top * r * r; auto integrand = [](const uvector& x) { return 1.0; }; power2BernsteinTensorProduct(phiPower, phiBernstein); v = xarray2StdVector(phiPower); uvector testX(0., 0., 0.5); real testEval = powerEvaluation(phiPower, testX); std::cout << "eval power:" << testEval << std::endl; real testEvalBernstein = bernstein::evalBernsteinPoly(phiBernstein, testX); auto vec = xarray2StdVector(phiBernstein); std::cout << "eval bernstein:" << testEval << std::endl; qConvBernstein(phiBernstein, -1, 1, integrand, 50, { {0, 0, 1, -bottom}, {0, 0, -1, top } }); } void testMultiScale() { auto phi0 = [](const uvector& xx) { real x = xx(0) + 100000.; real y = xx(1); real z = xx(2) - 100000.; real r = 800000.; return x * x + y * y + z * z - r * r; }; auto phi1 = [](const uvector& xx) { // real x = xx(0); // real y = xx(1); // real z = xx(2); // return x * x + y * y + z * z - 1; real x = xx(0) + 100000.; real y = xx(1) - 800000.; real z = xx(2) - 100000.; real r = 1000.; return x * x + y * y + z * z - r * r; }; auto integrand = [](const uvector& x) { return 1.0; }; qConvMultiPloy<3>(phi0, phi1, -1000000., 1000000., 3, integrand, 20, Difference); } void testBitSet() { std::bitset<10> set(128); set.set(); std::cout << set << std::endl; } void testBooluarray() { algoim::booluarray<2, 3> tmp; tmp(0) = true; tmp(1) = true; tmp(2) = true; std::cout << tmp.bits << std::endl; } void testMain() { testBooluarray(); testMultiPolys(); testMultiScale(); testSpherePowerDirectly(); // testCylinderPowerDirectly(); }