added: BasisFunctionCache in ASMu3D
This commit is contained in:
parent
2f676bf6b3
commit
730fdca306
@ -137,6 +137,8 @@ void ASMu3D::clear (bool retainGeometry)
|
||||
this->ASMbase::clear(retainGeometry);
|
||||
this->dirich.clear();
|
||||
projThreadGroups = ThreadGroups();
|
||||
|
||||
myCache.clear();
|
||||
}
|
||||
|
||||
|
||||
@ -896,78 +898,28 @@ bool ASMu3D::integrate (Integrand& integrand,
|
||||
|
||||
PROFILE2("ASMu3D::integrate(I)");
|
||||
|
||||
int p1 = lrspline->order(0);
|
||||
int p2 = lrspline->order(1);
|
||||
int p3 = lrspline->order(2);
|
||||
int pm = std::max(std::max(p1,p2),p3);
|
||||
|
||||
// Get Gaussian quadrature points and weights
|
||||
int nGP = this->getNoGaussPt(pm);
|
||||
const double* xg = GaussQuadrature::getCoord(nGP);
|
||||
const double* wg = GaussQuadrature::getWeight(nGP);
|
||||
if (!xg || !wg) return false;
|
||||
bool use2ndDer = integrand.getIntegrandType() & Integrand::SECOND_DERIVATIVES;
|
||||
|
||||
// Evaluate all gauss points on the bezier patch (-1, 1)
|
||||
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);
|
||||
Matrix BN( p1*p2*p3, nGP*nGP*nGP), rBN;
|
||||
Matrix BdNdu(p1*p2*p3, nGP*nGP*nGP), rBdNdu;
|
||||
Matrix BdNdv(p1*p2*p3, nGP*nGP*nGP), rBdNdv;
|
||||
Matrix BdNdw(p1*p2*p3, nGP*nGP*nGP), rBdNdw;
|
||||
int ig = 1; // gauss point iterator
|
||||
for (int zeta = 0; zeta < nGP; zeta++)
|
||||
for (int eta = 0; eta < nGP; eta++)
|
||||
for (int xi = 0; xi < nGP; 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
|
||||
for (int k = 0; k < p3; k++)
|
||||
for (int j = 0; j < p2; j++)
|
||||
for (int i = 0; i < p1; i++, ib++) {
|
||||
BN(ib,ig) = u[2*i ]*v[2*j ]*w[2*k ];
|
||||
BdNdu(ib,ig) = u[2*i+1]*v[2*j ]*w[2*k ];
|
||||
BdNdv(ib,ig) = u[2*i ]*v[2*j+1]*w[2*k ];
|
||||
BdNdw(ib,ig) = u[2*i ]*v[2*j ]*w[2*k+1];
|
||||
}
|
||||
}
|
||||
if (myCache.empty())
|
||||
myCache.emplace_back(std::make_unique<BasisFunctionCache>(*this, cachePolicy, 1));
|
||||
|
||||
BasisFunctionCache& cache = *myCache.front();
|
||||
cache.setIntegrand(&integrand);
|
||||
if (!cache.init(use2ndDer ? 2 : 1))
|
||||
return false;
|
||||
|
||||
const std::array<int,3>& ng = cache.nGauss();
|
||||
const std::array<const double*,3>& xg = cache.coord();
|
||||
const std::array<const double*,3>& wg = cache.weight();
|
||||
|
||||
// Get the reduced integration quadrature points, if needed
|
||||
const double* xr = nullptr;
|
||||
const double* wr = nullptr;
|
||||
int nRed = integrand.getReducedIntegration(nGP);
|
||||
if (nRed > 0)
|
||||
{
|
||||
xr = GaussQuadrature::getCoord(nRed);
|
||||
wr = GaussQuadrature::getWeight(nRed);
|
||||
if (!xr || !wr) return false;
|
||||
const double* xr = cache.coord(true)[0];
|
||||
const double* wr = cache.weight(true)[0];
|
||||
|
||||
rBN.resize( p1*p2*p3, nRed*nRed*nRed);
|
||||
rBdNdu.resize(p1*p2*p3, nRed*nRed*nRed);
|
||||
rBdNdv.resize(p1*p2*p3, nRed*nRed*nRed);
|
||||
rBdNdw.resize(p1*p2*p3, nRed*nRed*nRed);
|
||||
int ig = 1; // gauss point iterator
|
||||
for (int zeta = 0; zeta < nRed; zeta++)
|
||||
for (int eta = 0; eta < nRed; eta++)
|
||||
for (int xi = 0; xi < nRed; xi++, ig++) {
|
||||
basis1.computeBasisValues(xr[xi], u, 1);
|
||||
basis2.computeBasisValues(xr[eta], v, 1);
|
||||
basis3.computeBasisValues(xr[zeta], w, 1);
|
||||
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++) {
|
||||
rBN(ib,ig) = u[2*i ]*v[2*j ]*w[2*k ];
|
||||
rBdNdu(ib,ig) = u[2*i+1]*v[2*j ]*w[2*k ];
|
||||
rBdNdv(ib,ig) = u[2*i ]*v[2*j+1]*w[2*k ];
|
||||
rBdNdw(ib,ig) = u[2*i ]*v[2*j ]*w[2*k+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nRed < 0)
|
||||
nRed = nGP; // The integrand needs to know nGauss
|
||||
const int p1 = lrspline->order(0);
|
||||
const int p2 = lrspline->order(1);
|
||||
const int p3 = lrspline->order(2);
|
||||
|
||||
ThreadGroups oneGroup;
|
||||
if (glInt.threadSafe()) oneGroup.oneGroup(nel);
|
||||
@ -995,20 +947,15 @@ bool ASMu3D::integrate (Integrand& integrand,
|
||||
fe.p = p1 - 1;
|
||||
fe.q = p2 - 1;
|
||||
fe.r = p3 - 1;
|
||||
Matrix B(p1*p2*p3,4); // Bezier evaluation points and derivatives
|
||||
const Matrix& C = bezierExtract[iel-1];
|
||||
Matrix dNdu, Xnod, Jac;
|
||||
Matrix3D d2Ndu2, Hess;
|
||||
Matrix Xnod, Jac;
|
||||
Matrix3D Hess;
|
||||
double dXidu[3];
|
||||
double param[3] = { 0.0, 0.0, 0.0 };
|
||||
Vec4 X(param,time.t);
|
||||
|
||||
// Get element volume in the parameter space
|
||||
const LR::Element* el = lrspline->getElement(iel-1);
|
||||
double du = 0.5*(el->umax() - el->umin());
|
||||
double dv = 0.5*(el->vmax() - el->vmin());
|
||||
double dw = 0.5*(el->wmax() - el->wmin());
|
||||
double dV = du*dv*dw;
|
||||
double dV = 0.125*el->volume();
|
||||
|
||||
// Set up control point (nodal) coordinates for current element
|
||||
if (!this->getElementCoordinates(Xnod,iel))
|
||||
@ -1017,15 +964,6 @@ bool ASMu3D::integrate (Integrand& integrand,
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compute parameter values of the Gauss points over this element
|
||||
std::array<RealArray,3> gpar, redpar;
|
||||
for (int d = 0; d < 3; d++)
|
||||
{
|
||||
this->getGaussPointParameters(gpar[d],d,nGP,iel,xg);
|
||||
if (xr)
|
||||
this->getGaussPointParameters(redpar[d],d,nRed,iel,xr);
|
||||
}
|
||||
|
||||
if (integrand.getIntegrandType() & Integrand::ELEMENT_CORNERS)
|
||||
fe.h = this->getElementCorners(iel,fe.XC);
|
||||
|
||||
@ -1051,24 +989,21 @@ bool ASMu3D::integrate (Integrand& integrand,
|
||||
{
|
||||
// --- Compute average value of basis functions over the element -----
|
||||
|
||||
int ip = (iel-1)*nGP*nGP*nGP + firstIp;
|
||||
int ip = (iel-1)*ng[0]*ng[1]*ng[2] + firstIp;
|
||||
fe.Navg.resize(nen,true);
|
||||
double vol = 0.0;
|
||||
int ig = 1;
|
||||
for (int k = 0; k < nGP; k++)
|
||||
for (int j = 0; j < nGP; j++)
|
||||
for (int i = 0; i < nGP; i++, ++ip, ++ig)
|
||||
int ig = 0;
|
||||
for (int k = 0; k < ng[2]; k++)
|
||||
for (int j = 0; j < ng[1]; j++)
|
||||
for (int i = 0; i < ng[0]; i++, ++ip, ++ig)
|
||||
{
|
||||
B.fillColumn(1, BN.getColumn(ig));
|
||||
B.fillColumn(2, BdNdu.getColumn(ig)/du);
|
||||
B.fillColumn(3, BdNdv.getColumn(ig)/dv);
|
||||
B.fillColumn(4, BdNdw.getColumn(ig)/dw);
|
||||
this->evaluateBasis(fe, dNdu, C, B);
|
||||
const BasisFunctionVals& bfs = cache.getVals(iel-1,ig);
|
||||
fe.N = bfs.N;
|
||||
|
||||
// Compute Jacobian determinant of coordinate mapping
|
||||
// and multiply by weight of current integration point
|
||||
double detJac = utl::Jacobian(Jac,fe.dNdX,Xnod,dNdu,false);
|
||||
double weight = dV*wg[i]*wg[j]*wg[k];
|
||||
double detJac = utl::Jacobian(Jac,fe.dNdX,Xnod,bfs.dNdu,false);
|
||||
double weight = dV*wg[0][i]*wg[1][j]*wg[2][k];
|
||||
|
||||
// Numerical quadrature
|
||||
fe.Navg.add(fe.N,detJac*weight);
|
||||
@ -1081,6 +1016,7 @@ bool ASMu3D::integrate (Integrand& integrand,
|
||||
|
||||
// Initialize element quantities
|
||||
LocalIntegral* A = integrand.getLocalIntegral(nen,fe.iel);
|
||||
int nRed = cache.nGauss(true)[0];
|
||||
if (!integrand.initElement(MNPC[iel-1],fe,X,nRed*nRed*nRed,*A))
|
||||
{
|
||||
A->destruct();
|
||||
@ -1092,7 +1028,7 @@ bool ASMu3D::integrate (Integrand& integrand,
|
||||
{
|
||||
// --- Selective reduced integration loop ------------------------------
|
||||
|
||||
int ig = 1;
|
||||
int ig = 0;
|
||||
for (int k = 0; k < nRed; k++)
|
||||
for (int j = 0; j < nRed; j++)
|
||||
for (int i = 0; i < nRed; i++, ig++)
|
||||
@ -1103,19 +1039,15 @@ bool ASMu3D::integrate (Integrand& integrand,
|
||||
fe.zeta = xr[k];
|
||||
|
||||
// Parameter values of current integration point
|
||||
fe.u = param[0] = redpar[0][i];
|
||||
fe.v = param[1] = redpar[1][j];
|
||||
fe.w = param[2] = redpar[2][k];
|
||||
fe.u = param[0] = cache.getParam(0,iel-1,i,true);
|
||||
fe.v = param[1] = cache.getParam(1,iel-1,j,true);
|
||||
fe.w = param[2] = cache.getParam(2,iel-1,k,true);
|
||||
|
||||
// Extract bezier basis functions
|
||||
B.fillColumn(1, rBN.getColumn(ig));
|
||||
B.fillColumn(2, rBdNdu.getColumn(ig)/du);
|
||||
B.fillColumn(3, rBdNdv.getColumn(ig)/dv);
|
||||
B.fillColumn(4, rBdNdw.getColumn(ig)/dw);
|
||||
this->evaluateBasis(fe, dNdu, C, B);
|
||||
const BasisFunctionVals& bfs = cache.getVals(iel-1,ig,true);
|
||||
fe.N = bfs.N;
|
||||
|
||||
// Compute Jacobian inverse and derivatives
|
||||
fe.detJxW = utl::Jacobian(Jac,fe.dNdX,Xnod,dNdu);
|
||||
fe.detJxW = utl::Jacobian(Jac,fe.dNdX,Xnod,bfs.dNdu);
|
||||
if (fe.detJxW == 0.0) continue; // skip singular points
|
||||
|
||||
// Cartesian coordinates of current integration point
|
||||
@ -1131,67 +1063,34 @@ bool ASMu3D::integrate (Integrand& integrand,
|
||||
|
||||
// --- Integration loop over all Gauss points in each direction ----------
|
||||
|
||||
int ig = 1;
|
||||
int jp = (iel-1)*nGP*nGP*nGP;
|
||||
int ig = 0;
|
||||
int jp = (iel-1)*ng[0]*ng[1]*ng[2];
|
||||
fe.iGP = firstIp + jp; // Global integration point counter
|
||||
|
||||
for (int k = 0; k < nGP; k++)
|
||||
for (int j = 0; j < nGP; j++)
|
||||
for (int i = 0; i < nGP; i++, fe.iGP++, ig++)
|
||||
for (int k = 0; k < ng[2]; k++)
|
||||
for (int j = 0; j < ng[1]; j++)
|
||||
for (int i = 0; i < ng[0]; i++, fe.iGP++, ig++)
|
||||
{
|
||||
// Local element coordinates of current integration point
|
||||
fe.xi = xg[i];
|
||||
fe.eta = xg[j];
|
||||
fe.zeta = xg[k];
|
||||
fe.xi = xg[0][i];
|
||||
fe.eta = xg[1][j];
|
||||
fe.zeta = xg[2][k];
|
||||
|
||||
// Parameter values of current integration point
|
||||
fe.u = param[0] = gpar[0][i];
|
||||
fe.v = param[1] = gpar[1][j];
|
||||
fe.w = param[2] = gpar[2][k];
|
||||
fe.u = param[0] = cache.getParam(0,iel-1,i);
|
||||
fe.v = param[1] = cache.getParam(1,iel-1,j);
|
||||
fe.w = param[2] = cache.getParam(2,iel-1,k);
|
||||
|
||||
// Fetch basis function derivatives at current integration point
|
||||
if (integrand.getIntegrandType() & Integrand::SECOND_DERIVATIVES)
|
||||
#pragma omp critical
|
||||
this->evaluateBasis(iel-1, fe, dNdu, d2Ndu2);
|
||||
else
|
||||
{
|
||||
// Extract bezier basis functions
|
||||
B.fillColumn(1, BN.getColumn(ig));
|
||||
B.fillColumn(2, BdNdu.getColumn(ig)/du);
|
||||
B.fillColumn(3, BdNdv.getColumn(ig)/dv);
|
||||
B.fillColumn(4, BdNdw.getColumn(ig)/dw);
|
||||
this->evaluateBasis(fe, dNdu, C, B);
|
||||
|
||||
#ifdef SP_DEBUG
|
||||
// Check for errors in the bezier extraction
|
||||
if (fabs(fe.N.sum()-1.0) > 1.0e-10) {
|
||||
std::cerr <<" *** N does not sum to one at integration point #"<< ig << std::endl;
|
||||
exit(123);
|
||||
}
|
||||
char u = 'u';
|
||||
for (size_t d = 1; d <= 3; d++, u++)
|
||||
if (fabs(dNdu.getColumn(d).sum()) > 1.0e-10) {
|
||||
std::cerr <<" *** dNd"<< u <<" does not sum to zero at integration point #"<< ig << std::endl;
|
||||
exit(123);
|
||||
}
|
||||
if (fabs(B.getColumn(1).sum()-1.0) > 1.0e-10) {
|
||||
std::cerr <<" *** Bezier basis does not sum to one at integration point #"<< ig << std::endl;
|
||||
exit(123);
|
||||
}
|
||||
if (fabs(B.getColumn(2).sum()) > 1.0e-10) {
|
||||
std::cerr <<" *** Bezier derivatives do not sum to zero at integration point #"<< ig << std::endl;
|
||||
exit(123);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
const BasisFunctionVals& bfs = cache.getVals(iel-1,ig);
|
||||
fe.N = bfs.N;
|
||||
|
||||
// Compute Jacobian inverse of coordinate mapping and derivatives
|
||||
fe.detJxW = utl::Jacobian(Jac,fe.dNdX,Xnod,dNdu);
|
||||
fe.detJxW = utl::Jacobian(Jac,fe.dNdX,Xnod,bfs.dNdu);
|
||||
if (fe.detJxW == 0.0) continue; // skip singular points
|
||||
|
||||
// Compute Hessian of coordinate mapping and 2nd order derivatives
|
||||
if (integrand.getIntegrandType() & Integrand::SECOND_DERIVATIVES)
|
||||
if (!utl::Hessian(Hess,fe.d2NdX2,Jac,Xnod,d2Ndu2,dNdu))
|
||||
if (!utl::Hessian(Hess,fe.d2NdX2,Jac,Xnod,bfs.d2Ndu2,bfs.dNdu))
|
||||
ok = false;
|
||||
|
||||
// Compute G-matrix
|
||||
@ -1207,7 +1106,7 @@ bool ASMu3D::integrate (Integrand& integrand,
|
||||
X.assign(Xnod * fe.N);
|
||||
|
||||
// Evaluate the integrand and accumulate element contributions
|
||||
fe.detJxW *= dV*wg[i]*wg[j]*wg[k];
|
||||
fe.detJxW *= dV*wg[0][i]*wg[1][j]*wg[2][k];
|
||||
PROFILE3("Integrand::evalInt");
|
||||
if (!integrand.evalInt(*A,fe,time,X))
|
||||
ok = false;
|
||||
@ -1229,6 +1128,7 @@ bool ASMu3D::integrate (Integrand& integrand,
|
||||
#endif
|
||||
}
|
||||
|
||||
cache.finalizeAssembly();
|
||||
return ok;
|
||||
}
|
||||
|
||||
@ -2484,3 +2384,221 @@ void ASMu3D::generateThreadGroupsFromElms (const IntVec& elms)
|
||||
|
||||
threadGroups = threadGroups.filter(myElms);
|
||||
}
|
||||
|
||||
|
||||
ASMu3D::BasisFunctionCache::BasisFunctionCache (const ASMu3D& pch,
|
||||
ASM::CachePolicy plcy,
|
||||
int b) :
|
||||
::BasisFunctionCache<3>(plcy),
|
||||
patch(pch),
|
||||
basis(b)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ASMu3D::BasisFunctionCache::BasisFunctionCache (const BasisFunctionCache& cache,
|
||||
int b) :
|
||||
::BasisFunctionCache<3>(cache),
|
||||
patch(cache.patch),
|
||||
basis(b)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool ASMu3D::BasisFunctionCache::internalInit ()
|
||||
{
|
||||
if (!mainQ->xg[0])
|
||||
this->setupQuadrature();
|
||||
|
||||
std::array<int,3> order = { patch.getBasis(basis)->order(0),
|
||||
patch.getBasis(basis)->order(1),
|
||||
patch.getBasis(basis)->order(2) };
|
||||
// Evaluate all gauss points on the bezier patch (-1, 1)
|
||||
auto&& extractBezier = [order](const Quadrature& q,
|
||||
BezierExtract& b)
|
||||
{
|
||||
double u[2*order[0]], v[2*order[1]], w[2*order[2]];
|
||||
Go::BsplineBasis basis1 = getBezierBasis(order[0]);
|
||||
Go::BsplineBasis basis2 = getBezierBasis(order[1]);
|
||||
Go::BsplineBasis basis3 = getBezierBasis(order[2]);
|
||||
int P = order[0]*order[1]*order[2];
|
||||
int N = q.ng[0]*q.ng[1]*q.ng[2];
|
||||
b.N.resize(P,N);
|
||||
b.dNdu.resize(P,N);
|
||||
b.dNdv.resize(P,N);
|
||||
b.dNdw.resize(P,N);
|
||||
int ig = 1; // gauss point iterator
|
||||
for (int zeta = 0; zeta < q.ng[2]; zeta++)
|
||||
for (int eta = 0; eta < q.ng[1]; eta++)
|
||||
for (int xi = 0; xi < q.ng[0]; xi++, ig++) {
|
||||
basis1.computeBasisValues(q.xg[0][xi], u, 1);
|
||||
basis2.computeBasisValues(q.xg[1][eta], v, 1);
|
||||
basis3.computeBasisValues(q.xg[2][zeta], w, 1);
|
||||
int ib = 1; // basis function iterator
|
||||
for (int k = 0; k < order[2]; k++)
|
||||
for (int j = 0; j < order[1]; j++)
|
||||
for (int i = 0; i < order[0]; i++, ib++) {
|
||||
b.N(ib,ig) = u[2*i ]*v[2*j ]*w[2*k ];
|
||||
b.dNdu(ib,ig) = u[2*i+1]*v[2*j ]*w[2*k ];
|
||||
b.dNdv(ib,ig) = u[2*i ]*v[2*j+1]*w[2*k ];
|
||||
b.dNdw(ib,ig) = u[2*i ]*v[2*j ]*w[2*k+1];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
extractBezier(*mainQ, mainB);
|
||||
if (reducedQ->xg[0])
|
||||
extractBezier(*reducedQ, reducedB);
|
||||
|
||||
nTotal = patch.nel*mainQ->ng[0]*mainQ->ng[1]*mainQ->ng[2];
|
||||
if (reducedQ->xg[0])
|
||||
nTotalRed = patch.nel*reducedQ->ng[0]*reducedQ->ng[1]*reducedQ->ng[2];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ASMu3D::BasisFunctionCache::internalCleanup ()
|
||||
{
|
||||
if (basis == 1) {
|
||||
mainQ->reset();
|
||||
reducedQ->reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ASMu3D::BasisFunctionCache::setupQuadrature ()
|
||||
{
|
||||
std::array<int,3> order = { patch.getBasis(basis)->order(0),
|
||||
patch.getBasis(basis)->order(1),
|
||||
patch.getBasis(basis)->order(2) };
|
||||
|
||||
// Get Gaussian quadrature points and weights
|
||||
for (int d = 0; d < 3; d++)
|
||||
{
|
||||
mainQ->ng[d] = patch.getNoGaussPt(order[d]);
|
||||
mainQ->xg[d] = GaussQuadrature::getCoord(mainQ->ng[d]);
|
||||
mainQ->wg[d] = GaussQuadrature::getWeight(mainQ->ng[d]);
|
||||
if (!mainQ->xg[d] || !mainQ->wg[d]) return false;
|
||||
}
|
||||
|
||||
// Get the reduced integration quadrature points, if needed
|
||||
int nRed = integrand ? integrand->getReducedIntegration(mainQ->ng[0]) : 0;
|
||||
if (nRed > 0)
|
||||
{
|
||||
reducedQ->xg[0] = reducedQ->xg[1] = reducedQ->xg[2] = GaussQuadrature::getCoord(nRed);
|
||||
reducedQ->wg[0] = reducedQ->wg[1] = reducedQ->wg[2] = GaussQuadrature::getWeight(nRed);
|
||||
if (!reducedQ->xg[0] || !reducedQ->wg[0]) return false;
|
||||
} else
|
||||
nRed = mainQ->ng[0];
|
||||
|
||||
reducedQ->ng[0] = reducedQ->ng[1] = reducedQ->ng[2] = nRed;
|
||||
|
||||
// Compute parameter values of the Gauss points over the whole patch
|
||||
mainQ->gpar[0].resize(mainQ->ng[0],patch.nel);
|
||||
mainQ->gpar[1].resize(mainQ->ng[1],patch.nel);
|
||||
mainQ->gpar[2].resize(mainQ->ng[2],patch.nel);
|
||||
if (reducedQ->xg[0]) {
|
||||
reducedQ->gpar[0].resize(reducedQ->ng[0],patch.nel);
|
||||
reducedQ->gpar[1].resize(reducedQ->ng[1],patch.nel);
|
||||
reducedQ->gpar[2].resize(reducedQ->ng[2],patch.nel);
|
||||
}
|
||||
for (size_t iel = 1; iel <= patch.nel; ++iel)
|
||||
{
|
||||
RealArray u, v, w;
|
||||
patch.getGaussPointParameters(u,0,mainQ->ng[0],iel,mainQ->xg[0]);
|
||||
patch.getGaussPointParameters(v,1,mainQ->ng[1],iel,mainQ->xg[1]);
|
||||
patch.getGaussPointParameters(w,2,mainQ->ng[2],iel,mainQ->xg[2]);
|
||||
mainQ->gpar[0].fillColumn(iel,u.data());
|
||||
mainQ->gpar[1].fillColumn(iel,v.data());
|
||||
mainQ->gpar[2].fillColumn(iel,w.data());
|
||||
|
||||
if (reducedQ->xg[0])
|
||||
{
|
||||
patch.getGaussPointParameters(u,0,reducedQ->ng[0],iel,reducedQ->xg[0]);
|
||||
patch.getGaussPointParameters(v,1,reducedQ->ng[1],iel,reducedQ->xg[0]);
|
||||
patch.getGaussPointParameters(w,2,reducedQ->ng[2],iel,reducedQ->xg[0]);
|
||||
reducedQ->gpar[0].fillColumn(iel,u.data());
|
||||
reducedQ->gpar[1].fillColumn(iel,v.data());
|
||||
reducedQ->gpar[2].fillColumn(iel,w.data());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
BasisFunctionVals ASMu3D::BasisFunctionCache::calculatePt (size_t el,
|
||||
size_t gp,
|
||||
bool reduced) const
|
||||
{
|
||||
PROFILE2("Spline evaluation");
|
||||
const std::array<size_t,3> gpIdx = this->gpIndex(gp,reduced);
|
||||
FiniteElement fe;
|
||||
fe.u = this->getParam(0,el,gpIdx[0],reduced);
|
||||
fe.v = this->getParam(1,el,gpIdx[1],reduced);
|
||||
fe.w = this->getParam(2,el,gpIdx[2],reduced);
|
||||
|
||||
const LR::Element* elm = patch.lrspline->getElement(el);
|
||||
std::array<double,3> du;
|
||||
du[0] = elm->umax() - elm->umin();
|
||||
du[1] = elm->vmax() - elm->vmin();
|
||||
du[2] = elm->wmax() - elm->wmin();
|
||||
|
||||
return this->calculatePrm(fe,du,el,gp,reduced);
|
||||
}
|
||||
|
||||
|
||||
BasisFunctionVals ASMu3D::BasisFunctionCache::
|
||||
calculatePrm (FiniteElement& fe,
|
||||
const std::array<double,3>& du,
|
||||
size_t el, size_t gp, bool reduced) const
|
||||
{
|
||||
BasisFunctionVals result;
|
||||
const BezierExtract& b = reduced ? reducedB : mainB;
|
||||
RealArray extrMat;
|
||||
patch.getBasis(basis)->getBezierExtraction(el,extrMat);
|
||||
Matrix C;
|
||||
const LR::Element* elm = patch.getBasis(basis)->getElement(el);
|
||||
C.resize(elm->nBasisFunctions(), b.N.rows());
|
||||
C.fill(extrMat.data(),extrMat.size());
|
||||
|
||||
if (nderiv == 1 || reduced) {
|
||||
Matrix B(b.N.rows(), 4);
|
||||
B.fillColumn(1, b.N.getColumn(gp+1));
|
||||
B.fillColumn(2, b.dNdu.getColumn(gp+1)*2.0/du[0]);
|
||||
B.fillColumn(3, b.dNdv.getColumn(gp+1)*2.0/du[1]);
|
||||
B.fillColumn(4, b.dNdw.getColumn(gp+1)*2.0/du[2]);
|
||||
|
||||
patch.evaluateBasis(fe, result.dNdu, C, B, basis);
|
||||
result.N = fe.N;
|
||||
} else if (nderiv == 2) {
|
||||
patch.evaluateBasis(el, fe, result.dNdu, result.d2Ndu2, basis);
|
||||
result.N = fe.N;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void ASMu3D::BasisFunctionCache::calculateAll ()
|
||||
{
|
||||
PROFILE2("Spline evaluation");
|
||||
// Evaluate basis function values and derivatives at all integration points.
|
||||
// We do this before the integration point loop to exploit multi-threading
|
||||
// in the integrand evaluations, which may be the computational bottleneck.
|
||||
size_t iel, jp, rp;
|
||||
for (iel = jp = rp = 0; iel < patch.nel; iel++)
|
||||
{
|
||||
for (int k = 0; k < reducedQ->ng[2]; k++)
|
||||
for (int j = 0; j < mainQ->ng[1]; j++)
|
||||
for (int i = 0; i < mainQ->ng[0]; i++, jp++)
|
||||
values[jp] = this->calculatePt(iel,(k*mainQ->ng[1]+j)*mainQ->ng[0]+i,false);
|
||||
|
||||
if (reducedQ->xg[0])
|
||||
for (int k = 0; k < reducedQ->ng[2]; k++)
|
||||
for (int j = 0; j < reducedQ->ng[1]; j++)
|
||||
for (int i = 0; i < reducedQ->ng[0]; i++, rp++)
|
||||
valuesRed[rp] = this->calculatePt(iel,
|
||||
(k*reducedQ->ng[1]+j)*reducedQ->ng[0]+i,true);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "ASMLRSpline.h"
|
||||
#include "ASM3D.h"
|
||||
#include "BasisFunctionCache.h"
|
||||
#include "LRSpline/LRSpline.h"
|
||||
#include "ThreadGroups.h"
|
||||
#include <memory>
|
||||
@ -42,6 +43,71 @@ namespace LR {
|
||||
|
||||
class ASMu3D : public ASMLRSpline, public ASM3D
|
||||
{
|
||||
protected:
|
||||
//! \brief Implementation of basis function cache.
|
||||
class BasisFunctionCache : public ::BasisFunctionCache<3>
|
||||
{
|
||||
public:
|
||||
//! \brief The constructor initializes the class.
|
||||
//! \param pch Patch the cache is for
|
||||
//! \param plcy Cache policy to use
|
||||
//! \param b Basis to use
|
||||
BasisFunctionCache(const ASMu3D& pch, ASM::CachePolicy plcy, int b);
|
||||
|
||||
//! \brief Constructor reusing quadrature info from another instance.
|
||||
//! \param cache Instance holding quadrature information
|
||||
//! \param b Basis to use
|
||||
BasisFunctionCache(const BasisFunctionCache& cache, int b);
|
||||
|
||||
//! \brief Empty destructor.
|
||||
virtual ~BasisFunctionCache() = default;
|
||||
|
||||
protected:
|
||||
//! \brief Implementation specific initialization.
|
||||
bool internalInit() override;
|
||||
|
||||
//! \brief Implementation specific cleanup.
|
||||
void internalCleanup() override;
|
||||
|
||||
//! \brief Calculates basis function info in a single integration point.
|
||||
//! \param el Element of integration point (0-indexed)
|
||||
//! \param gp Integration point on element (0-indexed)
|
||||
//! \param reduced If true, returns values for reduced integration scheme
|
||||
BasisFunctionVals calculatePt(size_t el, size_t gp, bool reduced) const override;
|
||||
|
||||
//! \brief Calculates basis function info in a single integration point.
|
||||
//! \param fe Finite element information in integration point
|
||||
//! \param el Element of integration point (0-indexed)
|
||||
//! \param du Element size in parameter space
|
||||
//! \param gp Integration point on element (0-indexed)
|
||||
//! \param reduced If true, returns values for reduced integration scheme
|
||||
BasisFunctionVals calculatePrm(FiniteElement& fe,
|
||||
const std::array<double,3>& du,
|
||||
size_t el, size_t gp, bool reduced) const;
|
||||
|
||||
//! \brief Calculates basis function info in all integration points.
|
||||
void calculateAll() override;
|
||||
|
||||
//! \brief Struct holding bezier extraction matrices.
|
||||
struct BezierExtract {
|
||||
Matrix N; //!< Basis function values
|
||||
Matrix dNdu; //!< Basis function u-derivatives
|
||||
Matrix dNdv; //!< Basis function v-derivatives
|
||||
Matrix dNdw; //!< Basis function w-derivatives
|
||||
};
|
||||
|
||||
BezierExtract mainB; //!< Bezier extraction for main basis
|
||||
BezierExtract reducedB; //!< Bezier extraction for reduced basis
|
||||
|
||||
const ASMu3D& patch; //!< Reference to patch cache is for
|
||||
|
||||
int basis; //!< Basis to use
|
||||
|
||||
private:
|
||||
//! \brief Configure quadratures.
|
||||
bool setupQuadrature();
|
||||
};
|
||||
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
explicit ASMu3D(unsigned char n_f = 3);
|
||||
@ -646,6 +712,9 @@ protected:
|
||||
const Matrices& bezierExtract; //!< Bezier extraction matrices
|
||||
Matrices myBezierExtract; //!< Bezier extraction matrices
|
||||
|
||||
//! Basis function cache
|
||||
std::vector<std::unique_ptr<BasisFunctionCache>> myCache;
|
||||
|
||||
private:
|
||||
mutable double vMin; //!< Minimum element volume for adaptive refinement
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user