G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsDPatch.hpp
Go to the documentation of this file.
1
17#include <gsSolver/gsBlockOp.h>
18#include <gsSolver/gsMatrixOp.h>
19
21
22// #define PI 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647
23
24namespace gismo
25{
26 // Constructors
27 template<short_t d,class T>
29 :
30 Base(patches)
31 {
32 this->defaultOptions();
33 }
34
35 // Constructors
36 template<short_t d,class T>
38 :
39 Base(bases)
40 {
41 this->defaultOptions();
42 }
43
44 template<short_t d,class T>
46 {
47 // freeAll(m_bases);
48 }
49
50 template<short_t d,class T>
52 {
53 Base::defaultOptions();
54 m_options.addInt("Pi","Pi matrix to be applied, 0: Non-negative, 1: Idempotent",0);
55 m_options.addInt("RefLevel","Refinement level",0);
56 m_options.addReal("Beta","Beta parameter",0.4);
57 }
58
59 /*=====================================================================================
60 Coefficients
61 =====================================================================================*/
62 template<short_t d,class T>
64 {
65 GISMO_ASSERT(m_mapModified.isFinalized(),"Mapper is not finalized");
66
67 gsMatrix<T> coefs(m_mapModified.freeSize(),patches.geoDim());
68
69 index_t size;
70 for (size_t p=0; p!=m_bases0.nBases(); p++) // patches
71 {
72 gsMatrix<T> tmpCoefs;
73 if (m_tMatrices[p].rows()!=0 && m_tMatrices[p].cols()!=0)
74 tmpCoefs = m_tMatrices[p]*patches.patch(p).coefs();
75 else
76 tmpCoefs = patches.patch(p).coefs();
77
78 size = m_mapModified.patchSize(p);
79 for (index_t k=0; k!=size; k++)
80 {
81 if (m_mapModified.is_free(k,p,0))
82 coefs.row(m_mapModified.index(k,p,0)) = tmpCoefs.row(k);
83 }
84 }
85
86 // Correct the v=3 boundary vertices:
87 std::fill(m_vertCheck.begin(), m_vertCheck.end(), false);
88 for (size_t p=0; p!=m_bases0.nBases(); p++)
89 {
90 for (index_t c=1; c<5; c++)
91 {
92 index_t idx = this->_vertIndex(p,c);
93 if(m_vertCheck[ idx] )
94 continue;
95
96 patchCorner pcorner(p,c);
97 std::pair<index_t,bool> vdata = this->_vertexData(pcorner); // corner c
98
99 if (std::count(m_C0s.begin(), m_C0s.end(), pcorner))
100 continue;
101 if (vdata.first==3 && !vdata.second)
102 {
103 std::vector<patchCorner> otherCorners;
104 std::vector<patchSide> csides;
105
106 m_topology.getCornerList(pcorner,otherCorners);
107 index_t b00 = -1, b11i = -1;
108 std::vector<index_t> b11b;
109 for (std::vector<patchCorner>::iterator corner = otherCorners.begin(); corner != otherCorners.end(); corner++)
110 {
111 corner->getContainingSides(d,csides);
112 if ( m_topology.isBoundary(csides[0]) || m_topology.isBoundary(csides[1]) ) //
113 b11b.push_back(m_mapModified.index( this->_indexFromVert(m_bases0,1,*corner,csides[0],1) , corner->patch) );
114 else if (b11i==-1)
115 b11i = m_mapModified.index( this->_indexFromVert(m_bases0,1,*corner,csides[0],1) , corner->patch);
116 else
117 GISMO_ERROR("b11i is already assigned?");
118
119 if (corner==otherCorners.begin())
120 {
121 const gsBasis <T> * basis = &m_bases0.basis(corner->patch);
122 b00 = m_mapModified.index( basis->functionAtCorner(corner->corner()), corner->patch );
123 }
124
125 idx = this->_vertIndex(corner->patch,corner->corner());
126 m_vertCheck[ idx ] = true;
127 }
128 coefs.row(b00) = coefs.row(b11b[0]) + coefs.row(b11b[1]) - coefs.row(b11i);
129 }
130 else
131 m_vertCheck[ idx ] = true;
132
133 }
134 }
135
136 return coefs;
137 }
138
139 /*=====================================================================================
140 Construction functions
141 =====================================================================================*/
142
143 template<short_t d,class T>
145 {
146 // Cast all patches of the mp object to THB splines
147 for (size_t k=0; k!=m_Bbases.nBases(); ++k)
148 {
149 // Check the basis and make the new level(s)
150 std::vector<gsKnotVector<T>> KVs(d);
151 index_t degree;
152 if ( const gsTensorBSplineBasis<d,T> * tbasis0 = dynamic_cast<const gsTensorBSplineBasis<d,T> * > (&m_Bbases.basis(k)) )
153 {
154 gsTHBSplineBasis<d,T> thbBasis(*tbasis0,true);
155 for (short_t dim=0; dim!=d; dim++)
156 {
157 GISMO_ENSURE(tbasis0->degree(dim)>=2,"Degree of the basis must be larger than or equal to 2, but is "<<tbasis0->degree(dim)<<" (component "<<d<<")");
158 const gsKnotVector<T> & KV = tbasis0->knots(dim);
159 KVs[dim] = tbasis0->knots(dim);
160 degree = KVs[dim].degree();
161
162 // Every knot needs multiplicity p-1. For degree 2, this gives the same basis!
163 for (typename gsKnotVector<T>::uiterator knot = std::next(KV.ubegin()); knot!=std::prev(KV.uend()); knot++)
164 KVs[dim].insert(*knot,degree-KV.multiplicity(*knot)-1);
165
166 }
167 // Create level 1
168 gsTensorBSplineBasis<d,T> tbasis1(KVs);
169 thbBasis.addLevel(tbasis1);
170
171 // Create level 2
172 gsTensorBSplineBasis<d,T> tbasis2 = tbasis1;
173 for (short_t dim = 0; dim!=d; dim++)
174 tbasis2.uniformRefine(1,tbasis2.degree(dim)-1,dim);
175 thbBasis.addLevel(tbasis2);
176
177 m_bases0.addBasis(thbBasis.clone());
178 }
179 else
180 GISMO_ERROR("Basis can only be constructed on gsTensorBSplineBasis");
181 }
182 m_bases0.setTopology(m_topology);
183 m_bases = m_bases0;
184 }
185
186 template <short_t d, class T>
187 void gsDPatch<d,T>::_refBoxes(std::vector<std::vector<index_t>> & patchBoxes)
188 {
189 patchBoxes.clear();
190 patchBoxes.resize(m_bases0.size());
191
192 // prepare the geometry
193 gsMatrix<index_t> box(d,2);
194 std::vector<index_t> boxes;
195 gsVector<bool> pars;
196 index_t nelements;
197 index_t degree;
198 patchCorner corner;
199 std::vector<patchCorner> cornerList;
200 std::vector<std::vector<patchCorner> > cornerLists;
201
202 m_topology.getEVs(cornerLists);
203
204 index_t N = cornerLists.size();
205
206 // Make a mask of corners per patch to track which ones have been handled
207 gsMatrix<bool> mask(m_bases0.nBases(),math::pow(2,d));
208 mask.setConstant(false);
209
210 for (index_t v =0; v<N; v++)
211 {// Loop over EVs
212 for (size_t c = 0; c<cornerLists[v].size(); c++)
213 {// Loop over corners per EV
214 corner = cornerLists[v].at(c);
215 gsHTensorBasis<d,T> * basis = dynamic_cast<gsHTensorBasis<d,T>*>(&m_bases0.basis(corner.patch));
216
217 if (mask(corner.patch,corner.corner()-1))
218 continue;
219
220 corner.parameters_into(d,pars);
221 box.setZero();
222 for (short_t dim = 0; dim!=d; dim++)
223 {
224 const gsKnotVector<T> & KV = basis->tensorLevel(0).knots(dim);
225 degree = KV.degree();
226 nelements = (degree < 4) ? 2 : 1;
227 nelements *= std::pow(2,m_options.getInt("RefLevel"));
228
229 GISMO_ASSERT(nelements<=(index_t)KV.numElements(),"Need more elements than available for refinement around corner "<<corner.corner()<<" of patch "<<corner.patch<<".\n"<<"nelements = "<<nelements<<"; KV.numElements() = "<<KV.numElements()<<"\n");
230
231 box.row(dim).setConstant(pars(dim)*(KV.uSize()-1));
232 box(dim,!pars(dim)) += ( 1 - 2*pars(dim) ) * nelements; // subtracts from box(d,0) if pars(d)==1, adds to box(d,1) if pars(d)==0
233
234 // If all elements in this direction are refined, we need to add the other corner of this side to the list of corners to be refined
235 if ((index_t)KV.numElements()==nelements)
236 {
237 // Get the patch side in the direction of the knot vector KV
238 GISMO_ASSERT(d==2,"This does not work for d!=2!");
239 boxCorner otherCorner;
240 if ((corner.m_index==1 && dim==0) || (corner.m_index==4 && dim==1)) // the other corner is south east
241 otherCorner = 2;
242 else if ((corner.m_index==1 && dim==1) || (corner.m_index==4 && dim==0)) // the other corner is north west
243 otherCorner = 3;
244 else if ((corner.m_index==2 && dim==0) || (corner.m_index==3 && dim==1)) // the other corner is south west
245 otherCorner = 1;
246 else if ((corner.m_index==2 && dim==1) || (corner.m_index==3 && dim==0)) // the other corner is north east
247 otherCorner = 4;
248 else
249 GISMO_ERROR("Combination unknown...");
250
251 patchCorner otherPCorner(corner.patch,otherCorner.m_index);
252
253 cornerList.clear();
254 m_topology.getCornerList(otherPCorner,cornerList);
255 cornerLists.push_back(cornerList);
256 N++;
257 }
258 }
259 boxes.clear();
260 // Assign boxes. This is the box on the current level, level 0.
261 boxes.push_back(0);
262 boxes.insert(boxes.end(), box.data(), box.data()+box.size());
263 patchBoxes.at(corner.patch).insert(patchBoxes.at(corner.patch).end(), boxes.begin(), boxes.end());
264
265 mask(corner.patch,corner.corner()-1) = true;
266 }// Loop over corners per EV
267 }// Loop over EVs
268 }
269
270 template<short_t d,class T>
272 {
273 std::vector< std::vector<index_t> > elVec;
274 this->_refBoxes(elVec);
275 m_tMatrices.resize(m_bases0.nBases());
276 for (size_t p=0; p!=m_bases0.nBases(); p++)
277 {
278 // Transform using gsAsMatrix
279 gsAsMatrix<index_t> boxMat(elVec[p],2*d+1,elVec[p].size()/(2*d+1));
280 boxMat.row(0).array() += 1;
281 boxMat.block(1,0,boxMat.rows()-1,boxMat.cols()).array() *= 2;
282
283 // Refine elements
284 gsHTensorBasis<d,T> *basis = dynamic_cast<gsHTensorBasis<d,T>*>(&m_bases0.basis(p));
285 std::vector< gsSortedVector< index_t > > xmat = basis->getXmatrix();
286 basis->refineElements_withTransfer(elVec[p],m_tMatrices[p]);
287 }
288 m_bases = m_bases0;
289 }
290
291 template<short_t d,class T>
292 void gsDPatch<d,T>::_makeTHB() //IMPLEMENT THIS
293 {
294 gsMultiBasis<> refBases = m_bases;
295 std::vector< std::vector<index_t> > elVec;
296 this->_refBoxes(elVec);
297
299 index_t rows = 0, cols = 0;
300 std::vector<gsEigen::Triplet<T,index_t>> tripletList;
301 for (size_t p=0; p!=m_bases0.nBases(); p++)
302 {
303 // Transform using gsAsMatrix
304 gsAsMatrix<index_t> boxMat(elVec[p],2*d+1,elVec[p].size()/(2*d+1));
305 boxMat.row(0).array() += 2;
306 boxMat.block(1,0,boxMat.rows()-1,boxMat.cols()).array() *= 4;
307
308 gsHTensorBasis<d,T> *basis = dynamic_cast<gsHTensorBasis<d,T>*>(&refBases.basis(p));
309 std::vector< gsSortedVector< index_t > > xmat = basis->getXmatrix();
310 basis->refineElements_withTransfer(elVec[p],tmp);
311 for (index_t i = 0; i<tmp.outerSize(); ++i)
312 for (typename gsSparseMatrix<T>::iterator it(tmp,i); it; ++it)
313 tripletList.push_back(gsEigen::Triplet<T,index_t>(it.row()+rows,it.col()+cols,it.value()));
314
315 rows += tmp.rows();
316 cols += tmp.cols();
317 }
318
319 m_tMatrix.resize(rows,cols);
320 m_tMatrix.setFromTriplets(tripletList.begin(), tripletList.end());
321
322 m_tMatrix.makeCompressed();
323 m_bases = refBases;
324
325 // redefine the mappers
326 // m_mapModified = gsDofMapper(m_bases);
327 m_mapOriginal = gsDofMapper(m_bases);
328 m_mapOriginal.finalize();
329 }
330
331 template<short_t d,class T>
333 {
334 /*
335 Our goal is to create three vectors cij[0], cij[1], cij[2] which all contain the
336 cij[0], cij[1] and cij[2] coefficients of the patches around the EV in the right order
337 (counter)-clockwise.
338 */
339
340 std::vector<std::vector<patchCorner> > cornerLists;
341 m_topology.getEVs(cornerLists);
342
343 if (cornerLists.size()!=0)
344 {
345 // gsWriteCSV(m_matrix.toDense(),"matrix0.csv");
346 m_matrix = m_matrix * m_tMatrix.transpose();
347 // gsWriteCSV(m_tMatrix.toDense(),"matrixTHB.csv");
348 // gsWriteCSV(m_matrix.toDense(),"matrix1.csv");
349
351 std::vector<patchSide> sides(2);
352 std::vector<patchSide> allSides;
353 std::vector<std::vector<patchCorner> > cornerLists;
354 std::vector<patchCorner> corners;
355 std::vector<index_t> allPatches;
356 std::map<index_t,index_t> patches;
357 std::vector<boundaryInterface> interfaces;
358 m_topology.getEVs(cornerLists);
359
360 sparseEntry_t entries;
361
362 if (cornerLists.size()!=0)
363 {
364 for (size_t v =0; v!=cornerLists.size(); v++) // over EVs
365 {
366 patches.clear();
367 index_t N = cornerLists[v].size();
368
369 allPatches.resize(m_bases.nBases());
370 corners.resize(N);
371 interfaces.resize(N);
372
373 std::vector<gsMatrix<index_t>> cij(3);
374 for (index_t k=0; k!=3; k++)
375 cij.at(k) = gsMatrix<index_t>::Zero(N,1);
376
377 std::vector<gsMatrix<index_t>> cijo = cij;
378
379 /*
380 First, we loop over all the interfaces to construct a (counter)clock-wise map for our coefficients
381 Looping clock-wise or counter clock-wise does not matter, as long as the coefficients are neighboring
382 */
383 // Loop over all sides such that we can fill cij[1] and cij[2]. We just start from side 0 of corner 0
384 patchCorner corner = cornerLists[v][0];
385 patchCorner otherCorner = patchCorner(0,0);
386 corner.getContainingSides(d,sides);
387 patchSide side = sides[0];
388 patchSide otherSide;
389 std::vector<patchCorner> pcorners(2);
390
391 // Initialize patch map
392 for (index_t i = 0; i!=N; i++) // over interfaces
393 {
394 patches.insert(std::make_pair(side.patch,i));
395 corners[i] = corner;
396 bool isInterface = m_topology.getInterface(side,interfaces[i]);
397 GISMO_ENSURE(isInterface,"Side must be an interface!");
398
399 std::vector<boxCorner> adjcorners;
400 m_topology.getNeighbour(side,otherSide);
401 otherSide.getContainedCorners(d,adjcorners);
402 for (index_t k=0; k!=N; k++)
403 {
404 if (cornerLists[v][k] == patchCorner(otherSide.patch,adjcorners[0]))
405 otherCorner = patchCorner(otherSide.patch,adjcorners[0]);
406 else if (cornerLists[v][k] == patchCorner(otherSide.patch,adjcorners[1]))
407 otherCorner = patchCorner(otherSide.patch,adjcorners[1]);
408 else continue;
409 }
410 GISMO_ENSURE(otherCorner!=patchCorner(0,0),"Error");
411
412 // interfaces[i] = boundaryInterface(side,otherSide,d);
413 // GISMO_ASSERT(corners[i].patch==interfaces[i].first().patch,"Must be true");
414
415 // get the NEXT side
416 otherCorner.getContainingSides(d,sides);
417 if (otherSide == sides[0])
418 otherSide = sides[1];
419 else if (otherSide == sides[1])
420 otherSide = sides[0];
421 else
422 GISMO_ERROR("An error occurred.");
423
424 corner = otherCorner;
425 side = otherSide;
426 }
427
428 for (index_t i = 0; i!=N; i++) // over corners in EVs
429 {
430
431 otherCorner = interfaces[i].mapCorner(corners[i]);
432
433 if (interfaces[i].first().patch==corners[i].patch)
434 {
435 otherSide = interfaces[i].second();
436 side = interfaces[i].first();
437 }
438 else
439 {
440 otherSide = interfaces[i].first();
441 side = interfaces[i].second();
442 }
443
444 // C11 coefficients
445 cij[0](patches[side.patch],0) = this->_indexFromVert(m_bases,1,corners[i],side,1);
446 // C21 coefficients
447 cij[1](patches[otherSide.patch],0) = this->_indexFromVert(m_bases,2,otherCorner,otherSide,1);
448 // C12 coefficients
449 cij[2](patches[side.patch],0) = this->_indexFromVert(m_bases,2,corners[i],side,1);
450
451 // C11 coefficients
452 cijo[0](patches[side.patch],0) = this->_indexFromVert(m_bases0,1,corners[i],side,1);
453 // C21 coefficients
454 cijo[1](patches[otherSide.patch],0) = this->_indexFromVert(m_bases0,2,otherCorner,otherSide,1);
455 // C12 coefficients
456 cijo[2](patches[side.patch],0) = this->_indexFromVert(m_bases0,2,corners[i],side,1);
457 }
458
459 std::vector<gsMatrix<index_t>> rowIndices(3);
460 for (index_t k=0; k!=3; k++)
461 rowIndices.at(k) = gsMatrix<index_t>::Zero(N,1);
462
463 for (index_t i = 0; i!=N; i++)
464 {
465 corner = corners[i];
466 corner.getContainingSides(d,sides);
467 // we look for the 1,1 index so it does not matter which side we use
468 for (index_t k=0; k!=3; k++)
469 {
470 GISMO_ASSERT(m_mapModified.is_free(cijo[k](i,0),corner.patch),"Something went wrong in the indexing of the sparse matrix for EVs.\n corner = "<<corner.corner()<<"\n patch = "<<corner.patch<<"\n k = "<<k<<"\n i = "<<i<<"\n cijo[k](i,0) = "<<cijo[k](i,0)<<"\n cijo[k] = "<<cijo[k]<<"\n");
471 rowIndices[k](i,0) = m_mapModified.index(cijo[k](i,0),corner.patch);
472 GISMO_ASSERT(m_mapOriginal.is_free(cij[k](i,0),corner.patch),"Something went wrong in the indexing of the sparse matrix for EVs");
473 cij[k](i,0) = m_mapOriginal.index(cij[k](i,0),corner.patch);
474 }
475 }
476
477 gsMatrix<T> Pi = _makePi(N);
478 gsVector<T> c(3*N);
479 index_t colIdx = 0, idx = 0;
480 for (index_t i = 0; i!=N; i++) // for all involved corners
481 {
482 for (index_t k = 0; k!=3; k++) // loop over ij=11,12,21
483 {
484 for (index_t j=0; j!=N; j++) // loop over the connected corners
485 for (index_t l = 0; l!=3; l++) // loop over ij=11,12,21
486 c.at(j+l*N) = m_matrix.coeff(rowIndices[k](i,0),cij[l](j,0));
487 c = Pi * c;
488 for (index_t j=0; j!=N; j++) // loop over the connected corners
489 for (index_t l = 0; l!=3; l++) // loop over ij=11,12,21
490 entries.push_back(std::make_tuple(rowIndices[k](i,0),cij[l](j,0),c.at(j+l*N)));
491 }
492 }
493
494 #pragma omp critical (_computeEV1)
495 _push(entries);
496
497 entries.clear();
498
499 // smoothing center, i.e all 0,0, 1,0 and 0,1 basis functions get the same value as the 1,1
500 for (index_t i = 0; i!=N; i++) // for all involved corners
501 {
502 for (index_t j=0; j!=N; j++) // loop over the connected corners
503 {
504 for (index_t k = 0; k!=3; k++) // loop over ij=11,12,21
505 {
506 corners[j].getContainingSides(d,sides);
508 colIdx = this->_indexFromVert(m_bases,0,corners[j],sides[0],0); // 0,0
509 GISMO_ASSERT(m_mapOriginal.is_free(colIdx,corners[j].patch),"Something went wrong in the indexing of the sparse matrix for EVs");
510 colIdx = m_mapOriginal.index(colIdx,corners[j].patch);
511 entries.push_back(std::make_tuple(rowIndices[k](i,0),colIdx,m_matrix.coeff(rowIndices[k](i,0),cij[0](j,0))));
512
513 colIdx = this->_indexFromVert(m_bases,1,corners[j],sides[0],0); // 1,0
514 GISMO_ASSERT(m_mapOriginal.is_free(colIdx,corners[j].patch),"Something went wrong in the indexing of the sparse matrix for EVs");
515 colIdx = m_mapOriginal.index(colIdx,corners[j].patch);
516 entries.push_back(std::make_tuple(rowIndices[k](i,0),colIdx,m_matrix.coeff(rowIndices[k](i,0),cij[0](j,0))));
517
518 colIdx = this->_indexFromVert(m_bases,1,corners[j],sides[1],0); // 0,1
519 GISMO_ASSERT(m_mapOriginal.is_free(colIdx,corners[j].patch),"Something went wrong in the indexing of the sparse matrix for EVs");
520 colIdx = m_mapOriginal.index(colIdx,corners[j].patch);
521 entries.push_back(std::make_tuple(rowIndices[k](i,0),colIdx,m_matrix.coeff(rowIndices[k](i,0),cij[0](j,0))));
522
523 }
524 }
525 }
526
527 #pragma omp critical (_computeEV2)
528 _push(entries);
529
530 entries.clear();
531
532 // interface smoothing
533 for (index_t i = 0; i!=N; i++) // for all involved interfaces
534 {
535 patchCorner corner = corners[patches[interfaces[i].first().patch]];
536 patchCorner otherCorner = corners[patches[interfaces[i].second().patch]];
537 patchSide side = interfaces[i].first();
538 patchSide otherSide = interfaces[i].second();
539 for (index_t k = 2; k!=4 ; k++)// std::max(basis1->maxDegree(),basis2->maxDegree())+
540 {
541 idx = this->_indexFromVert(m_bases,k,corner,side,0);
542 GISMO_ASSERT(m_mapOriginal.is_free(idx,side.patch),"Something went wrong in the indexing of the sparse matrix for EVs");
543 index_t j0k = m_mapOriginal.index(idx,side.patch);
544
545 idx = this->_indexFromVert(m_bases,k,otherCorner,otherSide,0);
546 GISMO_ASSERT(m_mapOriginal.is_free(idx,otherSide.patch),"Something went wrong in the indexing of the sparse matrix for EVs");
547 index_t jk0 = m_mapOriginal.index(idx,otherSide.patch);
548
549 idx = this->_indexFromVert(m_bases,k,corner,side,1); // point (k,0)
550 GISMO_ASSERT(m_mapOriginal.is_free(idx,side.patch),"Something went wrong in the indexing of the sparse matrix for EVs");
551 index_t jk1 = m_mapOriginal.index(idx,side.patch); // point (k,0)
552
553 idx = this->_indexFromVert(m_bases,k,otherCorner,otherSide,1); // point (k,0)
554 GISMO_ASSERT(m_mapOriginal.is_free(idx,otherSide.patch),"Something went wrong in the indexing of the sparse matrix for EVs");
555 index_t j1k = m_mapOriginal.index(idx,otherSide.patch); // point (k,0)
556
557 index_t row;
558 for (index_t l = 0; l!=3; l++) // loop over ij=11,12,21
559 {
560 for (index_t r=0; r!=N; r++)
561 {
562 row = rowIndices[l](r,0);
563 entries.push_back(std::make_tuple(rowIndices[l](r,0),j0k,0.5 * ( m_matrix.coeff(row,jk1) + m_matrix.coeff(row,j1k) )));
564 entries.push_back(std::make_tuple(rowIndices[l](r,0),jk0,0.5 * ( m_matrix.coeff(row,jk1) + m_matrix.coeff(row,j1k) )));
565 }
566 }
567 }
568 }
569
570 #pragma omp critical (_computeEV3)
571 _push(entries);
572 }
573 }
574 }
575
576 m_matrix.makeCompressed();
577 // gsDebugVar(m_matrix.toDense());
578 }
579
580 template<short_t d,class T>
582 {
583 gsMatrix<T> Pi(3*valence,3*valence);
584 gsMatrix<T> P(valence,9);
585 P.setZero();
586
587 T pi = 4*std::atan(1);
588 T phi = 2*pi / valence;
589 std::complex<T> I(0,1);
590 T beta = m_options.getReal("Beta") * std::pow(0.5,m_options.getInt("RefLevel"));
591 T psi = std::arg( std::complex<T>((T(1.0)+I*beta*T(math::sin(phi)))*math::exp( -I*phi / T(2.0) ) ));
592 if (m_options.getInt("Pi")==0)//idempotent
593 {
594 for (index_t j=0; j!=valence; j++)
595 {
596 P(j,0) = P(j,1) = P(j,2) = P(j,3) = P(j,6) = 1.0 / (3.0 * valence);;
597 P(j,4) = P(j,8) = 1.0 / (3.0 * valence) * ( 1.0 + 3.0*math::cos( j * phi ) );
598 P(j,5) = 1.0 / (3.0 * valence) * ( 1.0 + 3.0*math::cos( 2.0 * psi + j * phi ) );
599 P(j,7) = 1.0 / (3.0 * valence) * ( 1.0 + 3.0*math::cos( 2.0 * psi - j * phi ) );
600 }
601 }
602 else if (m_options.getInt("Pi")==1) //non-negative entries
603 {
604 for (index_t j=0; j!=valence; j++)
605 {
606 P(j,0) = P(j,3) = P(j,6) = 0;
607 P(j,1) = P(j,2) = 1.0 / (2.0 * valence);
608 P(j,4) = P(j,8) = 1.0 / (2.0 * valence) * ( 1.0 + math::cos( j * phi ) );
609 P(j,5) = 1.0 / (2.0 * valence) * ( 1.0 + math::cos( 2.0 * psi + j * phi ) );
610 P(j,7) = 1.0 / (2.0 * valence) * ( 1.0 + math::cos( 2.0 * psi - j * phi ) );
611 }
612 }
613 else
614 GISMO_ERROR("Pi option unknown");
615
616 index_t offsetI, offsetJ = 0;
617 gsMatrix<T> tmp(valence,valence);
618 for (index_t i=0; i!=9; i++)
619 {
620 offsetI = (i / 3)*valence;// std::floor(i/3)
621 offsetJ = (i % 3)*valence;
622 for (index_t j=0; j!=valence; j++ )
623 for (index_t k=0; k!=valence; k++ )
624 {
625 index_t c = (j-k) % valence;
626 if (c < 0)
627 c += valence;
628 tmp(j,k) = P( c, i);
629 }
630
631 // gsDebugVar(offsetI);
632 // gsDebugVar(offsetJ);
633 // tmp.setOnes();
634 // tmp *= i;
635 Pi.block(offsetI,offsetJ,valence, valence) = tmp;
636 }
637
638 return Pi;
639 }
640
641 template<short_t d,class T>
642 void gsDPatch<d,T>::_countDoFs() // also initialize the mappers!
643 {
644 size_t tmp;
645 m_size = tmp = 0;
646 // number of interior basis functions
647 for (size_t p=0; p!=m_bases.nBases(); p++)
648 {
649 tmp += m_bases.basis(p).size();
650 for (index_t k=0; k!=2; k++)
651 {
652 tmp -= m_bases.basis(p).boundaryOffset(boxSide(1),k).size();
653 tmp -= m_bases.basis(p).boundaryOffset(boxSide(2),k).size();
654 tmp -= m_bases.basis(p).boundaryOffset(boxSide(3),k).size()-4;
655 tmp -= m_bases.basis(p).boundaryOffset(boxSide(4),k).size()-4;
656 }
657 }
658
659 // gsDebug<<"Number of interior DoFs: "<<tmp<<"\n";
660 m_size += tmp;
661
662 // interfaces
663 gsBasis<T> * basis1;
664 gsBasis<T> * basis2;
665 gsVector<index_t> indices1,indices2;
666 tmp = 0;
667 for(gsBoxTopology::const_iiterator iit = m_topology.iBegin(); iit!= m_topology.iEnd(); iit++)
668 {
669 basis1 = &m_bases.basis(iit->first().patch);
670 basis2 = &m_bases.basis(iit->second().patch);
671 tmp += basis1->boundary(iit->first().side()).size() - 4;
672 tmp += basis2->boundary(iit->second().side()).size() - 4;
673 }
674 // gsDebug<<"Number of interface DoFs: "<<tmp<<"\n";
675 m_size += tmp;
676
677 // boundaries
678 tmp = 0;
679 for(gsBoxTopology::const_biterator bit = m_topology.bBegin(); bit!= m_topology.bEnd(); bit++)
680 {
681 basis1 = &m_bases.basis(bit->patch);
682 tmp += (basis1->boundaryOffset(bit->side(),0).size() - 4);
683 tmp += (basis1->boundaryOffset(bit->side(),1).size() - 4);
684 }
685 // gsDebug<<"Number of boundary DoFs: "<<tmp<<"\n";
686 m_size += tmp;
687
688 // vertices
689 tmp = 0;
690 std::vector<bool> passed(m_bases.nBases()*4);
691 std::fill(passed.begin(), passed.end(), false);
692
693 std::vector<patchCorner> corners;
694 // index_t corn = 0;
695 for (size_t p=0; p!=m_bases.nBases(); p++)
696 for (index_t c=1; c<5; c++)
697 {
698 index_t idx = this->_vertIndex(p,c);
699 if (!passed.at(idx))
700 {
701 m_topology.getCornerList(patchCorner(p,c),corners);
702
703 for (size_t k=0; k!=corners.size(); k++)
704 passed.at(this->_vertIndex(corners[k].patch,corners[k])) = true;
705
706 std::pair<index_t,bool> vdata = this->_vertexData(patchCorner(p,c)); // corner c
707 bool C0 = m_C0s[idx];
708 if ((!vdata.second) && vdata.first==1) // valence = 1, must be a boundary vertex
709 tmp += 4;
710 else if ((!vdata.second) && vdata.first==2 && !C0)
711 tmp += 4;
712 else if ((!vdata.second) && vdata.first>2 && !C0)
713 tmp += 4;
714 else if ((!vdata.second) && vdata.first==2 && C0)
715 tmp += 6;
716 else if ((!vdata.second) && vdata.first>2 && C0)
717 tmp += 4;
718 else
719 tmp += vdata.first; // valence;
720
721 // corn +=1;
722 }
723 }
724 // gsDebug<<"Number of unique corners: "<<corn<<"\n";
725
726 // gsDebug<<"Number of vertex DoFs: "<<tmp<<"\n";
727
728 m_size += tmp;
729 }
730
731 template<short_t d,class T>
733 {
734 GISMO_UNUSED(valence);
735
736 // // 2. make container for the interfaces
737 // std::vector<boundaryInterface> ifaces;
738 // boundaryInterface iface;
739 // std::vector<patchSide> boundaries;
740 // index_t extraRow;
741 // std::vector<patchCorner> temp_corners, corners;
742 // std::vector<patchSide> psides;
743 // std::vector<index_t> colIndices,rowIndices, patches;
744
745 // sparseEntry_t entries;
746
747 // m_topology.getCornerList(pcorner,corners);
748
749 // /*
750 // Warning:
751 // This case handles all patchCorners related to this vertex at once!
752 // */
753
754 // // 1. get all adjacent vertices
755
756 // // find corner with the lowest patch index
757 // patchCorner lowest = corners[0];
758 // for (size_t k=0; k!=corners.size(); k++)
759 // lowest = (corners[k].patch < lowest.patch ) ? corners[k] : lowest;
760
761 // lowest.getContainingSides(d,psides);
762 // // get (0,0) index from the corner with lowest patch number and store the row index.
763 // extraRow = this->_indexFromVert(0,lowest,psides[0],0);
764 // extraRow = m_mapModified.index(extraRow,lowest.patch);
765
766 // // 2. loop over the adjacent vertices
767 // colIndices.clear();
768 // rowIndices.clear();
769 // patches.clear();
770 // for (std::vector<patchCorner>::iterator it = corners.begin(); it!=corners.end(); ++it)
771 // {
772 // // *it is a patchCorner
773 // // 3. determine if one of the contained sides is a boundary
774 // it->getContainingSides(d,psides);
775
776 // // store the 0,0 indices
777 // colIndices.push_back( this->_indexFromVert(0,*it,psides[0],0) );
778 // rowIndices.push_back( this->_indexFromVert(1,*it,psides[0],1) );
779 // patches.push_back(it->patch);
780
781 // for (index_t k = 0; k!=2; k++) // index of point over the interface
782 // {
783 // if ( m_topology.getInterface(psides[k],iface) ) // if it is an interface, store it
784 // {
785 // ifaces.push_back(iface);
786 // }
787 // else // if not, then store the side
788 // {
789 // //
790 // index_t colIdx = m_mapOriginal.index(this->_indexFromVert(1,*it,psides[k],0),it->patch);
791 // index_t rowIdx = m_mapModified.index(this->_indexFromVert(1,*it,psides[k],1),it->patch);
792 // entries.push_back(std::make_tuple(rowIdx,colIdx,0.5));
793 // entries.push_back(std::make_tuple(extraRow,colIdx,0.5));
794 // // m_matrix(rowIdx,colIdx) = 0.5;
795 // // m_matrix(extraRow,colIdx) = 0.5;
796 // // m_basisCheck[rowIdx] = true;
797 // }
798 // }
799 // }
800
801 // // GISMO_ASSERT(boundaries.size()==2,"There must be two boundaries that are not an interface!");
802 // // ifaces.push_back(boundaryInterface(boundaries[0],boundaries[1],d));
803
804 // // the extra (0,0) node gets 0.25 for all (0,0) entries
805 // for (size_t k = 0; k!=colIndices.size(); k++)
806 // {
807 // index_t colIdx = m_mapOriginal.index(colIndices[k],patches[k]);
808 // entries.push_back(std::make_tuple(extraRow,colIdx,0.25));
809 // // m_matrix(extraRow,colIdx) = 0.25;
810 // }
811
812 // // Fill the matrix entries related to the 1,1 coefs (stored in indices) with 1 for itself and with 0.25 for the others
813 // for (size_t k = 0; k!=rowIndices.size(); k++)
814 // {
815 // index_t rowIdx = m_mapModified.index(rowIndices[k],patches[k]);
816 // index_t colIdx = m_mapOriginal.index(rowIndices[k],patches[k]);
817 // // Fill the matrix entries related to itself (1,1) with a 1.0
818 // entries.push_back(std::make_tuple(rowIdx,colIdx,1.0));
819 // // m_matrix(rowIdx,colIdx) = 1.0;
820
821 // for (size_t l = 0; l!=colIndices.size(); l++)
822 // {
823 // // Fill the matrix entries related to the 0,0 coefs (stored in indices) 0.25 for all corners
824 // colIdx = m_mapOriginal.index(colIndices[l],patches[l]);
825 // entries.push_back(std::make_tuple(extraRow,colIdx,0.25));
826 // // m_matrix(rowIdx,colIdx) = 0.25;
827 // }
828
829 // // m_basisCheck[rowIdx] = true;
830 // }
831
832 // rowIndices.resize(2);
833 // colIndices.resize(2);
834 // patches.resize(2);
835
836 // // extra point handling
837 // colIndices.resize(2);
838 // for (std::vector<patchSide>::iterator it = boundaries.begin(); it!=boundaries.end(); ++it)
839 // {
840 // // find which corner of the interface
841 // it->getContainedCorners(d,temp_corners);
842 // for (std::vector<patchCorner>::iterator corn = temp_corners.begin(); corn!=temp_corners.end(); ++corn)
843 // {
844 // if ( std::find(corners.begin(), corners.end(), *corn) == corners.end() ) // the contained corner is not in corners
845 // continue;
846
847 // index_t colIdx = this->_indexFromVert(1,*corn,*it,0);
848 // colIdx = m_mapOriginal.index(colIdx,corn->patch);
849 // entries.push_back(std::make_tuple(extraRow,colIdx,0.5));
850 // // m_matrix(extraRow,colIdx) = 0.5;
851
852 // }
853 // }
854
855 // // m_basisCheck[extraRow] = true;
856 // // }
857 // // Interface handling
858 // for (std::vector<boundaryInterface>::iterator it = ifaces.begin(); it!=ifaces.end(); ++it)
859 // {
860 // // if (!m_topology.isInterface(it->first()))
861 // // continue;
862
863 // // find which corner of the interface
864 // it->first().getContainedCorners(d,temp_corners);
865
866 // std::vector<patchSide> isides(2);
867 // std::vector<patchCorner> icorners(2);
868
869 // for (std::vector<patchCorner>::iterator corn = temp_corners.begin(); corn!=temp_corners.end(); ++corn)
870 // {
871 // if ( std::find(corners.begin(), corners.end(), *corn) == corners.end() ) // the contained corner is not in corners
872 // {
873 // continue;
874 // }
875
876 // // Now we need to fill the matrix for the rows corresponding to the (1,1) coefficients of the corners
877 // icorners[0] = *corn;
878 // icorners[1] = it->mapCorner(*corn);
879 // isides[0] = it->first();
880 // isides[1] = it->second();
881
882 // // get rowIndices
883 // for (size_t k=0; k!=icorners.size(); k++)
884 // {
885 // rowIndices[k] = this->_indexFromVert(1,icorners[k],isides[k],1);
886 // colIndices[k] = this->_indexFromVert(1,icorners[k],isides[k],0);
887 // patches[k] = icorners[k].patch;
888 // }
889
890 // for (size_t k = 0; k!=rowIndices.size(); k++)
891 // {
892 // index_t rowIdx = m_mapModified.index(rowIndices[k],patches[k]);
893 // // Fill the matrix entries related to the 0,0 coefs (stored in indices) 0.25 for all corners
894 // for (size_t l = 0; l!=colIndices.size(); l++)
895 // {
896 // index_t colIdx = m_mapOriginal.index(colIndices[l],patches[l]);
897 // entries.push_back(std::make_tuple(rowIdx,colIdx,0.5));
898 // // m_matrix(rowIdx,colIdx) = 0.5;
899 // }
900 // // m_basisCheck[rowIdx] = true;
901 // }
902 // }
903 // }
904
905 // #pragma omp critical (handle_boundary_vertex_ff)
906 // {
907 // _pushAndCheck(entries);
908
909 // // Furthermore, all adjacent vertices are checked
910 // for (std::vector<patchCorner>::iterator it = corners.begin(); it!=corners.end(); ++it)
911 // m_vertCheck[ this->_vertIndex(it->patch, it->corner()) ] = true;
912 // }
913
914 // 2. make container for the interfaces
915 std::vector<boundaryInterface> ifaces;
916 boundaryInterface iface;
917 std::vector<patchSide> boundaries;
918 index_t extraRow;
919 std::vector<patchCorner> temp_corners, corners;
920 std::vector<patchSide> psides;
921 std::vector<index_t> colIndices,rowIndices, patches;
922
923 sparseEntry_t entries;
924
925 m_topology.getCornerList(pcorner,corners);
926
927 // if (!(std::count(m_C0s.begin(), m_C0s.end(), pcorner)))
928 // {
929 if ((std::count(m_C0s.begin(), m_C0s.end(), pcorner)))
930 gsWarn<<"C0 handling for boundary corners with valence 3 has not yet been implemented\n";
931
932
933 /*
934 Warning:
935 This case handles all patchCorners related to this vertex at once!
936 */
937
938 // 1. get all adjacent vertices
939
940 // find corner with the lowest patch index
941 patchCorner lowest = corners[0];
942 for (size_t k=0; k!=corners.size(); k++)
943 lowest = (corners[k].patch < lowest.patch ) ? corners[k] : lowest;
944
945 lowest.getContainingSides(d,psides);
946 // get (0,0) index from the corner with lowest patch number and store the row index.
947 extraRow = this->_indexFromVert(0,lowest,psides[0],0);
948 extraRow = m_mapModified.index(extraRow,lowest.patch);
949
950 // 2. loop over the adjacent vertices
951 colIndices.clear();
952 rowIndices.clear();
953 patches.clear();
954 for (std::vector<patchCorner>::iterator it = corners.begin(); it!=corners.end(); ++it)
955 {
956 // *it is a patchCorner
957 // 3. determine if one of the contained sides is a boundary
958 it->getContainingSides(d,psides);
959
960 // store the 0,0 indices
961 colIndices.push_back( this->_indexFromVert(0,*it,psides[0],0) );
962 rowIndices.push_back( this->_indexFromVert(1,*it,psides[0],1) );
963 patches.push_back(it->patch);
964
965 for (index_t k = 0; k!=2; k++) // index of point over the interface
966 {
967 if ( m_topology.getInterface(psides[k],iface) ) // if it is an interface, store it
968 {
969 ifaces.push_back(iface);
970 }
971 else // if not, then store the side
972 {
973 //
974 index_t colIdx = m_mapOriginal.index(this->_indexFromVert(1,*it,psides[k],0),it->patch);
975 index_t rowIdx = m_mapModified.index(this->_indexFromVert(1,*it,psides[k],1),it->patch);
976 // m_matrix(rowIdx,colIdx) = 0.5;
977 // m_matrix(extraRow,colIdx) = 0.5;
978 // m_basisCheck[rowIdx] = true;
979 entries.push_back(std::make_tuple(rowIdx,colIdx,0.5));
980 entries.push_back(std::make_tuple(extraRow,colIdx,0.5));
981 // boundaries.push_back(psides[k]);
982 }
983 }
984 }
985
986 // GISMO_ASSERT(boundaries.size()==2,"There must be two boundaries that are not an interface!");
987 // ifaces.push_back(boundaryInterface(boundaries[0],boundaries[1],d));
988
989
990
991
992 // the extra (0,0) node gets 0.25 for all (0,0) entries
993 for (size_t k = 0; k!=colIndices.size(); k++)
994 {
995 index_t colIdx = m_mapOriginal.index(colIndices[k],patches[k]);
996 // m_matrix(extraRow,colIdx) = 0.25;
997 entries.push_back(std::make_tuple(extraRow,colIdx,0.25));
998
999 }
1000 // Fill the matrix entries related to the 1,1 coefs (stored in indices) with 1 for itself and with 0.25 for the others
1001 for (size_t k = 0; k!=rowIndices.size(); k++)
1002 {
1003 index_t rowIdx = m_mapModified.index(rowIndices[k],patches[k]);
1004 index_t colIdx = m_mapOriginal.index(rowIndices[k],patches[k]);
1005 // Fill the matrix entries related to itself (1,1) with a 1.0
1006 entries.push_back(std::make_tuple(rowIdx,colIdx,1.0));
1007 // m_matrix(rowIdx,colIdx) = 1.0;
1008
1009 for (size_t l = 0; l!=colIndices.size(); l++)
1010 {
1011 // Fill the matrix entries related to the 0,0 coefs (stored in indices) 0.25 for all corners
1012 colIdx = m_mapOriginal.index(colIndices[l],patches[l]);
1013 // m_matrix(rowIdx,colIdx) = 0.25;
1014 entries.push_back(std::make_tuple(rowIdx,colIdx,0.25));
1015 }
1016
1017 // m_basisCheck[rowIdx] = true;
1018 }
1019
1020 rowIndices.resize(2);
1021 colIndices.resize(2);
1022 patches.resize(2);
1023
1024 // extra point handling
1025 colIndices.resize(2);
1026 for (std::vector<patchSide>::iterator it = boundaries.begin(); it!=boundaries.end(); ++it)
1027 {
1028 // find which corner of the interface
1029 it->getContainedCorners(d,temp_corners);
1030 for (std::vector<patchCorner>::iterator corn = temp_corners.begin(); corn!=temp_corners.end(); ++corn)
1031 {
1032 if ( std::find(corners.begin(), corners.end(), *corn) == corners.end() ) // the contained corner is not in corners
1033 continue;
1034
1035 index_t colIdx = this->_indexFromVert(1,*corn,*it,0);
1036 colIdx = m_mapOriginal.index(colIdx,corn->patch);
1037 entries.push_back(std::make_tuple(extraRow,colIdx,0.5));
1038 // m_matrix(extraRow,colIdx) = 0.5;
1039
1040 }
1041 }
1042
1043 // m_basisCheck[extraRow] = true;
1044 // }
1045 // Interface handling
1046 for (std::vector<boundaryInterface>::iterator it = ifaces.begin(); it!=ifaces.end(); ++it)
1047 {
1048 // if (!m_topology.isInterface(it->first()))
1049 // continue;
1050
1051 // find which corner of the interface
1052 it->first().getContainedCorners(d,temp_corners);
1053
1054 std::vector<patchSide> isides(2);
1055 std::vector<patchCorner> icorners(2);
1056
1057 for (std::vector<patchCorner>::iterator corn = temp_corners.begin(); corn!=temp_corners.end(); ++corn)
1058 {
1059 if ( std::find(corners.begin(), corners.end(), *corn) == corners.end() ) // the contained corner is not in corners
1060 {
1061 continue;
1062 }
1063
1064 // Now we need to fill the matrix for the rows corresponding to the (1,1) coefficients of the corners
1065 icorners[0] = *corn;
1066 icorners[1] = it->mapCorner(*corn);
1067 isides[0] = it->first();
1068 isides[1] = it->second();
1069
1070 // get rowIndices
1071 for (size_t k=0; k!=icorners.size(); k++)
1072 {
1073 rowIndices[k] = this->_indexFromVert(1,icorners[k],isides[k],1);
1074 colIndices[k] = this->_indexFromVert(1,icorners[k],isides[k],0);
1075 patches[k] = icorners[k].patch;
1076 }
1077
1078 for (size_t k = 0; k!=rowIndices.size(); k++)
1079 {
1080 index_t rowIdx = m_mapModified.index(rowIndices[k],patches[k]);
1081 // Fill the matrix entries related to the 0,0 coefs (stored in indices) 0.25 for all corners
1082 for (size_t l = 0; l!=colIndices.size(); l++)
1083 {
1084 index_t colIdx = m_mapOriginal.index(colIndices[l],patches[l]);
1085 entries.push_back(std::make_tuple(rowIdx,colIdx,0.5));
1086 // m_matrix(rowIdx,colIdx) = 0.5;
1087 }
1088 // m_basisCheck[rowIdx] = true;
1089 }
1090 }
1091
1092 }
1093
1094 #pragma omp critical (handle_boundary_vertex_ff)
1095 {
1096 _pushAndCheck(entries);
1097
1098 // Furthermore, all adjacent vertices are checked
1099 for (std::vector<patchCorner>::iterator it = corners.begin(); it!=corners.end(); ++it)
1100 m_vertCheck[ this->_vertIndex(it->patch, it->corner()) ] = true;
1101 }
1102 }
1103
1104 template<short_t d,class T>
1106 {
1107 gsWarn<<"C0 handling for boundary corners with valence 3 has not yet been implemented. Using the default approach\n";
1108 this->_handleIrregularBoundaryVertexSmooth(pcorner,valence);
1109 }
1110
1111 template<short_t d,class T>
1112 void gsDPatch<d,T>::_computeVertexMapper(patchCorner pcorner)
1113 {
1114 index_t cidx = _vertIndex(pcorner.patch,pcorner.corner());
1115 if (m_vertCheck.at(cidx))
1116 return;
1117
1118 bool C0 = m_C0s[cidx];
1119 bool interior;
1120 index_t valence;
1121
1122 std::tie(valence,interior) = _vertexData(pcorner); // corner c
1123 if (!interior && valence==1) //valence = 1
1124 _computeMapperRegularCorner_v1(pcorner,valence);
1125 else if (!interior && valence==2 && C0)
1126 _computeMapperRegularBoundaryVertexNonSmooth_v2(pcorner,valence);
1127 else if (!interior && valence==2 && !C0)
1128 _computeMapperRegularBoundaryVertexSmooth_v2(pcorner,valence);
1129 else if (!interior && valence==3 && C0)
1130 _computeMapperIrregularBoundaryVertexNonSmooth_v3(pcorner,valence);
1131 else if (!interior && valence==3 && !C0)
1132 _computeMapperIrregularBoundaryVertexSmooth_v3(pcorner,valence);
1133 else if (!interior && valence >3 && C0)
1134 _computeMapperIrregularBoundaryVertexNonSmooth_v(pcorner,valence);
1135 else if (!interior && valence >3 && !C0)
1136 _computeMapperIrregularBoundaryVertexSmooth_v(pcorner,valence);
1137 else if (interior)
1138 _computeMapperInteriorVertex_v(pcorner,valence);
1139 else
1140 GISMO_ERROR("Something went terribly wrong, interior="<<interior<<"; valence="<<valence);
1141
1142 // label vertex as processed
1143 m_vertCheck[ cidx ] = true;
1144 }
1145
1146 // Different for DPatch and AlmostC1
1147 template<short_t d,class T>
1148 void gsDPatch<d,T>::_computeMapperIrregularBoundaryVertexSmooth_v3(patchCorner pcorner, index_t valence)
1149 {
1150 GISMO_UNUSED(valence);
1151
1152 std::vector<patchSide> psides(2);
1153 std::vector<patchCorner> pcorners;
1154 /*
1155 o o o @ X |i| X @ o o o x: eliminated DoFs by vertex rule
1156 o o o @ X |n| X @ o o o X: eliminated DoFs by interface/boundary rule
1157 o o o @ X |t| X @ o o o o: preserved DoFs (interior)
1158 @ @ @ * x |e| x * @ @ @ @: modified DoFs by interface rule
1159 X X X x % |r| % x X X X *: modified DoFs by vertex rule (unique DoFs)
1160 ----------------------- %: modified DoFs by vertex rule (matched DoFs)
1161 -boundary-| |-interface
1162 -----------------------
1163 b| | % x X X X
1164 o| | x * @ @ @
1165 u| | X @ o o o
1166 n| | X @ o o o
1167 d| | X @ o o o
1168
1169 */
1170 // if (!(std::count(m_C0s.begin(), m_C0s.end(), pcorner)))
1171 // {
1172
1173 // We handle all corners associated to pcorner
1174 m_topology.getCornerList(pcorner,pcorners);
1175
1176 for (size_t c=0; c!=pcorners.size(); c++)
1177 {
1178 // Eliminate their 0,1 and 1,0 vertices
1179 pcorners[c].getContainingSides(d,psides);
1180 m_mapModified.eliminateDof(this->_indexFromVert(1,pcorners[c],psides[0]),pcorners[c].patch);
1181 m_mapModified.eliminateDof(this->_indexFromVert(1,pcorners[c],psides[1]),pcorners[c].patch);
1182
1183 // And match the 0,0 vertex (i.e. the corner) to the corner that is first in the list pcorners.
1184 patchSide pseudo; // this side does not contribute since we use index = 0 in this->_indexFromVert
1185 if (c!=0)
1186 m_mapModified.matchDof(pcorners[0].patch,this->_indexFromVert(0,pcorners[0],pseudo,0),pcorners[c].patch,this->_indexFromVert(0,pcorners[c],pseudo,0));
1187 // mark the vertex as passed
1188 m_vertCheck[ this->_vertIndex(pcorners[c].patch, pcorners[c].corner()) ] = true;
1189 }
1190 // }
1191 // else
1192 // {
1193 // pcorner.getContainingSides(d,psides);
1194 // for (size_t p=0; p!=psides.size(); p++)
1195 // {
1196 // if (m_topology.isInterface(psides[p]))
1197 // {
1198 // m_mapModified.eliminateDof(this->_indexFromVert(1,pcorner,psides[p],0),pcorner.patch);
1199 // }
1200 // }
1201 // }
1202 }
1203
1204 // Different for DPatch and AlmostC1
1205 template<short_t d,class T>
1206 void gsDPatch<d,T>::_computeMapperIrregularBoundaryVertexNonSmooth_v3(patchCorner pcorner, index_t valence)
1207 {
1208 gsWarn<<"C0 handling for boundary corners with valence 3 has not yet been implemented. Using the default approach\n";
1209 this->_computeMapperIrregularBoundaryVertexSmooth_v3(pcorner,valence);
1210 }
1211
1212 template<short_t d,class T>
1213 void gsDPatch<d,T>::_computeMapperIrregularBoundaryVertexSmooth_v(patchCorner pcorner, index_t valence)
1214 {
1215 GISMO_ERROR("Boundary vertex on patch"<<pcorner.patch<<" with index "<<pcorner.corner()<<" with valence = "<<valence<<" has no implementation");
1216 }
1217
1218 template<short_t d,class T>
1219 void gsDPatch<d,T>::_computeMapperIrregularBoundaryVertexNonSmooth_v(patchCorner pcorner, index_t valence)
1220 {
1221 GISMO_ERROR("Boundary vertex on patch"<<pcorner.patch<<" with index "<<pcorner.corner()<<" with valence = "<<valence<<" has no implementation");
1222 }
1223
1224} // namespace gismo
Struct which represents a certain side of a box.
Definition gsBoundary.h:85
Creates a mapped object or data pointer to a matrix without copying data.
Definition gsAsMatrix.h:32
A basis represents a family of scalar basis functions defined over a common parameter domain.
Definition gsBasis.h:79
gsMatrix< index_t > boundary(boxSide const &s) const
Returns the indices of the basis functions that are nonzero at the domain boundary as single-column-m...
Definition gsBasis.h:520
virtual gsMatrix< index_t > boundaryOffset(boxSide const &s, index_t offset) const
Definition gsBasis.hpp:339
Constructs the D-Patch, from which the transformation matrix can be called.
Definition gsDPatchBase.h:37
Constructs the D-Patch, from which the transformation matrix can be called.
Definition gsDPatch.h:34
gsMatrix< T > _makePi(index_t valence)
Makes the Pi matrix.
Definition gsDPatch.hpp:581
void _makeTHB() override
Prints which DoFs have been handled and which have been eliminated.
Definition gsDPatch.hpp:292
gsDPatch()
Empty constructor.
Definition gsDPatch.h:48
void _countDoFs() override
Initializes the matrix, the basis and the mappers.
Definition gsDPatch.hpp:642
void _computeEVs() override
Corrects the EVs.
Definition gsDPatch.hpp:332
void _handleIrregularBoundaryVertexSmooth(patchCorner pcorner, index_t valence) override
Handles a vertex in the global matrix.
Definition gsDPatch.hpp:732
void defaultOptions() override
Sets the default options.
Definition gsDPatch.hpp:51
void _initTHB() override
Initializes the matrix, the basis and the mappers.
Definition gsDPatch.hpp:144
void _initBasis() override
Initializes the basis.
Definition gsDPatch.hpp:271
Maintains a mapping from patch-local dofs to global dof indices and allows the elimination of individ...
Definition gsDofMapper.h:69
uPtr clone()
Clone methode. Produceds a deep copy inside a uPtr.
const gsBasis< T > & basis(const index_t k) const
Helper which casts and returns the k-th piece of this function set as a gsBasis.
Definition gsFunctionSet.hpp:33
Class representing a (scalar) hierarchical tensor basis of functions .
Definition gsHTensorBasis.h:75
void addLevel(const gsTensorBSplineBasis< d, T > &next_basis)
Adds a level, only if manual levels are activated.
Definition gsHTensorBasis.hpp:35
Class for representing a knot vector.
Definition gsKnotVector.h:80
uiterator ubegin() const
Returns unique iterator pointing to the beginning of the unique knots.
Definition gsKnotVector.hpp:235
int degree() const
Returns the degree of the knot vector.
Definition gsKnotVector.hpp:700
uiterator uend() const
Returns unique iterator pointing past the end of the unique knots.
Definition gsKnotVector.hpp:241
size_t uSize() const
Number of unique knots (i.e., without repetitions).
Definition gsKnotVector.h:245
mult_t multiplicity(T u) const
Definition gsKnotVector.hpp:421
internal::gsUKnotIterator< T > uiterator
Definition gsKnotVector.h:102
size_t numElements() const
Number of knot intervals inside domain.
Definition gsKnotVector.h:268
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
Holds a set of patch-wise bases and their topology information.
Definition gsMultiBasis.h:37
const gsBasis< T > & basis(const size_t i) const
Return the i-th basis block.
Definition gsMultiBasis.h:267
Container class for a set of geometry patches and their topology, that is, the interface connections ...
Definition gsMultiPatch.h:100
short_t geoDim() const
Dimension of the geometry (must match for all patches).
Definition gsMultiPatch.hpp:150
gsGeometry< T > & patch(size_t i) const
Return the i-th patch.
Definition gsMultiPatch.h:292
Iterator over the non-zero entries of a sparse matrix.
Definition gsSparseMatrix.h:74
Sparse matrix class, based on gsEigen::SparseMatrix.
Definition gsSparseMatrix.h:139
Truncated hierarchical B-spline basis.
Definition gsTHBSplineBasis.h:36
A tensor product B-spline basis.
Definition gsTensorBSplineBasis.h:37
virtual void uniformRefine(int numKnots=1, int mul=1, short_t dir=-1)
Refine the basis uniformly by inserting numKnots new knots with multiplicity mul on each knot span.
Definition gsTensorBasis.h:315
short_t degree(short_t i) const
Returns the degree of the basis wrt variable i.
Definition gsTensorBasis.h:465
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
Simple class create a block preconditioner structure.
#define short_t
Definition gsConfig.h:35
#define index_t
Definition gsConfig.h:32
#define GISMO_ERROR(message)
Definition gsDebug.h:118
#define gsWarn
Definition gsDebug.h:50
#define GISMO_UNUSED(x)
Definition gsDebug.h:112
#define GISMO_ENSURE(cond, message)
Definition gsDebug.h:102
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Provides definition of HTensorBasis abstract interface.
Simple adapter classes to use matrices or linear solvers as gsLinearOperators.
Provides declaration of THBSplineBasis class.
Provides declaration of THBSplineBasis class.
Provides declaration of functions writing Paraview files.
The G+Smo namespace, containing all definitions for the library.
Struct which represents an interface between two patches.
Definition gsBoundary.h:650
Struct which represents a certain corner of a hyper-cube.
Definition gsBoundary.h:292
index_t m_index
Index of the corner.
Definition gsBoundary.h:298
void parameters_into(index_t dim, gsVector< bool > &param) const
returns a vector of parameters describing the position of the corner
Definition gsBoundary.h:322
Struct which represents a certain corner of a patch.
Definition gsBoundary.h:393
void getContainingSides(short_t dim, std::vector< patchSide > &sides) const
returns a vector of patchSides that contain this corner
Definition gsBoundary.h:416
Struct which represents a certain side of a patch.
Definition gsBoundary.h:232
index_t patch
The index of the patch.
Definition gsBoundary.h:234
void getContainedCorners(short_t dim, std::vector< patchCorner > &corners) const
returns the vector of the corners contained in the side
Definition gsBoundary.cpp:35