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