Browse Source

tests for multi-scale and direct basis conversion

master
gjj 8 months ago
parent
commit
8b464894b8
  1. 1754
      algoim/bernstein.hpp
  2. 59
      examples/examples_quad_multipoly.cpp
  3. 35
      gjj/analyticSolution.py
  4. 313
      gjj/myDebug.hpp

1754
algoim/bernstein.hpp

File diff suppressed because it is too large

59
examples/examples_quad_multipoly.cpp

@ -118,6 +118,52 @@ void qConv(const Phi& phi,
}
}
template <typename Phi, typename F>
void debug3D(const Phi& phi,
real xmin,
real xmax,
uvector<int, 3> P,
const F& integrand,
int q,
real volume_exact,
real surf_exact)
{
// Construct Bernstein polynomial by mapping [0,1] onto bounding box [xmin,xmax]
xarray<real, 3> phipoly(nullptr, P);
algoim_spark_alloc(real, phipoly);
bernstein::bernsteinInterpolate<3>([&](const uvector<real, 3>& x) { return phi(xmin + x * (xmax - xmin)); }, phipoly);
DebugXArray<3>()(phipoly, [&](const uvector<real, 3>& x) { return phi(xmin + x * (xmax - xmin)); });
uvector<real, 3> testX(0., 0., 0.5);
real testEvalBernstein = bernstein::evalBernsteinPoly(phipoly, testX);
std::cout << "eval bernstein using interpolation:" << testEvalBernstein << std::endl;
// Build quadrature hierarchy
ImplicitPolyQuadrature<3> 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<real, 3>& 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<real, 3>& x, real w, const uvector<real, 3>& wn) {
surf += w * integrand(xmin + x * (xmax - xmin));
});
// scale appropriately
volume *= pow(xmax - xmin, 3);
surf *= pow(xmax - xmin, 3 - 1);
};
// Compute results for all q and output in a convergence table
compute(q);
std::cout << "volume: " << volume << std::endl;
}
// Given a set of quadrature points and weights, output them to an VTP XML file for visualisation
// purposes, e.g., using ParaView
template <int N>
@ -252,7 +298,7 @@ int main(int argc, char* argv[])
std::cout << std::scientific << std::setprecision(10);
// q-convergence study for a 2D ellipse
if (true) {
if (false) {
auto ellipse = [](const uvector<real, 2>& x) { return x(0) * x(0) + x(1) * x(1) * 4 - 1; };
auto integrand = [](const uvector<real, 2>& x) { return 1.0; };
real volume_exact = algoim::util::pi / 2;
@ -338,6 +384,17 @@ int main(int argc, char* argv[])
std::cout << "(XML VTP file format).\n";
}
// a 3D sphere
if (true) {
auto ellipsoid = [](const uvector<real, 3>& x) { return x(0) * x(0) + x(1) * x(1) + x(2) * x(2) - 1; };
auto integrand = [](const uvector<real, 3>& x) { return 1.0; };
real volume_exact = (algoim::util::pi * 2) / 9;
real surf_exact = 4.400809564664970341600200389229705943483674323377145800356686868037845;
std::cout << "\n\nEllipsoid q-convergence test\n";
std::cout << "q volume(q) surf(q) vol error surf error\n";
debug3D(ellipsoid, -1., 1., 3, integrand, 10, volume_exact, surf_exact);
}
// module_test();
testMain();

35
gjj/analyticSolution.py

@ -0,0 +1,35 @@
import math
class Sphere:
def __init__(self, radius, center):
self.radius = radius
self.center = center
# specify class for the input parameters
def caseSpheresBOnAFace(rA, rB):
#intersection:
rAsq = rA**2
rBsq = rB**2
crownHeightA = rBsq / (2 * rA)
crownHeightB = rB - crownHeightA
crownVolumeA = math.pi * crownHeightA**2 * (3 * rA - crownHeightA) / 3
crownVolumeB = math.pi * crownHeightB**2 * (3 * rB - crownHeightB) / 3
volumeInter = crownVolumeA + crownVolumeB
#union:
volumeA = 4/3 * math.pi * rAsq * rA
volumeB = 4/3 * math.pi * rBsq * rB
volumeUnion = volumeA + volumeB - volumeInter
#difference:
volumeDiff = volumeA - volumeInter
return volumeInter, volumeUnion, volumeDiff
if __name__=="__main__":
volumeInter, volumeUnion, volumeDiff = caseSpheresBOnAFace(800000, 1000)
print("volumeInter = ", volumeInter)
print("volumeUnion = ", volumeUnion)
print("volumeDiff = ", volumeDiff)

313
gjj/myDebug.hpp

@ -1,3 +1,4 @@
#include <array>
#include <bitset>
#include <iostream>
#include <booluarray.hpp>
@ -10,12 +11,13 @@
#include <vector>
#include "bernstein.hpp"
#include "quadrature_multipoly.hpp"
#include "binomial.hpp"
#include "real.hpp"
#include "uvector.hpp"
#include "vector"
#include "xarray.hpp"
#include<chrono>
#include <chrono>
using namespace algoim;
@ -68,6 +70,8 @@ void qConv1(const Phi& phi,
}
}
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
@ -79,13 +83,13 @@ void qConvMultiPloy(const F1& fphi1,
const uvector<int, N>& P,
const F& integrand,
int q,
std::string qfile)
BoolOp op)
{
// Construct phi by mapping [0,1] onto bounding box [xmin,xmax]
xarray<real, N> phi1(nullptr, P), phi2(nullptr, P);
algoim_spark_alloc(real, phi1, phi2);
bernstein::bernsteinInterpolate<N>([&](const uvector<real, N>& x) { return fphi1(xmin + x * (xmax - xmin)); }, phi1);
// bernstein::bernsteinInterpolate<N>([&](const uvector<real, N>& x) { return fphi2(xmin + x * (xmax - xmin)); }, phi2);
bernstein::bernsteinInterpolate<N>([&](const uvector<real, N>& x) { return fphi2(xmin + x * (xmax - xmin)); }, phi2);
// Build quadrature hierarchy
ImplicitPolyQuadrature<N> ipquad(phi1, phi2);
@ -98,7 +102,16 @@ void qConvMultiPloy(const F1& fphi1,
surf = 0.0;
// compute volume integral over {phi < 0} using AutoMixed strategy
ipquad.integrate(AutoMixed, q, [&](const uvector<real, N>& x, real w) {
if (bernstein::evalBernsteinPoly(phi1, x) < 0 && bernstein::evalBernsteinPoly(phi2, x) < 0) volume += w * integrand(xmin + x * (xmax - xmin));
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
@ -114,37 +127,30 @@ void qConvMultiPloy(const F1& fphi1,
}
template <int N, typename F>
void qConvMultiPloy2(
real xmin,
real xmax,
const uvector<int, N>& P,
const F& integrand,
int q,
std::string qfile)
void qConvMultiPloy2(real xmin, real xmax, const uvector<int, N>& P, const F& integrand, int q, std::string qfile)
{
// Construct phi by mapping [0,1] onto bounding box [xmin,xmax]
// bernstein::bernsteinInterpolate<N>([&](const uvector<real, N>& x) { return fphi1(xmin + x * (xmax - xmin)); }, phi1);
// bernstein::bernsteinInterpolate<N>([&](const uvector<real, N>& x) { return fphi2(xmin + x * (xmax - xmin)); }, phi2);
std::vector<xarray<real, N>> 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<real, 3>& xx) {
real x = xx(0) - centerX;
real y = xx(1) - centerY;
real z = xx(2) - centerZ;
return x * x + y * y + z * z - 1;
};
xarray<real, N> phi(nullptr, P);
algoim_spark_alloc(real, phi);
bernstein::bernsteinInterpolate<N>([&](const uvector<real, N>& x) { return fphi(xmin + x * (xmax - xmin)); }, phi);
}
auto t = std::chrono::system_clock::now();
ImplicitPolyQuadrature<N> ipquad(phis);
std::vector<xarray<real, N>> 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<real, 3>& 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<real, N> phi(nullptr, P);
algoim_spark_alloc(real, phi);
bernstein::bernsteinInterpolate<N>([&](const uvector<real, N>& x) { return fphi(xmin + x * (xmax - xmin)); }, phi);
}
auto t = std::chrono::system_clock::now();
ImplicitPolyQuadrature<N> ipquad(phis);
// Build quadrature hierarchy
@ -158,9 +164,10 @@ void qConvMultiPloy2(
surf = 0.0;
// compute volume integral over {phi < 0} using AutoMixed strategy
ipquad.integrate(AutoMixed, q, [&](const uvector<real, N>& 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));
// 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<real, N>& x, real w, const uvector<real, N>& wn) {
@ -172,15 +179,13 @@ void qConvMultiPloy2(
};
compute(q);
auto tAfter = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = tAfter - t;
std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";
auto tAfter = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = tAfter - t;
std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";
std::cout << "q volume: " << volume << std::endl;
}
void fromCommon2Bernstein() {
}
void fromCommon2Bernstein() {}
void testMultiPolys()
{
@ -219,12 +224,233 @@ void testMultiPolys()
// };
auto integrand = [](const uvector<real, 3>& x) { return 1.0; };
// qConvMultiPloy<3>(phi0, phi1, -1.0, 1.0, 3, integrand, 3, "exampleC");
qConvMultiPloy2<3>(-1.0, 1.0, 3, integrand, 20, "exampleC");
std::cout << "\n\nQuadrature visualisation of a 2D implicitly-defined domain involving the\n";
std::cout << "intersection of two polynomials, corresponding to the top-left example of Figure 15,\n";
std::cout << "https://doi.org/10.1016/j.jcp.2021.110720, written to exampleC-xxxx.vtp files\n";
std::cout << "(XML VTP file format).\n";
qConvMultiPloy2<3>(-1.0, 1.0, 3, integrand, 10, "exampleC");
}
}
template <int N>
void power2BernsteinTensorProduct(const xarray<real, N>& phiPower, xarray<real, N>& 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<std::vector<real>> decompFactors(N, std::vector<real>(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<real, N> 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 <int N>
real powerEvaluation(const xarray<real, N>& phi, const uvector<real, N>& 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<real, 3>& array)
{
auto ext = array.ext();
std::vector<std::vector<std::vector<real>>> v(ext(0), std::vector<std::vector<real>>(ext(1), std::vector<real>(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<int, 3>(i, j, k)); }
}
}
return v;
}
template <int N, typename F>
void qConvBernstein(const xarray<real, N>& phi,
real xmin,
real xmax,
const F& integrand,
int q,
const std::vector<std::array<real, 4>>& halfFaces)
{
uvector<real, 3> 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<N> ipquad(phi);
// ImplicitPolyQuadrature<N> 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<real, N>& x, real w) {
if (bernstein::evalBernsteinPoly(phi, x) >= 0) return;
bool in = true;
for (int i = 0; i < halfFaces.size(); ++i) {
uvector<real, 3> 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<real, N>& 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 <typename T, int N>
void xarrayInit(xarray<T, N>& 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<real, 3> xmin = -1, xmax = 1;
uvector<real, 3> range = xmax - xmin;
assert(all(range != 0));
// uvector<real, 3> k = 1 / range;
// uvector<real, 3> bias = -k * xmin;
uvector<real, 3> k = range;
uvector<real, 3> bias = xmin;
real a[3] = {1, 1, 1};
real c[3] = {0, 0, 0};
real r = 1;
uvector<int, 3> ext = 3;
xarray<real, 3> 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<int, 3> 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<real, 3>& x) { return 1.0; };
power2BernsteinTensorProduct(phiPower, phiBernstein);
v = xarray2StdVector(phiPower);
uvector<real, 3> 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<real, 3> xmin = -1, xmax = 1;
uvector<real, 3> range = xmax - xmin;
assert(all(range != 0));
// uvector<real, 3> k = 1 / range;
// uvector<real, 3> bias = -k * xmin;
uvector<real, 3> k = range;
uvector<real, 3> bias = xmin;
real c[3] = {0, 0, 0};
real r = 1, h = 1;
uvector<int, 3> ext = 3;
xarray<real, 3> 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<int, 3>(2, 0, 2)) = -1;
phiPower.m(uvector<int, 3>(0, 2, 2)) = -1;
phiPower.m(uvector<int, 3>(0, 0, 2)) = r * r;
phiPower.m(uvector<int, 3>(2, 0, 1)) = top + bottom;
phiPower.m(uvector<int, 3>(0, 2, 1)) = top + bottom;
phiPower.m(uvector<int, 3>(0, 0, 1)) = -(bottom + top) * r * r;
phiPower.m(uvector<int, 3>(1, 0, 0)) = -bottom * top;
phiPower.m(uvector<int, 3>(0, 1, 0)) = -bottom * top;
phiPower.m(uvector<int, 3>(0, 0, 0)) = bottom * top * r * r;
auto integrand = [](const uvector<real, 3>& x) { return 1.0; };
power2BernsteinTensorProduct(phiPower, phiBernstein);
v = xarray2StdVector(phiPower);
uvector<real, 3> 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<real, 3>& 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<real, 3>& 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<real, 3>& x) { return 1.0; };
qConvMultiPloy<3>(phi0, phi1, -1000000., 1000000., 3, integrand, 20, Difference);
}
void testBitSet()
@ -247,4 +473,7 @@ void testMain()
{
testBooluarray();
testMultiPolys();
testMultiScale();
testSpherePowerDirectly();
// testCylinderPowerDirectly();
}

Loading…
Cancel
Save