Added: Error exit if integrand with reduced integration for mixed LR.

Fixed: Solution transfer for mixed in 3D.
This commit is contained in:
Knut Morten Okstad 2018-09-20 17:43:26 +02:00
parent d8ac636fee
commit 58a1bf78d1
2 changed files with 150 additions and 150 deletions

View File

@ -325,6 +325,14 @@ bool ASMu2Dmx::integrate (Integrand& integrand,
const double* xg = GaussQuadrature::getCoord(nGauss);
const double* wg = GaussQuadrature::getWeight(nGauss);
if (!xg || !wg) return false;
if (integrand.getReducedIntegration(nGauss))
{
std::cerr <<" *** Reduced integration not available for mixed LR splines"
<< std::endl;
return false;
}
bool use2ndDer = integrand.getIntegrandType() & Integrand::SECOND_DERIVATIVES;
ThreadGroups oneGroup;
@ -333,9 +341,9 @@ bool ASMu2Dmx::integrate (Integrand& integrand,
// === Assembly loop over all elements in the patch ==========================
bool ok = true;
for (size_t t = 0; t < groups.size() && ok; ++t)
{
#pragma omp parallel for schedule(static)
for (size_t e = 0; e < groups[t].size(); ++e)
{
@ -346,23 +354,23 @@ bool ASMu2Dmx::integrate (Integrand& integrand,
std::vector<size_t> elem_sizes;
this->getElementsAt(threadBasis->getElement(groups[t][e])->midpoint(),els,elem_sizes);
int geoEl = els[geoBasis-1];
MxFiniteElement fe(elem_sizes);
fe.iel = MLGE[geoEl-1];
std::vector<Matrix> dNxdu(m_basis.size());
MxFiniteElement fe(elem_sizes);
std::vector<Matrix> dNxdu(m_basis.size());
std::vector<Matrix3D> d2Nxdu2(use2ndDer ? m_basis.size() : 0);
Matrix Xnod, Jac;
double param[3] = { 0.0, 0.0, 0.0 };
Vec4 X(param,time.t);
std::vector<Matrix3D> d2Nxdu2(m_basis.size());
Matrix3D Hess;
double dXidu[2];
double param[3] = { 0.0, 0.0, 0.0 };
Vec4 X(param,time.t);
int geoEl = els[geoBasis-1];
fe.iel = MLGE[geoEl-1];
// Get element area in the parameter space
double dA = this->getParametricArea(geoEl);
if (dA < 0.0) // topology error (probably logic error)
double dA = 0.25*this->getParametricArea(geoEl);
if (dA < 0.0)
{
ok = false;
ok = false; // topology error (probably logic error)
continue;
}
@ -389,8 +397,8 @@ bool ASMu2Dmx::integrate (Integrand& integrand,
this->getGaussPointParameters(gpar[d],d,nGauss,geoEl,xg);
// Initialize element quantities
LocalIntegral* A = integrand.getLocalIntegral(elem_sizes,fe.iel,false);
if (!integrand.initElement(MNPC[geoEl-1], fe, elem_sizes, nb, *A))
LocalIntegral* A = integrand.getLocalIntegral(elem_sizes,fe.iel);
if (!integrand.initElement(MNPC[geoEl-1],fe,elem_sizes,nb,*A))
{
A->destruct();
ok = false;
@ -444,7 +452,7 @@ bool ASMu2Dmx::integrate (Integrand& integrand,
X.assign(Xnod * fe.basis(geoBasis));
// Evaluate the integrand and accumulate element contributions
fe.detJxW *= 0.25*dA*wg[i]*wg[j];
fe.detJxW *= dA*wg[i]*wg[j];
if (!integrand.evalIntMx(*A,fe,time,X))
ok = false;
}
@ -459,7 +467,6 @@ bool ASMu2Dmx::integrate (Integrand& integrand,
A->destruct();
}
}
return ok;
}
@ -469,7 +476,7 @@ bool ASMu2Dmx::integrate (Integrand& integrand, int lIndex,
GlobalIntegral& glInt,
const TimeDomain& time)
{
if (!m_basis[0] || !m_basis[1])
if (m_basis.empty())
return true; // silently ignore empty patches
PROFILE2("ASMu2Dmx::integrate(B)");
@ -589,9 +596,9 @@ bool ASMu2Dmx::integrate (Integrand& integrand, int lIndex,
dNxdu[geoBasis-1],t1,t2);
if (fe.detJxW == 0.0) continue; // skip singular points
for (size_t b = 0; b < m_basis.size(); ++b)
if (b != (size_t)geoBasis-1)
fe.grad(b+1).multiply(dNxdu[b],Jac);
for (size_t b = 1; b <= m_basis.size(); ++b)
if ((int)b != geoBasis)
fe.grad(b).multiply(dNxdu[b-1],Jac);
if (edgeDir < 0)
normal *= -1.0;
@ -626,8 +633,11 @@ bool ASMu2Dmx::integrate (Integrand& integrand,
const TimeDomain& time,
const ASM::InterfaceChecker& iChkgen)
{
if (!geo) return true; // silently ignore empty patches
if (!(integrand.getIntegrandType() & Integrand::INTERFACE_TERMS)) return true;
if (m_basis.empty())
return true; // silently ignore empty patches
if (!(integrand.getIntegrandType() & Integrand::INTERFACE_TERMS))
return true; // No interface terms
PROFILE2("ASMu2Dmx::integrate(J)");
@ -767,16 +777,18 @@ bool ASMu2Dmx::integrate (Integrand& integrand,
// Compute Jacobian inverse of the coordinate mapping and
// basis function derivatives w.r.t. Cartesian coordinates
fe.detJxW = utl::Jacobian(Jac2, normal,
fe.grad(geoBasis+m_basis.size()),
Xnod2,dNxdu[geoBasis-1+m_basis.size()],t1,t2);
fe.detJxW = utl::Jacobian(Jac, normal,
fe.grad(geoBasis),Xnod,dNxdu[geoBasis-1],t1,t2);
fe.detJxW = utl::Jacobian(Jac2,normal,
fe.grad(geoBasis+m_basis.size()),Xnod2,
dNxdu[geoBasis-1+m_basis.size()],t1,t2);
fe.detJxW = utl::Jacobian(Jac,normal,
fe.grad(geoBasis),Xnod,
dNxdu[geoBasis-1],t1,t2);
if (fe.detJxW == 0.0) continue; // skip singular points
for (size_t b = 0; b < m_basis.size(); ++b)
if (b != (size_t)geoBasis-1) {
fe.grad(b+1).multiply(dNxdu[b],Jac);
fe.grad(b+1+m_basis.size()).multiply(dNxdu[b+m_basis.size()],Jac);
for (size_t b = 1; b <= m_basis.size(); ++b)
if ((int)b != geoBasis) {
fe.grad(b).multiply(dNxdu[b-1],Jac);
fe.grad(b+m_basis.size()).multiply(dNxdu[b-1+m_basis.size()],Jac);
}
if (edgeDir < 0)
@ -844,6 +856,7 @@ bool ASMu2Dmx::evalSolution (Matrix& sField, const Vector& locSol,
for (size_t j=0; j < m_basis.size(); ++j) {
if (nc[j] == 0)
continue;
// Fetch element containing evaluation point.
// Sadly, points are not always ordered in the same way as the elements.
int iel = m_basis[j]->getElementContaining(gpar[0][i],gpar[1][i]);
@ -897,10 +910,10 @@ bool ASMu2Dmx::evalSolution (Matrix& sField, const IntegrandBase& integrand,
this->getElementsAt({gpar[0][i],gpar[1][i]},els,elem_sizes);
// Evaluate the basis functions at current parametric point
MxFiniteElement fe(elem_sizes,firstIp+i);
std::vector<Matrix> dNxdu(m_basis.size());
MxFiniteElement fe(elem_sizes,firstIp+i);
std::vector<Matrix> dNxdu(m_basis.size());
std::vector<Matrix3D> d2Nxdu2(use2ndDer ? m_basis.size() : 0);
Matrix Jac, Xnod;
std::vector<Matrix3D> d2Nxdu2(m_basis.size());
Matrix3D Hess;
if (use2ndDer)
for (size_t b = 0; b < m_basis.size(); ++b) {
@ -927,14 +940,13 @@ bool ASMu2Dmx::evalSolution (Matrix& sField, const IntegrandBase& integrand,
if (use2ndDer && !fe.Hessian(Hess,Jac,Xnod,d2Nxdu2,geoBasis))
return false;
// Now evaluate the solution field
Vector solPt;
// Cartesian coordinates of current integration point
fe.u = gpar[0][i];
fe.v = gpar[1][i];
utl::Point X4(Xnod*fe.basis(geoBasis),{fe.u,fe.v});
// Now evaluate the solution field
Vector solPt;
if (!integrand.evalSol(solPt,fe,X4,
MNPC[els[geoBasis-1]-1],elem_sizes,nb))
return false;
@ -956,13 +968,12 @@ bool ASMu2Dmx::refine (const LR::RefineData& prm, Vectors& sol)
if (prm.errors.empty() && prm.elements.empty())
return true;
for (Vector& solvec : sol) {
for (Vector& solvec : sol)
for (size_t j = 0; j < m_basis.size(); j++) {
Vector bVec;
this->extractNodeVec(solvec, bVec, 0, j+1);
LR::extendControlPoints(m_basis[j].get(), bVec, nfx[j]);
}
}
if (doRefine(prm, refBasis.get())) {
for (size_t j = 0; j < m_basis.size(); ++j)
@ -1118,8 +1129,8 @@ void ASMu2Dmx::getBoundaryNodes (int lIndex, IntVec& nodes, int basis,
}
void ASMu2Dmx::remapErrors(RealArray& errors,
const RealArray& origErr, bool elemErrors) const
void ASMu2Dmx::remapErrors (RealArray& errors,
const RealArray& origErr, bool elemErrors) const
{
const LR::LRSplineSurface* geo = this->getBasis(ASMmxBase::geoBasis);
for (const LR::Element* elm : geo->getAllElements()) {

View File

@ -40,6 +40,7 @@ ASMu3Dmx::ASMu3Dmx (const CharVec& n_f)
: ASMu3D(std::accumulate(n_f.begin(), n_f.end(), 0)), ASMmxBase(n_f),
bezierExtractmx(myBezierExtractmx)
{
threadBasis = nullptr;
myGeoBasis = ASMmxBase::geoBasis;
}
@ -49,6 +50,7 @@ ASMu3Dmx::ASMu3Dmx (const ASMu3Dmx& patch, const CharVec& n_f)
m_basis(patch.m_basis),
bezierExtractmx(patch.myBezierExtractmx)
{
threadBasis = patch.threadBasis;
nfx = patch.nfx;
nb = patch.nb;
myGeoBasis = ASMmxBase::geoBasis;
@ -199,6 +201,9 @@ bool ASMu3Dmx::getSolution (Matrix& sField, const Vector& locSol,
bool ASMu3Dmx::generateFEMTopology ()
{
if (!myMLGN.empty())
return true;
if (m_basis.empty()) {
VolumeVec vvec = ASMmxBase::establishBases(tensorspline, ASMmxBase::Type);
m_basis.resize(vvec.size());
@ -314,6 +319,9 @@ bool ASMu3Dmx::integrate (Integrand& integrand,
GlobalIntegral& glInt,
const TimeDomain& time)
{
if (m_basis.empty())
return true; // silently ignore empty patches
PROFILE2("ASMu3Dmx::integrate(I)");
// Get Gaussian quadrature points and weights
@ -321,6 +329,15 @@ bool ASMu3Dmx::integrate (Integrand& integrand,
const double* wg = GaussQuadrature::getWeight(nGauss);
if (!xg || !wg) return false;
if (integrand.getReducedIntegration(nGauss))
{
std::cerr <<" *** Reduced integration not available for mixed LR splines"
<< std::endl;
return false;
}
bool use2ndDer = integrand.getIntegrandType() & Integrand::SECOND_DERIVATIVES;
// evaluate all gauss points on the bezier patch (-1, 1)
std::vector<Matrix> BN(m_basis.size());
std::vector<Matrix> BdNdu(m_basis.size());
@ -331,55 +348,33 @@ bool ASMu3Dmx::integrate (Integrand& integrand,
int p1 = lrspline->order(0);
int p2 = lrspline->order(1);
int p3 = lrspline->order(2);
double u[2*p1], v[2*p2], w[2*p3];
Go::BsplineBasis basis1 = getBezierBasis(p1);
Go::BsplineBasis basis2 = getBezierBasis(p2);
Go::BsplineBasis basis3 = getBezierBasis(p3);
BN[b-1].resize(p1*p2*p3, nGauss*nGauss*nGauss);
BN [b-1].resize(p1*p2*p3, nGauss*nGauss*nGauss);
BdNdu[b-1].resize(p1*p2*p3, nGauss*nGauss*nGauss);
BdNdv[b-1].resize(p1*p2*p3, nGauss*nGauss*nGauss);
BdNdw[b-1].resize(p1*p2*p3, nGauss*nGauss*nGauss);
int ig=1; // gauss point iterator
for(int zeta=0; zeta<nGauss; zeta++) {
for(int eta=0; eta<nGauss; eta++) {
for(int xi=0; xi<nGauss; xi++, ig++) {
double u[2*p1];
double v[2*p2];
double w[2*p3];
int ig = 1; // gauss point iterator
for (int zeta = 0; zeta < nGauss; zeta++)
for (int eta = 0; eta < nGauss; eta++)
for (int xi = 0; xi < nGauss; xi++, ig++) {
basis1.computeBasisValues(xg[xi], u, 1);
basis2.computeBasisValues(xg[eta], v, 1);
basis3.computeBasisValues(xg[zeta], w, 1);
int ib=1; // basis function iterator
double sum = 0;
for(int k=0; k<p3; k++) {
for(int j=0; j<p2; j++) {
for(int i=0; i<p1; i++, ib++) {
int ib = 1; // basis function iterator
for (int k = 0; k < p3; k++)
for (int j = 0; j < p2; j++)
for (int i = 0; i < p1; i++, ib++) {
BN[b-1](ib,ig) = u[2*i ]*v[2*j ]*w[2*k ];
BdNdu[b-1](ib,ig) = u[2*i+1]*v[2*j ]*w[2*k ];
BdNdv[b-1](ib,ig) = u[2*i ]*v[2*j+1]*w[2*k ];
BdNdw[b-1](ib,ig) = u[2*i ]*v[2*j ]*w[2*k+1];
sum += BN[b-1](ib,ig);
}
}
}
}
}
}
}
// Get the reduced integration quadrature points, if needed
const double* xr = nullptr;
const double* wr = nullptr;
int nRed = integrand.getReducedIntegration(nGauss);
if (nRed > 0)
{
xr = GaussQuadrature::getCoord(nRed);
wr = GaussQuadrature::getWeight(nRed);
if (!xr || !wr) return false;
}
else if (nRed < 0)
nRed = nGauss; // The integrand needs to know nGauss
ThreadGroups oneGroup;
if (glInt.threadSafe()) oneGroup.oneGroup(nel);
const IntMat& groups = glInt.threadSafe() ? oneGroup[0] : threadGroups[0];
@ -400,17 +395,18 @@ bool ASMu3Dmx::integrate (Integrand& integrand,
std::vector<int> els;
std::vector<size_t> elem_sizes;
this->getElementsAt(el->midpoint(),els,elem_sizes);
int iEl = el->getId();
MxFiniteElement fe(elem_sizes);
fe.iel = MLGE[iEl];
std::vector<Matrix> dNxdu(m_basis.size());
MxFiniteElement fe(elem_sizes);
std::vector<Matrix> dNxdu(m_basis.size());
std::vector<Matrix3D> d2Nxdu2(use2ndDer ? m_basis.size() : 0);
Matrix Xnod, Jac;
std::vector<Matrix3D> d2Nxdu2(m_basis.size());
Matrix3D Hess;
double dXidu[3];
double param[3] = { 0.0, 0.0, 0.0 };
Vec4 X(param,time.t);
int iEl = el->getId();
fe.iel = MLGE[iEl];
// Get element volume in the parameter space
double du = el->umax() - el->umin();
double dv = el->vmax() - el->vmin();
@ -430,14 +426,9 @@ bool ASMu3Dmx::integrate (Integrand& integrand,
}
// Compute parameter values of the Gauss points over the whole element
std::array<RealArray,3> gpar, redpar;
std::array<RealArray,3> gpar;
for (int d = 0; d < 3; d++)
{
this->getGaussPointParameters(gpar[d],d,nGauss,iEl+1,xg);
if (xr)
this->getGaussPointParameters(redpar[d],d,nRed,iEl+1,xr);
}
if (integrand.getIntegrandType() & Integrand::ELEMENT_CORNERS)
fe.h = this->getElementCorners(iEl+1, fe.XC);
@ -498,12 +489,6 @@ bool ASMu3Dmx::integrate (Integrand& integrand,
continue;
}
if (xr)
{
std::cerr << "Haven't really figured out what this part does yet\n";
exit(42142);
}
// --- Integration loop over all Gauss points in each direction ----------
int jp = iEl*nGauss*nGauss*nGauss;
@ -534,7 +519,7 @@ bool ASMu3Dmx::integrate (Integrand& integrand,
B.fillColumn(4, BdNdw[b].getColumn(ig)*2.0/dw);
// Fetch basis function derivatives at current integration point
if (integrand.getIntegrandType() & Integrand::SECOND_DERIVATIVES)
if (use2ndDer)
this->evaluateBasis(els[b]-1, fe, dNxdu[b], d2Nxdu2[b], b+1);
else
this->evaluateBasis(fe, dNxdu[b], bezierExtractmx[b][els[b]-1], B, b+1);
@ -560,8 +545,7 @@ bool ASMu3Dmx::integrate (Integrand& integrand,
fe.detJxW *= 0.125*vol*wg[i]*wg[j]*wg[k];
if (!integrand.evalIntMx(*A,fe,time,X))
ok = false;
} // end gauss integrand
}
// Finalize the element quantities
if (ok && !integrand.finalizeElement(*A,fe,time,firstIp+jp))
@ -582,6 +566,9 @@ bool ASMu3Dmx::integrate (Integrand& integrand, int lIndex,
GlobalIntegral& glInt,
const TimeDomain& time)
{
if (m_basis.empty())
return true; // silently ignore empty patches
PROFILE2("ASMu3Dmx::integrate(B)");
// Get Gaussian quadrature points and weights
@ -663,7 +650,7 @@ bool ASMu3Dmx::integrate (Integrand& integrand, int lIndex,
double dXidu[3];
// Get element face area in the parameter space
double dA = this->getParametricArea(iEl+1,abs(faceDir));
double dA = 0.25*this->getParametricArea(iEl+1,abs(faceDir));
if (dA < 0.0) return false; // topology error (probably logic error)
// Set up control point coordinates for current element
@ -728,9 +715,10 @@ bool ASMu3Dmx::integrate (Integrand& integrand, int lIndex,
fe.detJxW = utl::Jacobian(Jac, normal, fe.grad(geoBasis), Xnod,
dNxdu[geoBasis-1], t1, t2);
if (fe.detJxW == 0.0) continue; // skip singular points
for (size_t b = 0; b < m_basis.size(); ++b)
if (b != (size_t)geoBasis-1)
fe.grad(b+1).multiply(dNxdu[b],Jac);
for (size_t b = 1; b <= m_basis.size(); ++b)
if ((int)b != geoBasis)
fe.grad(b).multiply(dNxdu[b-1],Jac);
if (faceDir < 0) normal *= -1.0;
@ -742,7 +730,7 @@ bool ASMu3Dmx::integrate (Integrand& integrand, int lIndex,
X.assign(Xnod * fe.basis(geoBasis));
// Evaluate the integrand and accumulate element contributions
fe.detJxW *= 0.25*dA*wg[i]*wg[j];
fe.detJxW *= dA*wg[i]*wg[j];
ok = integrand.evalBouMx(*A,fe,time,X,normal);
}
@ -792,6 +780,7 @@ bool ASMu3Dmx::evalSolution (Matrix& sField, const Vector& locSol,
for (size_t j=0; j < m_basis.size(); ++j) {
if (nc[j] == 0)
continue;
// Fetch element containing evaluation point.
// Sadly, points are not always ordered in the same way as the elements.
int iel = m_basis[j]->getElementContaining(gpar[0][i],gpar[1][i],gpar[2][i]);
@ -845,10 +834,10 @@ bool ASMu3Dmx::evalSolution (Matrix& sField, const IntegrandBase& integrand,
this->getElementsAt({gpar[0][i],gpar[1][i],gpar[2][i]},els,elem_sizes);
// Evaluate the basis functions at current parametric point
MxFiniteElement fe(elem_sizes,firstIp+i);
std::vector<Matrix> dNxdu(m_basis.size());
MxFiniteElement fe(elem_sizes,firstIp+i);
std::vector<Matrix> dNxdu(m_basis.size());
std::vector<Matrix3D> d2Nxdu2(use2ndDer ? m_basis.size() : 0);
Matrix Jac, Xnod;
std::vector<Matrix3D> d2Nxdu2(m_basis.size());
Matrix3D Hess;
if (use2ndDer)
for (size_t b = 0; b < m_basis.size(); ++b) {
@ -904,13 +893,12 @@ bool ASMu3Dmx::refine (const LR::RefineData& prm, Vectors& sol)
if (prm.errors.empty() && prm.elements.empty())
return true;
for (Vector& solvec : sol) {
size_t ofs = 0;
for (Vector& solvec : sol)
for (size_t j = 0; j < m_basis.size(); j++) {
LR::extendControlPoints(m_basis[j].get(), solvec, nfx[j], ofs);
ofs += nfx[j]*nb[j];
Vector bVec;
this->extractNodeVec(solvec, bVec, 0, j+1);
LR::extendControlPoints(m_basis[j].get(), bVec, nfx[j]);
}
}
if (doRefine(prm, refBasis.get())) {
for (size_t j = 0; j < m_basis.size(); ++j)
@ -943,7 +931,7 @@ bool ASMu3Dmx::refine (const LR::RefineData& prm, Vectors& sol)
}
size_t ofs = 0;
for (int i = sol.size()-1; i > 0; i--)
for (int i = sol.size()-1; i >= 0; i--)
for (size_t j = 0; j < m_basis.size(); ++j) {
sol[i].resize(len);
LR::contractControlPoints(m_basis[j].get(), sol[i], nfx[j], ofs);
@ -992,48 +980,6 @@ Vec3 ASMu3Dmx::getCoord (size_t inod) const
}
void ASMu3Dmx::remapErrors (RealArray& errors,
const RealArray& origErr, bool elemErrors) const
{
const LR::LRSplineVolume* geo = this->getBasis(ASMmxBase::geoBasis);
for (const LR::Element* elm : geo->getAllElements()) {
int rEl = refBasis->getElementContaining((elm->umin()+elm->umax())/2.0,
(elm->vmin()+elm->vmax())/2.0,
(elm->wmin()+elm->wmax())/2.0);
if (elemErrors)
errors[rEl] += origErr[elm->getId()];
else
for (LR::Basisfunction* b : refBasis->getElement(rEl)->support())
errors[b->getId()] += origErr[elm->getId()];
}
}
size_t ASMu3Dmx::getNoRefineNodes() const
{
return refBasis->nBasisFunctions();
}
size_t ASMu3Dmx::getNoRefineElms() const
{
return refBasis->nElements();
}
void ASMu3Dmx::copyRefinement(LR::LRSplineVolume* basis, int multiplicity) const
{
for (const LR::MeshRectangle* rect : refBasis->getAllMeshRectangles()) {
int mult = rect->multiplicity_ > 1 ? basis->order(rect->constDirection())
: multiplicity;
LR::MeshRectangle* newRect = rect->copy();
newRect->multiplicity_ = mult;
basis->insert_line(newRect);
}
}
void ASMu3Dmx::generateThreadGroups (const Integrand& integrand, bool silence,
bool ignoreGlobalLM)
{
@ -1081,6 +1027,49 @@ void ASMu3Dmx::generateThreadGroups (const Integrand& integrand, bool silence,
}
void ASMu3Dmx::remapErrors (RealArray& errors,
const RealArray& origErr, bool elemErrors) const
{
const LR::LRSplineVolume* geo = this->getBasis(ASMmxBase::geoBasis);
for (const LR::Element* elm : geo->getAllElements()) {
int rEl = refBasis->getElementContaining((elm->umin()+elm->umax())/2.0,
(elm->vmin()+elm->vmax())/2.0,
(elm->wmin()+elm->wmax())/2.0);
if (elemErrors)
errors[rEl] += origErr[elm->getId()];
else
for (LR::Basisfunction* b : refBasis->getElement(rEl)->support())
errors[b->getId()] += origErr[elm->getId()];
}
}
size_t ASMu3Dmx::getNoRefineNodes() const
{
return refBasis->nBasisFunctions();
}
size_t ASMu3Dmx::getNoRefineElms() const
{
return refBasis->nElements();
}
void ASMu3Dmx::copyRefinement (LR::LRSplineVolume* basis,
int multiplicity) const
{
for (const LR::MeshRectangle* rect : refBasis->getAllMeshRectangles()) {
int mult = rect->multiplicity_ > 1 ? basis->order(rect->constDirection())
: multiplicity;
LR::MeshRectangle* newRect = rect->copy();
newRect->multiplicity_ = mult;
basis->insert_line(newRect);
}
}
void ASMu3Dmx::swapProjectionBasis ()
{
if (altProjBasis) {