G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsIetiMapper.hpp
Go to the documentation of this file.
1 
14 #pragma once
15 
17 
18 /* Concerning the status flag m_status:
19  * (m_status&1)!=0 means that the object has been initialized by calling init or the value constructor
20  * (m_status&2)!=0 means that the jump matrices have been computed
21  * (m_status&4)!=0 means that corners have been set up as primal constraints
22  * (m_status&flag)!=0 for flag = 8, 16,... means that edges, faces, ... have been set up as primal constraints
23  */
24 
25 namespace gismo
26 {
27 
28 template <class T>
30  const gsMultiBasis<T>& multiBasis,
31  gsDofMapper dofMapperGlobal,
32  const Matrix& fixedPart
33  )
34 {
35  GISMO_ASSERT( dofMapperGlobal.componentsSize() == 1, "gsIetiMapper::init: "
36  "Got only 1 multi basis, so a gsDofMapper with only 1 component is expected." );
37  GISMO_ASSERT( dofMapperGlobal.numPatches() == multiBasis.nBases(), "gsIetiMapper::init: "
38  "Number of patches does not agree." );
39 
40  const index_t nPatches = dofMapperGlobal.numPatches();
41  m_multiBasis = &multiBasis;
42  m_dofMapperGlobal = give(dofMapperGlobal);
43  m_dofMapperLocal.clear();
44  m_dofMapperLocal.resize(nPatches);
45  m_fixedPart.clear();
46  m_fixedPart.resize(nPatches);
47  m_jumpMatrices.clear();
48  m_nPrimalDofs = 0;
49  m_primalConstraints.clear();
50  m_primalConstraints.resize(nPatches);
51  m_primalDofIndices.clear();
52  m_primalDofIndices.resize(nPatches);
53  m_status = 1;
54 
55  for (index_t k=0; k<nPatches; ++k)
56  {
57  const index_t nDofs = m_dofMapperGlobal.patchSize(k);
58  GISMO_ASSERT( nDofs==m_multiBasis->piece(k).size(), "gsIetiMapper::init: "
59  "The mapper for patch "<<k<<" has not as many dofs as the corresponding basis." );
60 
61  m_dofMapperLocal[k].setIdentity(1,nDofs);
62 
63  // Eliminate boundary dofs (we do not consider the full floating case).
64  for (index_t i=0; i<nDofs; ++i)
65  {
66  const index_t idx = m_dofMapperGlobal.index(i,k);
67  if (m_dofMapperGlobal.is_boundary_index(idx))
68  m_dofMapperLocal[k].eliminateDof(i,0);
69  }
70  m_dofMapperLocal[k].finalize();
71 
72  const index_t szFixedPart = m_dofMapperLocal[k].boundarySize();
73  m_fixedPart[k].setZero(szFixedPart,1);
74  for (index_t i=0; i<nDofs; ++i)
75  {
76  const index_t idx = m_dofMapperGlobal.index(i,k);
77  if (m_dofMapperGlobal.is_boundary_index(idx))
78  {
79  const index_t globalBoundaryIdx = m_dofMapperGlobal.bindex(i,k);
80  const index_t localBoundaryIdx = m_dofMapperLocal[k].bindex(i,0);
81  m_fixedPart[k](localBoundaryIdx,0) = fixedPart(globalBoundaryIdx,0);
82  }
83  }
84  }
85 }
86 
87 
88 template <class T>
90 gsIetiMapper<T>::constructGlobalSolutionFromLocalSolutions( const std::vector<Matrix>& localContribs )
91 {
92  GISMO_ASSERT( m_status&1, "gsIetiMapper: The class has not been initialized." );
93 
94  const index_t nPatches = m_dofMapperGlobal.numPatches();
95  GISMO_ASSERT( nPatches == static_cast<index_t>(localContribs.size()),
96  "gsIetiMapper::constructGlobalSolutionFromLocalSolutions; The number of local contributions does "
97  "not argee with the number of patches." );
98 
99  Matrix result;
100  result.setZero( m_dofMapperGlobal.freeSize(), localContribs[0].cols() );
101 
102  for (index_t k=0; k<nPatches; ++k)
103  {
104  const index_t sz=m_dofMapperLocal[k].size();
105  for (index_t i=0; i<sz; ++i)
106  {
107  if (m_dofMapperLocal[k].is_free(i,0) && m_dofMapperGlobal.is_free(i,k))
108  result.row(m_dofMapperGlobal.index(i,k)) = localContribs[k].row(m_dofMapperLocal[k].index(i,0));
109  }
110  }
111  return result;
112 }
113 
114 namespace {
115 struct dof_helper {
116  index_t globalIndex;
117  index_t patch;
118  index_t localIndex;
119  bool operator<(const dof_helper& other) const
120  { return globalIndex < other.globalIndex; }
121 };
122 }
123 
124 template <class T>
126 {
127  GISMO_ASSERT( m_status&1, "gsIetiMapper: The class has not been initialized." );
128  GISMO_ASSERT( !(m_status&4), "gsIetiMapper::cornersAsPrimals: This function has already been called." );
129  m_status |= 4;
130 
131  const index_t nPatches = m_dofMapperLocal.size();
132 
133  // Construct all corners
134  std::vector<dof_helper> corners;
135  const index_t dim = m_multiBasis->dim();
136  corners.reserve((1<<dim)*nPatches);
137  // Add corners on all patches
138  for (index_t k=0; k<nPatches; ++k)
139  {
140  for (boxCorner it = boxCorner::getFirst(dim); it!=boxCorner::getEnd(dim); ++it)
141  {
142  const index_t idx = (*m_multiBasis)[k].functionAtCorner(it);
143  dof_helper dh;
144  dh.globalIndex = m_dofMapperGlobal.index( idx, k );
145  dh.patch = k;
146  dh.localIndex = m_dofMapperLocal[k].index( idx, 0 );
147  if (m_dofMapperGlobal.is_free_index(dh.globalIndex))
148  corners.push_back(dh);
149  }
150  }
151 
152  // Sort corners to collapse corners with same global index
153  std::sort(corners.begin(), corners.end());
154 
155  // Create data
156  index_t lastIndex = -1;
157  const index_t sz = corners.size();
158  for (index_t i=0; i<sz; ++i)
159  {
160  if (lastIndex!=corners[i].globalIndex)
161  {
162  lastIndex = corners[i].globalIndex;
163  if (i+1<sz&&corners[i+1].globalIndex==corners[i].globalIndex)
164  ++m_nPrimalDofs;
165  else
166  continue; // Ignore corners that are not shared
167  }
168  const index_t cornerIndex = m_nPrimalDofs - 1;
169  const index_t patch = corners[i].patch;
170  const index_t localIndex = corners[i].localIndex;
171 
172  SparseVector constr(m_dofMapperLocal[patch].freeSize());
173  constr[localIndex] = 1;
174 
175  m_primalConstraints[patch].push_back(give(constr));
176  m_primalDofIndices[patch].push_back(cornerIndex);
177  }
178 
179 }
180 
181 template <class T>
183  const gsGeometry<T>& geo,
184  const gsBasis<T>& basis,
185  const gsDofMapper& dm,
186  boxComponent bc
187 )
188 {
189  gsMatrix<index_t> indices;
190 
192  *(geo.component(bc)),
193  *(basis.componentBasis_withIndices(bc, indices, false))
194  ).assembleMoments(
196  );
197 
198  SparseVector constraint( dm.freeSize() );
199  T sum = (T)0;
200  const index_t sz = moments.size();
201  GISMO_ASSERT( sz == indices.size(), "Internal error." );
202  for (index_t i=0; i<sz; ++i)
203  {
204  const index_t idx = dm.index( indices(i,0), 0 );
205  if (dm.is_free_index(idx))
206  {
207  constraint[idx] = moments(i,0);
208  sum += moments(i,0);
209  }
210  }
211  return constraint / sum;
212 
213 }
214 
215 
216 template <class T>
218 {
219  GISMO_ASSERT( m_status&1, "gsIetiMapper: The class has not been initialized." );
220  GISMO_ASSERT( d>0, "gsIetiMapper::interfaceAveragesAsPrimals cannot handle corners." );
221  GISMO_ASSERT( d<=m_multiBasis->dim(), "gsIetiMapper::interfaceAveragesAsPrimals: "
222  "Interfaces cannot have larger dimension than considered object." );
223  GISMO_ASSERT( (index_t)(geo.nPatches()) == m_multiBasis->nPieces(),
224  "gsIetiMapper::interfaceAveragesAsPrimals: The given geometry does not fit.");
225  GISMO_ASSERT( geo.parDim() == m_multiBasis->dim(),
226  "gsIetiMapper::interfaceAveragesAsPrimals: The given geometry does not fit.");
227 
228  const unsigned flag = 1<<(2+d);
229  GISMO_ASSERT( !(m_status&flag), "gsIetiMapper::interfaceAveragesAsPrimals: This function has "
230  " already been called for d="<<d );
231  m_status |= flag;
232 
233  std::vector< std::vector<patchComponent> > components = geo.allComponents();
234  const index_t nComponents = components.size();
235  for (index_t n=0; n<nComponents; ++n)
236  {
237  const index_t sz = components[n].size();
238  if ( components[n][0].dim() == d && ( sz > 1 || m_multiBasis->dim() == d ))
239  {
240  index_t used = 0;
241  for (index_t i=0; i<sz; ++i)
242  {
243  const index_t k = components[n][i].patch();
244  gsSparseVector<T> constr = assembleAverage(
245  geo[k],
246  (*m_multiBasis)[k],
247  m_dofMapperLocal[k],
248  components[n][i]
249  );
250  if ( constr.nonZeros() > 0 )
251  {
252  m_primalConstraints[k].push_back(give(constr));
253  m_primalDofIndices[k].push_back(m_nPrimalDofs);
254  ++used;
255  }
256  }
257  GISMO_ASSERT( used==0 || used == sz, "Internal error." );
258  if (used)
259  ++m_nPrimalDofs;
260  }
261  }
262 }
263 
264 
265 template <class T>
266 void gsIetiMapper<T>::customPrimalConstraints( std::vector< std::pair<index_t,SparseVector> > data )
267 {
268  GISMO_ASSERT( m_status&1, "gsIetiMapper: The class has not been initialized." );
269 
270  const index_t sz = data.size();
271  for (index_t i=0; i<sz; ++i)
272  {
273  const index_t patch = data[i].first;
274  m_primalConstraints[patch].push_back(give(data[i].second));
275  m_primalDofIndices[patch].push_back(m_nPrimalDofs);
276  }
277  ++m_nPrimalDofs;
278 }
279 
280 template <class T>
281 std::vector<index_t> gsIetiMapper<T>::skeletonDofs( const index_t patch ) const
282 {
283  GISMO_ASSERT( m_status&1, "gsIetiMapper: The class has not been initialized." );
284 
285  std::vector<index_t> result;
286  const index_t patchSize = m_dofMapperGlobal.patchSize(patch);
287  const index_t dim = m_multiBasis->dim();
288  result.reserve(2*dim*std::pow(patchSize,(1.0-dim)/dim));
289  for (index_t i=0; i<patchSize; ++i)
290  if ( m_dofMapperGlobal.is_coupled(i,patch) )
291  result.push_back(m_dofMapperLocal[patch].index(i,0));
292  return result;
293 }
294 
295 template <class T>
296 void gsIetiMapper<T>::computeJumpMatrices( bool fullyRedundant, bool excludeCorners )
297 {
298  GISMO_ASSERT( m_status&1, "gsIetiMapper: The class has not been initialized." );
299 
300  GISMO_ASSERT( !(m_status&2), "gsIetiMapper::computeJumpMatrices: This function has already been called." );
301  m_status |= 2;
302 
303  const index_t nPatches = m_dofMapperGlobal.numPatches();
304  const index_t coupledSize = m_dofMapperGlobal.coupledSize();
305 
306  // Find the groups of to be coupled indices
307  std::vector< std::vector< std::pair<index_t,index_t> > > coupling;
308  coupling.resize(coupledSize);
309 
310  for (index_t k=0; k<nPatches; ++k)
311  {
312  const index_t patchSize = m_dofMapperGlobal.patchSize(k);
313  for (index_t i=0; i<patchSize; ++i)
314  {
315  const index_t globalIndex = m_dofMapperGlobal.index(i,k);
316  if ( m_dofMapperGlobal.is_coupled_index(globalIndex) )
317  {
318  const index_t coupledIndex = m_dofMapperGlobal.cindex(i,k);
319  const index_t localIndex = m_dofMapperLocal[k].index(i,0);
320  coupling[coupledIndex].push_back(
321  std::pair<index_t,index_t>(k,localIndex)
322  );
323  }
324  }
325  }
326 
327  // Erease data for corners if so desired
328  if (excludeCorners)
329  {
330  const index_t dim = m_multiBasis->dim();
331  for (index_t k=0; k<nPatches; ++k)
332  {
333  for (boxCorner it = boxCorner::getFirst(dim); it!=boxCorner::getEnd(dim); ++it)
334  {
335  const index_t idx = (*m_multiBasis)[k].functionAtCorner(it);
336  const index_t globalIndex = m_dofMapperGlobal.index(idx,k);
337  if ( m_dofMapperGlobal.is_coupled_index(globalIndex) )
338  {
339  const index_t coupledIndex = m_dofMapperGlobal.cindex(idx,k);
340  coupling[coupledIndex].clear();
341  }
342  }
343  }
344  }
345 
346  // Compute the number of Lagrange multipliers
347  index_t numLagrangeMult = 0;
348  for (index_t i=0; i<coupledSize; ++i)
349  {
350  const index_t n = coupling[i].size();
351  GISMO_ASSERT( n>1 || excludeCorners, "gsIetiMapper::computeJumpMatrices:"
352  "Found a coupled dof that is not coupled to any other dof." );
353  if (fullyRedundant)
354  numLagrangeMult += (n * (n-1))/2;
355  else
356  numLagrangeMult += n-1;
357  }
358 
359  // Compute the jump matrices
360  std::vector< gsSparseEntries<T> > jumpMatrices_se(nPatches);
361  for (index_t i=0; i<nPatches; ++i)
362  {
363  const index_t dim = m_multiBasis->dim();
364  jumpMatrices_se[i].reserve(std::pow(m_dofMapperLocal[i].freeSize(),(1.0-dim)/dim));
365  }
366 
367  index_t multiplier = 0;
368  for (index_t i=0; i<coupledSize; ++i)
369  {
370  const index_t n = coupling[i].size();
371  const index_t maxIndex = fullyRedundant ? (n-1) : 1;
372  for (index_t j1=0; j1<maxIndex; ++j1)
373  {
374  const index_t patch1 = coupling[i][j1].first;
375  const index_t localMappedIndex1 = coupling[i][j1].second;
376  for (index_t j2=j1+1; j2<n; ++j2)
377  {
378  const index_t patch2 = coupling[i][j2].first;
379  const index_t localMappedIndex2 = coupling[i][j2].second;
380  jumpMatrices_se[patch1].add(multiplier,localMappedIndex1,(T)1);
381  jumpMatrices_se[patch2].add(multiplier,localMappedIndex2,(T)-1);
382  ++multiplier;
383  }
384  }
385  }
386  GISMO_ASSERT( multiplier == numLagrangeMult, "gsIetiMapper::computeJumpMatrices: Internal error: "
387  << multiplier << "!=" << numLagrangeMult );
388 
389  m_jumpMatrices.clear();
390  for (index_t i=0; i<nPatches; ++i)
391  {
392  m_jumpMatrices.push_back(JumpMatrix(numLagrangeMult, m_dofMapperLocal[i].freeSize()));
393  m_jumpMatrices[i].setFrom(jumpMatrices_se[i]);
394  }
395 
396 }
397 
398 template <class T>
400 {
401  GISMO_ASSERT(localSolution.cols() == m_fixedPart[k].cols(), "gsIetiMapper::incorporateFixedPart: Dimension missmatch.");
402  const std::size_t sz = m_dofMapperLocal[k].totalSize();
403  Matrix coeffs(sz, localSolution.cols());
404  for (std::size_t i = 0; i < sz; ++i)
405  {
406  if ( m_dofMapperLocal[k].is_free(i, 0) )
407  coeffs.row(i) = localSolution.row( m_dofMapperLocal[k].index(i, 0) );
408  else
409  coeffs.row(i) = m_fixedPart[k].row( m_dofMapperLocal[k].bindex(i, 0) );
410  }
411  return coeffs;
412 }
413 
414 
415 } // namespace gismo
void cornersAsPrimals()
Set up the corners as primal dofs.
Definition: gsIetiMapper.hpp:125
Abstract base class representing a geometry map.
Definition: gsGeometry.h:92
#define short_t
Definition: gsConfig.h:35
short_t parDim() const
Dimension of the parameter domain (must match for all patches).
Definition: gsMultiPatch.h:183
S give(S &x)
Definition: gsMemory.h:266
#define index_t
Definition: gsConfig.h:32
void init(const gsMultiBasis< T > &multiBasis, gsDofMapper dofMapperGlobal, const Matrix &fixedPart)
Init the ieti mapper after default construction.
Definition: gsIetiMapper.hpp:29
const gsMatrix< T > & assembleMoments(const gsFunction< T > &func, index_t patchIndex=-1, bool refresh=true)
Moments assembly routine.
Definition: gsGenericAssembler.hpp:93
virtual uPtr componentBasis_withIndices(boxComponent b, gsMatrix< index_t > &indices, bool noBoundary=true) const
Returns the basis that corresponds to the component.
Definition: gsBasis.hpp:360
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
void computeJumpMatrices(bool fullyRedundant, bool excludeCorners)
This function computes the jump matrices.
Definition: gsIetiMapper.hpp:296
Maintains a mapping from patch-local dofs to global dof indices and allows the elimination of individ...
Definition: gsDofMapper.h:68
void customPrimalConstraints(std::vector< std::pair< index_t, SparseVector > > data)
With this function, the caller can register more primal constraints.
Definition: gsIetiMapper.hpp:266
index_t index(index_t i, index_t k=0, index_t c=0) const
Returns the global dof index associated to local dof i of patch k.
Definition: gsDofMapper.h:325
bool is_free_index(index_t gl) const
Returns true if global dof gl is not eliminated.
Definition: gsDofMapper.h:376
Holds a set of patch-wise bases and their topology information.
Definition: gsMultiBasis.h:36
size_t nPatches() const
Number of patches.
Definition: gsMultiPatch.h:208
Container class for a set of geometry patches and their topology, that is, the interface connections ...
Definition: gsMultiPatch.h:33
size_t numPatches() const
Returns the number of patches present underneath the mapper.
Definition: gsDofMapper.h:469
Matrix incorporateFixedPart(index_t k, const gsMatrix< T > &localSolution) const
Incorporates fixedPart (eg. from eliminated Dirichlet dofs) to given patch-local solution.
Definition: gsIetiMapper.hpp:399
Assembles mass and stiffness matrices and right-hand sides on a given domain.
Definition: gsGenericAssembler.h:32
void interfaceAveragesAsPrimals(const gsMultiPatch< T > &geo, short_t d)
Set up interface averages as primal dofs.
Definition: gsIetiMapper.hpp:217
Matrix constructGlobalSolutionFromLocalSolutions(const std::vector< Matrix > &localContribs)
Construct the global solution from a vector of patch-local ones.
Definition: gsIetiMapper.hpp:90
size_t nBases() const
Number of patch-wise bases.
Definition: gsMultiBasis.h:264
std::vector< std::vector< patchComponent > > allComponents(bool combineCorners=false) const
Returns all components representing the topology.
Definition: gsBoxTopology.cpp:294
std::vector< index_t > skeletonDofs(index_t patch) const
Returns a list of dofs that are (on the coarse level) coupled.
Definition: gsIetiMapper.hpp:281
static boxCorner getFirst(short_t)
helper for iterating on corners of an n-dimensional box
Definition: gsBoundary.h:356
gsGeometry::uPtr component(boxComponent const &bc) const
Get parametrization of box component bc as a new gsGeometry uPtr.
Definition: gsGeometry.hpp:240
short_t targetDim() const
Dimension of the ambient physical space (overriding gsFunction::targetDim())
Definition: gsGeometry.h:286
index_t freeSize() const
Returns the number of free (not eliminated) dofs.
Definition: gsDofMapper.h:436
static gsSparseVector< T > assembleAverage(const gsGeometry< T > &geo, const gsBasis< T > &basis, const gsDofMapper &dm, boxComponent bc)
Assembles for interfaceAveragesAsPrimals.
Definition: gsIetiMapper.hpp:182
Sparse vector class, based on gsEigen::SparseVector.
Definition: gsSparseVector.h:34
static boxCorner getEnd(short_t dim)
helper for iterating on corners of an n-dimensional box
Definition: gsBoundary.h:372
Provides an assembler for common IGA matrices.
Struct which represents a certain corner of a hyper-cube.
Definition: gsBoundary.h:291
A basis represents a family of scalar basis functions defined over a common parameter domain...
Definition: gsBasis.h:78
Class defining a globally constant function.
Definition: gsConstantFunction.h:33
Struct which represents a certain component (interior, face, egde, corner).
Definition: gsBoundary.h:445