#include #include #include #include #include #include #include #include #include #include #include "bernstein.hpp" #include "multiloop.hpp" #include "quadrature_multipoly.hpp" #include "binomial.hpp" #include "real.hpp" #include "sparkstack.hpp" #include "uvector.hpp" #include "vector" #include "xarray.hpp" #include #include #include #include "organizer/primitive.hpp" namespace algoim::Organizer { namespace detail { void bernstein2PowerTensor(const tensor3& phiBernstein, tensor3& phiPower) {} } // namespace detail bool keepQuadraturePoint(std::vector& originTensors, const uvector3& originPt) { // TODO: using blobtree to filter tensors for (auto& t : originTensors) { if (evalPower(t, originPt) >= 0) { return false; } } return true; } // std::vector> primitives; // BasicTask(std::vector> ps) {}; void restrictToInnerFace(const tensor3& phi, int k, real facePos, tensor2& res) { assert(0 <= k && k < 3); assert(all(res.ext() == remove_component(phi.ext(), k))); assert(0 < facePos && facePos < 1); real* basisAlongK; int P = phi.ext(k); algoim_spark_alloc(real, &basisAlongK, P); bernstein::evalBernsteinBasis(facePos, P, basisAlongK); for (auto i = res.loop(); ~i; ++i) { real evalAlongKAtFacePos = 0; for (int j = 0; j < P; ++j) { evalAlongKAtFacePos += basisAlongK[j] * phi.m(add_component(i(), k, j)); } res.l(i) = evalAlongKAtFacePos; } } void basicTask(const std::shared_ptr& p, int q = 20, real xmin = -1, real xmax = 1) { real volume = 0; auto integrand = [](const uvector& x) { return 1.0; }; uvector3 range = xmax - xmin; if (auto pt = std::dynamic_pointer_cast(p)) { tensor3 tensor(nullptr, 3); algoim_spark_alloc(real, tensor); makeSphere(*pt, tensor); detail::powerTransformation(range, xmin, tensor); tensor3 phi(nullptr, 3); algoim_spark_alloc(real, phi); detail::power2BernsteinTensor(tensor, phi); uvector testX(0., 0., 0.25); real testEvalBernstein = bernstein::evalBernsteinPoly(phi, testX); // auto vec1 = xarray2StdVector(phi); std::cout << "eval bernstein without interpolation:" << testEvalBernstein << std::endl; ImplicitPolyQuadrature<3> ipquad(phi); ipquad.integrate(AutoMixed, q, [&](const uvector& x, real w) { if (isInsideBernstein(phi, x)) volume += w * integrand(xmin + x * (xmax - xmin)); }); } else if (auto pt = std::dynamic_pointer_cast(p)) { const int faceCount = pt->indexInclusiveScan.size(); assert(faceCount > 1); std::vector planeTensors(faceCount, tensor3(nullptr, 2)); algoim_spark_alloc(real, planeTensors); tensor3 compositeTensor(nullptr, 1 + faceCount); algoim_spark_alloc(real, compositeTensor); makeMesh(*pt, compositeTensor, planeTensors); detail::powerTransformation(range, xmin, compositeTensor); auto planeStdVector1 = xarray2StdVector(planeTensors[0]); auto planeStdVector2 = xarray2StdVector(planeTensors[1]); auto compositeTensorStdVector = xarray2StdVector(compositeTensor); uvector testX(0., 0.75, 0.2); real textEvalPower = evalPower(compositeTensor, testX); tensor3 phi(nullptr, 1 + faceCount); algoim_spark_alloc(real, phi); detail::power2BernsteinTensor(compositeTensor, phi); int quadraturePointCount = 0; ImplicitPolyQuadrature<3> ipquad(phi); real testEvalBernstein = bernstein::evalBernsteinPoly(phi, testX); ipquad.integrate(AutoMixed, q, [&](const uvector& x, real w) { quadraturePointCount++; auto realX = x * range + xmin; if (isInsidePowers(planeTensors, realX)) volume += w * integrand(realX); }); std::cout << "textEvalPower: " << textEvalPower << std::endl; std::cout << "quadraturePointCount: " << quadraturePointCount << std::endl; } volume *= pow(xmax - xmin, 3); std::cout << "Volume xxx: " << volume << std::endl; }; void basicTask(const std::vector>& primitives, int q = 20, real xmin = -1, real xmax = 1) { std::vector*> phiStacks; std::vector phis; std::vector*> originTensorStacks; std::vector originTensors; real volume; auto integrand = [](const uvector& x) { return 1.0; }; uvector3 range = xmax - xmin; uvector testX(0., 0.75, 0.2); for (int i = 0; i < primitives.size(); i++) { if (auto pt = std::dynamic_pointer_cast(primitives[i])) { tensor3 originTensor(nullptr, 3), transformedTensor(nullptr, 3); originTensorStacks.emplace_back(algoim_spark_alloc_heap(real, originTensor)); // 记录,用以最后bool tensor3 phi(nullptr, 3); phiStacks.emplace_back( algoim_spark_alloc_heap(real, phi)); // 必须先于algoim_spark_alloc,使transformedTensor的内存以栈形式释放 algoim_spark_alloc(real, transformedTensor); makeSphere(*pt, originTensor); originTensors.emplace_back(originTensor); detail::powerTransformation(range, xmin, originTensor, transformedTensor); detail::power2BernsteinTensor(transformedTensor, phi); phis.emplace_back(phi); } else if (auto pt = std::dynamic_pointer_cast(primitives[i])) { const int faceCount = pt->indexInclusiveScan.size(); assert(faceCount > 1); std::vector planeTensors(faceCount, tensor3(nullptr, 2)); algoimSparkAllocHeapVector(originTensorStacks, planeTensors); tensor3 phi(nullptr, 1 + faceCount); phiStacks.emplace_back( algoim_spark_alloc_heap(real, phi)); // 必须先于algoim_spark_alloc,使compositeTensor的内存以栈形式释放 tensor3 compositeTensor(nullptr, 1 + faceCount); algoim_spark_alloc(real, compositeTensor); makeMesh(*pt, compositeTensor, planeTensors); detail::powerTransformation(range, xmin, compositeTensor); real testEvalPower = evalPower(compositeTensor, testX); originTensors.insert(originTensors.end(), planeTensors.begin(), planeTensors.end()); detail::power2BernsteinTensor(compositeTensor, phi); real testEvalBernstein = bernstein::evalBernsteinPoly(phi, testX); phis.emplace_back(phi); } } real testEvalBernstein = bernstein::evalBernsteinPoly(phis[0], testX); ImplicitPolyQuadrature<3> ipquad(phis); ipquad.integrate(AutoMixed, q, [&](const uvector& x, real w) { auto realX = x * range + xmin; if (keepQuadraturePoint(originTensors, realX)) volume += w * integrand(realX); }); volume *= pow(xmax - xmin, 3); std::cout << "Volume xxx: " << volume << std::endl; // free memory, thus deallocate memory of xarray for (auto& p : phiStacks) delete p; for (auto& p : originTensorStacks) delete p; }; void quadratureTask(const Scene& scene) {} void buildOctree(const Scene& scene, std::vector& nodes, const uvector3& min, const uvector3& max) {} template int numOfZero(const uvector& v) { int res = 0; for (int i = 0; i < N; ++i) { if (v(i) == 0) { res++; } } return res; } template int binaryToDecimal(const uvector& v, int zeroRep = 0) { int res = 0; int base = 1; for (int i = N - 1; i >= 0; --i) { if (v(i) != zeroRep) { res += base; } base *= 2; } return res; } template int replaceFirst(uvector& v, int oldVal, int newVal) { for (int i = 0; i < N; ++i) { if (v(i) == oldVal) { v(i) = newVal; return i; } } return -1; } void build(const Scene& scene, std::vector& nodes, int nowNodeIdx, const uvector3& nowNodeMin, const uvector3& nowNodeMax) { const std::vector& polyIntersectIndices = nodes[nowNodeIdx].polyIntersectIndices; if (polyIntersectIndices.size() == 1) { // TODO 相交很少时 } int lastIdx = nodes.size(); nodes.resize(lastIdx + 8); uvector3 nodeMid = (nowNodeMin + nowNodeMax) / 2; for (int i = 0; i < polyIntersectIndices.size(); ++i) { auto poly = scene.polys[polyIntersectIndices[i]]; uvector mark(0, 0, 0); for (int faceAxis = 0; faceAxis < 3; ++faceAxis) { real centerPlane = nodeMid(faceAxis); tensor2 restrictToCenterPlane(nullptr, remove_component(poly.ext(), faceAxis)); algoim_spark_alloc(real, restrictToCenterPlane); restrictToInnerFace(poly, faceAxis, centerPlane, restrictToCenterPlane); if (bernstein::uniformSign(restrictToCenterPlane) == -1) { // primitive contain the conterface mark(faceAxis) = 2; } else { // primitive is on one side of the centerface // deCasteljau to transformation uvector3 halfCellMin = 0, halfCellMax = 1; halfCellMax(faceAxis) = 0.5; tensor3 negativeHalfCell(nullptr, poly.ext()); algoim_spark_alloc(real, negativeHalfCell); bernstein::deCasteljau(poly, halfCellMin, halfCellMax, negativeHalfCell); if (bernstein::uniformSign(negativeHalfCell) == -1) { // 不在负半空间,此时一定在正半空间,可以assert一下正半空间的sign,不能为-1 mark(faceAxis) = 1; } else { mark(faceAxis) = -1; } } } if (any(mark == uvector3(2, 2, 2))) { int subIdx = 0; for (MultiLoop<3> j(0, 2); ~j; ++j, ++subIdx) { nodes[lastIdx + subIdx].polyIntersectIndices.emplace_back(poly); nodes[lastIdx + subIdx].min = nowNodeMin; nodes[lastIdx + subIdx].max = nowNodeMax; for (int k = 0; k < 3; ++k) { if (j(k) == 0) nodes[lastIdx + subIdx].max(k) = nodeMid(k); else nodes[lastIdx + subIdx].min(k) = nodeMid(k); } } continue; } int zeroCount = numOfZero<3>(mark); if (zeroCount == 0) { // mark has -1 or 1 only nodes[lastIdx + binaryToDecimal(mark, -1)].polyIntersectIndices.emplace_back(polyIntersectIndices[i]); } else if (zeroCount == 1) { // poly related to 2 subcells uvector sideMark = mark; int zeroIdx = replaceFirst(sideMark, 0, 1); nodes[lastIdx + binaryToDecimal(sideMark, -1)].polyIntersectIndices.emplace_back(polyIntersectIndices[i]); sideMark(zeroIdx) = -1; nodes[lastIdx + binaryToDecimal(sideMark, -1)].polyIntersectIndices.emplace_back(polyIntersectIndices[i]); } else { // zeroCount == 2 or 3 } } // TODO: 考虑fully contain 问题 } }; // namespace algoim::Organizer // clang-format off /** 最一开始的cell应当包含所有的primitive func(given cell) { 得到8个subcell for each primitive { mark = [0,0,0] for k in 0,1,2 { 测试primitive和k轴向的centerface有无交 if 无交 { if primitive包裹centerface { mark[k] = 2 } else { 判断primitive位于哪一侧 if k正方向 mark[k] = 1 else mark[k] = -1 } } } if mark 含2 { // TODO: 可能需要优化:在极端情况下, // 例如primitive的边刚好与centerface重合, // 此时不是所有subcell都关联primitive 将primitive放入所有subcell } elif mark 没有0 { 将primitive放入对应的subcell } elif mark 有1个0 { 将primitive放入两个对应的subcell } else { // >= 2个0 测试每个可能有交subcell是否与primitive相交 相交的放入对于subcell } } for each subcell { func(subcell) } } */ // clang-format on