G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsPatchRule.hpp
Go to the documentation of this file.
1
14#pragma once
15
16#include <gsCore/gsBasis.h>
18#include <gsIO/gsOptionList.h>
19
20namespace gismo
21{
22
23template<class T>
25 const index_t degree,
26 const index_t regularity,
27 const bool overintegrate,
28 const short_t fixDir
29 )
30 :
31 m_basis(&basis),
32 m_deg(degree),
33 m_reg(regularity),
34 m_over(overintegrate),
35 m_fixDir(fixDir)
36{
37 GISMO_ENSURE(m_reg<m_deg,"regularity cannot be greater or equal to the order!");
38 // Initialize some stuff
39 m_dim = m_basis->dim();
40
41 GISMO_ASSERT( m_fixDir < short_t(m_dim) && m_fixDir>-2, "Invalid input fixDir = "<<m_fixDir);
42
43 m_nodes.resize(m_dim);
44 m_weights.resize(m_dim);
45 m_maps.resize(m_dim);
46
47 gsKnotVector<T> knots;
48 gsMatrix<T> greville;
49 gsVector<T> integral;
50 gsBSplineBasis<T> * Bbasis;
51
52 // Loop over dimensions of the basis and store the nodes and weights for each dimension
53 for (size_t d = 0; d != m_dim; d++)
54 {
55 m_end = m_basis->support().col(1);
56 if (short_t(d)==m_fixDir && m_fixDir!=-1)
57 {
58 m_nodes[d].resize(2);
59 m_nodes[d]<<0,1;
60 m_weights[d].resize(2);
61 m_weights[d]<<1,1;
62 }
63 else
64 {
65 // Construct temporary basis (must be B-spline because we use knots!)
66 Bbasis = const_cast<gsBSplineBasis<T> *>(static_cast<const gsBSplineBasis<T> * >(&m_basis->component(d)));
67
68 // Find the knots
69 knots = this->_init(Bbasis);
70 // Compute exact integrals
71 #if __cplusplus >= 201103L || _MSC_VER >= 1600
72 std::tie(greville,integral) = this->_integrate(knots);
73 #else
74 std::pair< gsMatrix<T>,gsVector<T> > tmp1 = this->_integrate(knots);
75 tmp1.first.swap(greville);
76 tmp1.second.swap(integral);
77 #endif
78
79 // Compute quadrule
80 #if __cplusplus >= 201103L || _MSC_VER >= 1600
81 std::tie(m_nodes[d],m_weights[d]) = this->_compute(knots,greville,integral);
82 #else
83 std::pair< gsVector<T>,gsVector<T> > tmp2 = this->_compute(knots,greville,integral);
84 tmp2.first.swap(m_nodes[d]);
85 tmp2.second.swap(m_weights[d]);
86 #endif
87 }
88
89 // Construct a map with the nodes and the weights
90 for (index_t k=0; k!=m_nodes[d].size(); k++)
91 m_maps[d][m_nodes[d].at(k)] = m_weights[d].at(k);
92
93 }
94}
95
96
97
98/*
99 Maps as follows:
100
101 COORDINATES
102 d=1:[x1 x2 x3 x4]
103
104 d=2:[x1 x2 x3 x4][x1 x2 x3 x4][x1 x2 x3 x4][x1 x2 x3 x4]
105 [y1 y1 y1 y1][y2 y2 y2 y2][y3 y3 y3 y3][y4 y4 y4 y4]
106
107 d=3:[x1 x2 x3 x4][x1 x2 x3 x4][x1 x2 x3 x4][x1 x2 x3 x4]...
108 [y1 y1 y1 y1][y2 y2 y2 y2][y3 y3 y3 y3][y4 y4 y4 y4]...
109 [z1 z1 z1 z1][z1 z1 z1 z1][z1 z1 z1 z1][z1 z1 z1 z1]...
110
111 [x1 x2 x3 x4][x1 x2 x3 x4][x1 x2 x3 x4][x1 x2 x3 x4]...
112 [y1 y1 y1 y1][y2 y2 y2 y2][y3 y3 y3 y3][y4 y4 y4 y4]...
113 [z2 z2 z2 z2][z2 z2 z2 z2][z2 z2 z2 z2][z2 z2 z2 z2]...
114
115 [x1 x2 x3 x4][x1 x2 x3 x4][x1 x2 x3 x4][x1 x2 x3 x4]...
116 [y1 y1 y1 y1][y2 y2 y2 y2][y3 y3 y3 y3][y4 y4 y4 y4]...
117 [z3 z3 z3 z3][z3 z3 z3 z3][z3 z3 z3 z3][z3 z3 z3 z3]...
118
119 [x1 x2 x3 x4][x1 x2 x3 x4][x1 x2 x3 x4][x1 x2 x3 x4]
120 [y1 y1 y1 y1][y2 y2 y2 y2][y3 y3 y3 y3][y4 y4 y4 y4]
121 [z4 z4 z4 z4][z4 z4 z4 z4][z4 z4 z4 z4][z4 z4 z4 z4]
122
123 WEIGHTS
124 d=1:[wx1 wx2 wx3 wx4]
125
126 d=2: [wy1*[wx1 wx2 wx3 wx4]] [wy2*[wx1 wx2 wx3 wx4]] [wy3*[wx1 wx2 wx3 wx4]] [wy4*[wx1 wx2 wx3 wx4]]
127
128 d=3: wz1*[[wy1*[wx1 wx2 wx3 wx4]] [wy2*[wx1 wx2 wx3 wx4]] [wy3*[wx1 wx2 wx3 wx4]] [wy4*[wx1 wx2 wx3 wx4]]]...
129 wz2*[[wy1*[wx1 wx2 wx3 wx4]] [wy2*[wx1 wx2 wx3 wx4]] [wy3*[wx1 wx2 wx3 wx4]] [wy4*[wx1 wx2 wx3 wx4]]]...
130 wz3*[[wy1*[wx1 wx2 wx3 wx4]] [wy2*[wx1 wx2 wx3 wx4]] [wy3*[wx1 wx2 wx3 wx4]] [wy4*[wx1 wx2 wx3 wx4]]]...
131 wz4*[[wy1*[wx1 wx2 wx3 wx4]] [wy2*[wx1 wx2 wx3 wx4]] [wy3*[wx1 wx2 wx3 wx4]] [wy4*[wx1 wx2 wx3 wx4]]]
132*/
133template<class T>
135 const gsVector<T>& upper,
136 gsMatrix<T> & nodes,
137 gsVector<T> & weights ) const
138{
139 // First, we compute the nodes and weights that are between the lower and upper corners.
140 // This number can be different per element
141 // we also compute the total number of points in the tensor product (size)
142 index_t size = 1;
143 std::vector<gsVector<T> > elNodes(m_dim), elWeights(m_dim);
144 index_t k = 0; // counter per direction d
145 for (size_t d = 0; d!=m_dim; d++)
146 {
147 elNodes[d].resize(m_nodes[d].size());
148 elWeights[d].resize(m_weights[d].size());
149 for (typename std::map<T,T>::const_iterator it = m_maps[d].lower_bound(lower[d]); it!= ( upper[d]==m_end[d] ? m_maps[d].end() : m_maps[d].lower_bound(upper[d]) ); it++, k++) // lower_bound = geq, upper_bound= greather than
150 {
151 elNodes[d].at(k) = it->first;
152 elWeights[d].at(k) = it->second;
153 }
154 elNodes[d].conservativeResize(k);
155 elWeights[d].conservativeResize(k);
156 size *= elNodes[d].size(); // compute tensor size
157 k = 0; // reset counter
158 }
159
160 // This could work. However, in cases when there are elements which have no quadPoint, it goes wrong
161 // this->computeTensorProductRule_into(elNodes,elWeights,nodes,weights);
162
163 // initialize the number of nodes and weights
164 nodes.resize(m_dim,size);
165 weights.resize(size);
166 if (size==0)
167 return;
168
169 // Now we fill the matrix with the points and we construct the tensor product (according to the scheme on top)
170 gsMatrix<T> tmpNodes, tmpWeights;
171 gsVector<T> ones;
172 tmpNodes = elNodes[0].transpose();
173 tmpWeights = elWeights[0].transpose();
174 size = 1;
175 for (size_t d = 1; d!=m_dim; d++)
176 {
177 nodes.block( 0, 0, d, tmpNodes.cols()*elNodes[d].size() ) = tmpNodes.replicate(1,elNodes[d].size());
178
179 ones.setOnes(tmpNodes.cols());
180 for (k = 0; k != elNodes[d].size(); k++)
181 {
182 nodes.block(d,k*ones.size(),1,ones.size()) = ones.transpose()*elNodes[d].at(k);
183 weights.segment(k*ones.size(),ones.size()) = (ones.transpose()*elWeights[d].at(k)).cwiseProduct(tmpWeights);
184 }
185
186 tmpWeights.transpose() = weights.segment(0,tmpWeights.cols()*elWeights[d].size());
187 tmpNodes = nodes.block( 0, 0, d+1, tmpNodes.cols()*elNodes[d].size() );
188 }
189};
190
191template<class T> void
192gsPatchRule<T>::mapTo( T startVal, T endVal,
193 gsMatrix<T> & nodes, gsVector<T> & weights ) const
194{
195 GISMO_ASSERT( 1 == m_nodes.size(), "Inconsistent quadrature mapping (dimension != 1)");
196
197 nodes.resize(1,m_nodes[0].size());
198 weights.resize(m_weights[0].size());
199 index_t k=0;
200 for (typename std::map<T,T>::const_iterator it = m_maps[0].lower_bound(startVal); it!= ( endVal==m_end[0] ? m_maps[0].end() : m_maps[0].lower_bound(endVal) ); it++, k++) // lower_bound = geq, upper_bound= greather than
201 {
202 nodes.at(k) = it->first;
203 weights.at(k) = it->second;
204 }
205 nodes.conservativeResize(1,k);
206 weights.conservativeResize(k);
207}
208
209template<class T>
211{
212 // get the knot vector and the size of the basis
213 gsKnotVector<T> knots = Bbasis->knots();
214 index_t size = Bbasis->size();
215
216 // check the difference in the current order and the desired order
217 index_t pdiff = m_deg - knots.degree();
218 // check the difference in the current regularity and the desired regularity
219 std::vector<index_t> multiplicities = knots.multiplicities();
220 index_t rmin = *std::min_element(multiplicities.begin(), multiplicities.end());
221 index_t rdiff = (m_deg-m_reg)-rmin ;
222
223 // Increase order and regularity
224 if (pdiff>0)
225 knots.degreeIncrease(pdiff);
226 else if (pdiff<0)
227 knots.degreeDecrease(-pdiff);
228 if (rdiff>0)
229 knots.increaseMultiplicity(rdiff);
230 else if (rdiff>0)
231 knots.reduceMultiplicity(-rdiff);
232
234 size = basis.size();
235
236 // If basis should be over-integrated, then add extra knots in the boundary elements
237 if (m_over)
238 {
239 index_t numOver = knots.degree()-1;
240
241 T lowerLength = (knots(1)-knots.first())/static_cast<T>(numOver+1);
242 T upperLength = (knots.last()-knots(knots.uSize()-2))/static_cast<T>(numOver+1);
243 for (index_t k=0; k!=numOver; k++)
244 {
245 knots.insert(knots.first()+static_cast<T>(k+1)*lowerLength);
246 knots.insert(knots.last()-static_cast<T>(k+1)*upperLength);
247 }
248
249 size += 2*numOver;
250 }
251
252 // Add a middle knot if the size of the knot vector is odd
253 if (size % 2 == 1)
254 {
255 typedef typename gsKnotVector<T>::const_iterator knotIterator;
256 knotIterator prevKnot = knots.begin();
257 std::vector<T> diff;
258 for (knotIterator it = knots.begin()+1; it!=knots.end(); it++ )
259 {
260 diff.push_back(*it-*prevKnot);
261 prevKnot = it;
262 }
263
264 T max = *std::max_element(diff.begin(),diff.end());
265 std::vector<index_t> maxIdx;
266 index_t k=0;
267 for (typename std::vector<T>::iterator it = diff.begin(); it!=diff.end(); it++,k++)
268 {
269 if (math::abs(*it-max)/(max)<1e-15)//warning: fixed acuracy
270 maxIdx.push_back(k);
271 }
272
273 const index_t i = maxIdx.at(
274 static_cast<index_t>(std::ceil(maxIdx.size()/2.))-1);
275 knots.insert((knots.at(i) + knots.at(i+1))/2.) ;
276
277 /* ALTERNATIVE (does not work well)
278 T first = knots.first();
279 T last = knots.last();
280 T knot = (last - first) / 2.0;
281
282 knots.insert( knot );
283
284 size++;
285 */
286
287 }
288 return knots;
289};
290
291template <class T>
292std::pair<gsMatrix<T>,gsVector<T> > gsPatchRule<T>::_integrate(const gsKnotVector<T> & knots ) const
293{
294 // Obtain a temporary bspline basis and quadrule
296 gsQuadRule<T> quRule = gsGaussRule<T>(basis,1,1);
297
298
299 // obtain the greville points
300 gsMatrix<T> greville;
301 knots.greville_into(greville);
302
303 gsMatrix<T> integrals(basis.size(),1);
304 integrals.setZero();
305 gsMatrix<T> nodes, tmp;
306 gsMatrix<index_t> actives;
307 gsVector<T> weights;
308
309 // obtain the exact integrals of the functions
310 typename gsBasis<T>::domainIter domIt = basis.makeDomainIterator();
311 for (; domIt->good(); domIt->next() )
312 {
313 quRule.mapTo(domIt->lowerCorner(),domIt->upperCorner(),nodes,weights);
314 basis.active_into(nodes,actives);
315 basis.eval_into(nodes,tmp);
316 tmp *= weights;
317 for (index_t k = 0; k!=weights.size(); k++)
318 integrals(actives.at(k),0) += tmp(k,0);
319 }
320
321 return std::make_pair(greville,integrals);
322};
323
324template <class T>
325std::pair<gsVector<T>,gsVector<T> > gsPatchRule<T>::_compute(const gsKnotVector<T> & knots,
326 const gsMatrix<T> & greville,
327 const gsVector<T> & integrals,
328 const T tol) const
329{
330 // Initialization
331 gsVector<T> nodes, weights;
333 gsQuadRule<T> quRule = gsGaussRule<T>(basis,1,1);
334 index_t size = basis.size();
335 GISMO_ENSURE((size % 2 == 0),"Number of points should be even!");
336
337 // Construct initial guess
338 nodes.resize(size/2);
339 weights.resize(size/2);
340 for (index_t k = 0; k!=size/2; k++)
341 {
342 nodes.at(k) = 0.5 * (greville.at(2*k) + greville.at(2*k+1));
343 weights.at(k) = integrals(2*k,0) + integrals(2*k+1,0);
344 }
345
346 // Initialize Newton iterations
347 index_t itMax = 100;
348 gsMatrix<index_t> actives;
349 gsMatrix<T> vals,dvals,vals_tmp,dvals_tmp,res,dres;
350 gsVector<T> update(size);
351 vals.resize(size,size/2); vals.setZero(); // Jacobian: dF/dw
352 dvals.resize(size,size/2); dvals.setZero(); // Jacobian: dF/dxi
353 index_t it;
354
355 // Newton Iterations
356 for (it = 0; it != itMax; it++)
357 {
358 // Compute matrix with values and derivatives of the basis on the quadrature point estimates
359 basis.active_into(nodes.transpose(),actives);
360 basis.eval_into(nodes.transpose(),vals_tmp);
361 basis.deriv_into(nodes.transpose(),dvals_tmp);
362 for (index_t act=0; act!=actives.rows(); act++)
363 for (index_t pt=0; pt!=actives.cols(); pt++)
364 {
365 vals(actives(act,pt),pt) = vals_tmp(act,pt); // Jacobian: dF/dw
366 dvals(actives(act,pt),pt) = dvals_tmp(act,pt);// Jacobian: dF/dxi
367 }
368
369 // Compute the residual (res) and the Jacobian (dres)
370 res = vals * weights - integrals; // Residual
371 dres = gsMatrix<T>::Zero(size,size);
372 dres.block(0,0,size,size/2) = vals;
373 dres.block(0,size/2,size,size/2) = dvals * weights.asDiagonal();
374
375 // Compute the Newton update
376 m_solver.compute(dres.sparseView());
377 update = m_solver.solve(-res);
378
379 // Update the weights and the nodes
380 weights += update.head(size/2);
381 nodes += update.tail(size/2);
382
383 GISMO_ENSURE(nodes.minCoeff() > knots.first(),"Construction failed: min(nodes) < min(knots) minCoef = "<<nodes.minCoeff()<<"; min(knots) = "<<knots.first());
384 GISMO_ENSURE(nodes.maxCoeff() < knots.last(),"Construction failed: max(nodes) > max(knots) maxCoef = "<<nodes.maxCoeff()<<"; min(knots) = "<<knots.last());
385
386 // Check convergence
387 if (res.norm() < tol)
388 break;
389 }
390 GISMO_ENSURE(it+1!=itMax,"Maximum iterations reached");
391 return std::make_pair(nodes,weights);
392}
393
394} // namespace gismo
A univariate B-spline basis.
Definition gsBSplineBasis.h:700
A basis represents a family of scalar basis functions defined over a common parameter domain.
Definition gsBasis.h:79
Class that represents the (tensor) Gauss-Legendre quadrature rule.
Definition gsGaussRule.h:28
Class for representing a knot vector.
Definition gsKnotVector.h:80
void greville_into(gsMatrix< T > &result) const
Definition gsKnotVector.hpp:991
void reduceMultiplicity(const mult_t i=1, bool boundary=false)
Definition gsKnotVector.hpp:903
T at(const size_t &i) const
Returns the value of the i - th knot (counted with repetitions).
Definition gsKnotVector.h:865
iterator begin() const
Returns iterator pointing to the beginning of the repeated knots.
Definition gsKnotVector.hpp:117
T first() const
Get the first knot.
Definition gsKnotVector.h:721
int degree() const
Returns the degree of the knot vector.
Definition gsKnotVector.hpp:700
multContainer multiplicities() const
Returns vector of multiplicities of the knots.
Definition gsKnotVector.hpp:714
T last() const
Get the last knot.
Definition gsKnotVector.h:728
void degreeIncrease(int const &i=1)
Definition gsKnotVector.h:759
void insert(T knot, mult_t mult=1)
Inserts knot knot into the knot vector with multiplicity mult.
Definition gsKnotVector.hpp:325
void degreeDecrease(int const &i=1, bool updateInterior=false)
Inverse of degreeIncrease.
Definition gsKnotVector.h:775
size_t uSize() const
Number of unique knots (i.e., without repetitions).
Definition gsKnotVector.h:245
iterator end() const
Returns iterator pointing past the end of the repeated knots.
Definition gsKnotVector.hpp:124
void increaseMultiplicity(const mult_t i=1, bool boundary=false)
Definition gsKnotVector.hpp:874
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
T at(index_t i) const
Returns the i-th element of the vectorization of the matrix.
Definition gsMatrix.h:211
gsPatchRule()
Default empty constructor.
Definition gsPatchRule.h:91
std::pair< gsVector< T >, gsVector< T > > _compute(const gsKnotVector< T > &knots, const gsMatrix< T > &greville, const gsVector< T > &integrals, const T tol=1e-10) const
Computes the points and weights for the patch rule using Newton iterations.
Definition gsPatchRule.hpp:325
gsKnotVector< T > _init(const gsBSplineBasis< T > *Bbasis) const
Initializes the knot vector for the patch-rule implementation.
Definition gsPatchRule.hpp:210
void mapTo(const gsVector< T > &lower, const gsVector< T > &upper, gsMatrix< T > &nodes, gsVector< T > &weights) const
Maps the points in the d-dimensional cube with points lower and upper.
Definition gsPatchRule.hpp:134
std::pair< gsMatrix< T >, gsVector< T > > _integrate(const gsKnotVector< T > &knots) const
Integrates all basis functions from a knot vector (numerically with Gauss)
Definition gsPatchRule.hpp:292
Class representing a reference quadrature rule.
Definition gsQuadRule.h:29
virtual void mapTo(const gsVector< T > &lower, const gsVector< T > &upper, gsMatrix< T > &nodes, gsVector< T > &weights) const
Maps quadrature rule (i.e., points and weights) from the reference domain to an element.
Definition gsQuadRule.h:177
const KnotVectorType & knots(int i=0) const
Returns the knot vector of the basis.
Definition gsBSplineBasis.h:371
index_t size() const
Returns the number of elements in the basis.
Definition gsBSplineBasis.h:165
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition gsVector.h:37
T at(index_t i) const
Returns the i-th element of the vector.
Definition gsVector.h:177
Provides declaration of BSplineBasis class.
Provides declaration of Basis abstract interface.
#define short_t
Definition gsConfig.h:35
#define index_t
Definition gsConfig.h:32
#define GISMO_ENSURE(cond, message)
Definition gsDebug.h:102
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Provides a list of labeled parameters/options that can be set and accessed easily.
The G+Smo namespace, containing all definitions for the library.