G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsDirichletValues.h
Go to the documentation of this file.
1 
14 #include <gsUtils/gsPointGrid.h>
15 #include <gsCore/gsDofMapper.h>
18 
19 namespace gismo {
20 
21 namespace expr
22 {
23 template<class T> class gsFeSpace;
24 };
25 
26 template<class T>
27 void gsDirichletValues(
28  const gsBoundaryConditions<T> & bc,
29  const index_t dir_values,
30  const expr::gsFeSpace<T> & u)
31 {
32  if ( bc.container("Dirichlet").empty() && bc.cornerValues().empty()) return;
33 
34  const gsDofMapper & mapper = u.mapper();
35  gsMatrix<T> & fixedDofs = const_cast<expr::gsFeSpace<T>&>(u).fixedPart();
36  fixedDofs.setZero(u.mapper().boundarySize(), 1 );
37 
38  switch ( dir_values )
39  {
40  case dirichlet::homogeneous :
41  case dirichlet::user :
42  // If we have a homogeneous problem then fill with zeros
43  break;
44  case dirichlet::interpolation:
45  gsDirichletValuesByTPInterpolation(u,bc);
46  break;
47  case dirichlet::l2Projection:
48  gsDirichletValuesByL2Projection(u,bc);
49  break;
50  default:
51  GISMO_ERROR("Something went wrong with Dirichlet values: "<< dir_values);
52  }
53 
54  // Corner values -- todo
55  for ( typename gsBoundaryConditions<T>::const_citerator it = bc.cornerBegin(); it != bc.cornerEnd(); ++it )
56  {
57  if(it->unknown != u.id())
58  continue;
59 
60  const int k = it->patch;
61  const gsBasis<T> & basis = u.source().basis(k);
62  const int i = basis.functionAtCorner(it->corner);
63  const index_t com = it->component;
64 
65  for (index_t r = 0; r!=u.dim(); ++r)
66  {
67  if (com!=-1 && r!=com) continue;
68  const int ii = mapper.bindex( i , k, r );
69  fixedDofs.at(ii) = it->value;
70  }
71  }
72 }
73 
74 template<class T>
75 void gsDirichletValuesByTPInterpolation(const expr::gsFeSpace<T> & u,
76  const gsBoundaryConditions<T> & bc)
77 {
78  const index_t parDim = u.source().domainDim();
79 
80  std::vector< gsVector<T> > rr;
81  gsMatrix<index_t> boundary;
82  gsVector<T> b(1);
83  gsMatrix<T> fpts, tmp;
84 
85  gsMatrix<T> & fixedDofs = const_cast<expr::gsFeSpace<T>&>(u).fixedPart();
86  fixedDofs.setZero(u.mapper().boundarySize(), 1 );
87 
88  // Iterate over all patch-sides with Boundary conditions
89  typedef gsBoundaryConditions<T> bcList;
90  for ( typename bcList::const_iterator it = bc.begin("Dirichlet");
91  it != bc.end("Dirichlet") ; ++it )
92  {
93  if( it->unknown()!=u.id() ) continue;
94 
95  const index_t com = it->unkComponent();
96 
97  const int k = it->patch();
98  const gsBasis<T> & basis = u.source().basis(k);
99 
100  // Get dofs on this boundary
101  boundary = basis.boundary(it->side());
102 
103  // Get the side information
104  const int dir = it->side().direction( );
105  const index_t param = (it->side().parameter() ? 1 : 0);
106 
107  // Get basis on the boundary
108  typename gsBasis<T>::uPtr h = basis.boundaryBasis(it->side());
109 
110  //
111  for (index_t r = 0; r!=u.dim(); ++r)
112  {
113  if (com!=-1 && r!=com) continue;
114 
115  // If the condition is homogeneous then fill with zeros
116  if ( it->isHomogeneous() )
117  {
118  for (index_t i=0; i!= boundary.size(); ++i)
119  {
120  const int ii = u.mapper().bindex( boundary.at(i) , k, r );
121  fixedDofs.at(ii) = 0;
122  }
123  continue;
124  }
125 
126  // Compute grid of points on the face ("face anchors")
127  rr.clear();
128  rr.reserve( parDim );
129 
130  for ( int i=0; i < parDim; ++i)
131  {
132  if ( i==dir )
133  {
134  b[0] = ( basis.component(i).support() ) (0, param);
135  rr.push_back(b);
136  }
137  else
138  {
139  rr.push_back( basis.component(i).anchors().transpose() );
140  }
141  }
142 
143  // GISMO_ASSERT(it->function()->targetDim() == u.dim(),
144  // "Given Dirichlet boundary function does not match problem dimension."
145  // <<it->function()->targetDim()<<" != "<<u.dim()<<"\n");
146 
147  // Compute dirichlet values
148  if ( it->parametric() )
149  fpts = it->function()->piece(it->patch()).eval( gsPointGrid<T>( rr ) );
150  else
151  {
152  const gsFunctionSet<T> & gmap = bc.geoMap();
153  fpts = it->function()->piece(it->patch()).eval( gmap.piece(it->patch()).eval( gsPointGrid<T>( rr ) ) );
154  }
155 
156  // Interpolate dirichlet boundary
157  typename gsGeometry<T>::uPtr geo = h->interpolateAtAnchors(fpts);
158  const gsMatrix<T> & dVals = geo->coefs();
159 
160  // Save corresponding boundary dofs
161  for (index_t l=0; l!= boundary.size(); ++l)
162  {
163  const int ii = u.mapper().bindex( boundary.at(l) , k, r );
164  fixedDofs.at(ii) = dVals.at(l);
165  }
166  }
167  }
168 }
169 
170 // Not called and used, todo
171 template<class T> void
172 gsDirichletValuesInterpolationTP(const expr::gsFeSpace<T> & u,
173  const boundary_condition<T> & bc,
174  gsMatrix<index_t> & boundary,
175  gsMatrix<T> & values)
176 {
177  const index_t parDim = u.source().domainDim();
178 
179  const gsFunctionSet<T> & gmap = bc.geoMap();
180  std::vector< gsVector<T> > rr;
181 
182  gsVector<T> b(1);
183  gsMatrix<T> fpts, tmp;
184 
185  gsMatrix<T> & fixedDofs = const_cast<expr::gsFeSpace<T>&>(u).fixedPart();
186 
187  if( bc.unknown()!=u.id() ) { boundary.clear(); values.clear(); return; }
188 
189  const int k = bc.patch();
190  const gsBasis<T> & basis = u.source().basis(k);
191 
192  // Get dofs on this boundary
193  boundary = basis.boundary(bc.side());
194 
195  // If the condition is homogeneous then fill with zeros
196  if ( bc.isHomogeneous() )
197  {
198  const index_t com = bc.unkComponent();
199  values.setZero(boundary.size(), (-1==com ? u.dim():1) );
200  return;
201  }
202 
203  // Get the side information
204  int dir = bc.side().direction( );
205  index_t param = (bc.side().parameter() ? 1 : 0);
206 
207  // Compute grid of points on the face ("face anchors")
208  rr.clear();
209  rr.reserve( parDim );
210 
211  for ( int i=0; i < parDim; ++i)
212  {
213  if ( i==dir )
214  {
215  b[0] = ( basis.component(i).support() ) (0, param);
216  rr.push_back(b);
217  }
218  else
219  {
220  rr.push_back( basis.component(i).anchors().transpose() );
221  }
222  }
223 
224  // GISMO_ASSERT(bc.function()->targetDim() == u.dim(),
225  // "Given Dirichlet boundary function does not match problem dimension."
226  // <<bc.function()->targetDim()<<" != "<<u.dim()<<"\n");
227 
228  // Compute dirichlet values
229  if ( bc.parametric() )
230  fpts = bc.function()->eval( gsPointGrid<T>( rr ) );
231  else
232  {
233  const gsFunctionSet<T> & gmap = bc.geoMap();
234  fpts = bc.function()->eval( gmap.piece(bc.patch()).eval( gsPointGrid<T>( rr ) ) );
235  }
236 
237  /*
238  if ( fpts.rows() != u.dim() )
239  {
240  // assume scalar
241  tmp.resize(u.dim(), fpts.cols());
242  tmp.setZero();
243  gsDebugVar(!dir);
244  tmp.row(!dir) = (param ? 1 : -1) * fpts; // normal !
245  fpts.swap(tmp);
246  }
247  */
248 
249  // Interpolate dirichlet boundary
250  typename gsBasis<T>::uPtr h = basis.boundaryBasis(bc.side());
251  typename gsGeometry<T>::uPtr geo = h->interpolateAtAnchors(fpts);
252  values = give( geo->coefs() );
253 }
254 
255 
256 template<class T>
257 void gsDirichletValuesByL2Projection( const expr::gsFeSpace<T> & u,
258  const gsBoundaryConditions<T> & bc)
259 {
260  const gsFunctionSet<T> & gmap = bc.geoMap();
261 
262  const gsDofMapper & mapper = u.mapper();
263  gsMatrix<T> & fixedDofs = const_cast<expr::gsFeSpace<T>& >(u).fixedPart();
264 
265  // Set up matrix, right-hand-side and solution vector/matrix for
266  // the L2-projection
267  gsSparseEntries<T> projMatEntries;
268  gsMatrix<T> globProjRhs;
269  globProjRhs.setZero(u.mapper().boundarySize(), 1 );
270 
271  // Temporaries
272  gsVector<T> quWeights;
273  gsMatrix<T> basisVals, rhsVals;
274  gsMatrix<index_t> globIdxAct, globBasisAct;
275 
276  gsMapData<T> md(NEED_MEASURE | SAME_ELEMENT);
277 
278  // eltBdryFcts stores the row in basisVals/globIdxAct, i.e.,
279  // something like a "element-wise index"
280  std::vector<index_t> eltBdryFcts;
281 
282  //const gsMultiPatch<T> & mp = static_cast<const gsMultiPatch<T> &>(gmap);
283 
284  // Iterate over all patch-sides with Dirichlet-boundary conditions
285  typedef gsBoundaryConditions<T> bcList;
286  for (typename bcList::const_iterator iter = bc.begin("Dirichlet");
287  iter != bc.end("Dirichlet"); ++iter)
288  {
289  const int unk = iter->unknown();
290  if(unk != u.id()) continue;
291 
292  const index_t com = iter->unkComponent();
293  const int patchIdx = iter->patch();
294  const gsBasis<T> & basis = u.source().basis(patchIdx);
295  const gsFunction<T> & patch = gmap.function(patchIdx);
296 
297  // Set up quadrature to degree+1 Gauss points per direction,
298  // all lying on iter->side() except from the direction which
299  // is NOT along the element
300  gsGaussRule<T> bdQuRule(basis, 1.0, 1, iter->side().direction());
301 
302  // Create the iterator along the given part boundary.
303  typename gsBasis<T>::domainIter bdryIter = basis.makeDomainIterator(iter->side());
304 
305 
306  for (; bdryIter->good(); bdryIter->next())
307  {
308  bdQuRule.mapTo(bdryIter->lowerCorner(), bdryIter->upperCorner(),
309  md.points, quWeights);
310 
311  patch.computeMap(md);
312 
313  // Indices involved here:
314  // --- Local index:
315  // Index of the basis function/DOF on the patch.
316  // Does not take into account any boundary or interface conditions.
317  // --- Global Index:
318  // Each DOF has a unique global index that runs over all patches.
319  // This global index includes a re-ordering such that all eliminated
320  // DOFs come at the end.
321  // The global index also takes care of glued interface, i.e., corresponding
322  // DOFs on different patches will have the same global index, if they are
323  // glued together.
324  // --- Boundary Index (actually, it's a "Dirichlet Boundary Index"):
325  // The eliminated DOFs, which come last in the global indexing,
326  // have their own numbering starting from zero.
327 
328  // Get the global indices (second line) of the local
329  // active basis (first line) functions/DOFs:
330  basis.active_into(md.points.col(0), globBasisAct);
331 
332  // Compute the basis function values because they don't
333  // depend on the component
334  basis.eval_into(md.points, basisVals);
335 
336  for (index_t r = 0; r!=u.dim(); ++r)
337  {
338  if (com!=-1 && r!=com) continue;
339 
340  mapper.localToGlobal(globBasisAct, patchIdx, globIdxAct,r);
341 
342  // Out of the active functions/DOFs on this element, collect all those
343  // which correspond to a boundary DOF.
344  // This is checked by calling mapper.is_boundary_index( global Index )
345 
346  // eltBdryFcts stores the row in basisVals/globIdxAct, i.e.,
347  // something like a "element-wise index"
348  eltBdryFcts.clear();
349  eltBdryFcts.reserve(mapper.boundarySize());
350  for (index_t i = 0; i < globIdxAct.rows(); i++)
351  {
352  if (mapper.is_boundary_index(globIdxAct.at(i)))
353  {
354  eltBdryFcts.push_back(i);
355  }
356  }
357 
358  // the values of the boundary condition are stored
359  // to rhsVals. Here, "rhs" refers to the right-hand-side
360  // of the L2-projection, not of the PDE.
361 
362  // if the component is not specified and the function evaluates
363  // for all target dimensions simultaneous, rhsValues does not
364  // need to be updated
365  if ((com != -1) || (r == 0))
366  {
367  // If the condition is homogeneous then fill with zeros
368  if (iter->isHomogeneous())
369  {
370  rhsVals.setZero((com==-1) ? u.dim() : 1, md.points.size());
371  }
372  else
373  {
374  if (iter->parametric())
375  rhsVals =
376  iter->function()->piece(patchIdx).eval(md.points);
377  else
378  rhsVals = iter->function()->piece(patchIdx).eval(
379  gmap.piece(patchIdx).eval(md.points));
380  }
381  }
382 
383  GISMO_ASSERT((com!=-1) || rhsVals.rows() == u.dim(),
384  "If no component is specified for Dirichlet boundary, "
385  "target dimension must match field dimension.");
386  GISMO_ASSERT((com==-1) || rhsVals.rows() == 1,
387  "If the component is specified for Dirichlet boundary, "
388  "then a scalar function is expected.");
389 
390  // Do the actual assembly:
391  for (index_t k = 0; k < md.points.cols(); k++)
392  {
393  const T weight_k = quWeights[k] * md.measure(k);
394 
395  // Only run through the active boundary functions on the element:
396  for (size_t i0 = 0; i0 < eltBdryFcts.size(); i0++)
397  {
398  // Each active boundary function/DOF in eltBdryFcts has...
399  // ...the above-mentioned "element-wise index"
400  const index_t i = eltBdryFcts[i0];
401  // ...the boundary index.
402  const index_t ii = mapper.global_to_bindex(globIdxAct.at(i));
403 
404  for (size_t j0 = 0; j0 < eltBdryFcts.size(); j0++)
405  {
406  const index_t j = eltBdryFcts[j0];
407  const index_t jj = mapper.global_to_bindex(globIdxAct.at(j));
408 
409  // Use the "element-wise index" to get the needed
410  // function value.
411  // Use the boundary index to put the value in the proper
412  // place in the global projection matrix.
413  projMatEntries.add(ii, jj, weight_k * basisVals(i, k) * basisVals(j, k));
414  } // for j
415 
416  globProjRhs.at(ii) += weight_k * basisVals(i, k) * rhsVals( (-1==com?r:0) ,k);
417  //globProjRhs.at(ii) += weight_k * basisVals(i, k) * rhsVals(r ,k);
418 
419  } // for i
420  } // for k
421  }// for r
422  } // bdryIter
423  } // boundaryConditions-Iterator
424 
425  gsSparseMatrix<T> globProjMat(mapper.boundarySize(), mapper.boundarySize());
426  globProjMat.setFrom(projMatEntries);
427  globProjMat.makeCompressed();
428 
429  // Solve the linear system:
430  // The position in the solution vector already corresponds to the
431  // numbering by the boundary index. Hence, we can simply take them
432  // for the values of the eliminated Dirichlet DOFs.
433  typename gsSparseSolver<T>::CGDiagonal solver;
434  fixedDofs = solver.compute(globProjMat).solve(globProjRhs);
435 } // computeDirichletDofsL2Proj
436 
437 
438 
439 }; // namespace gismo
const_citerator cornerBegin() const
Definition: gsBoundaryConditions.h:561
index_t boundarySize() const
Returns the number of eliminated dofs.
Definition: gsDofMapper.h:457
S give(S &x)
Definition: gsMemory.h:266
#define index_t
Definition: gsConfig.h:32
Provides assembler and solver options.
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
Maintains a mapping from patch-local dofs to global dof indices and allows the elimination of individ...
Definition: gsDofMapper.h:68
Provides the gsDofMapper class for re-indexing DoFs.
T at(index_t i) const
Returns the i-th element of the vectorization of the matrix.
Definition: gsMatrix.h:211
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
Definition: gsDirichletValues.h:23
const bcContainer & container(const std::string &label) const
Return a reference to boundary conditions of certain type.
Definition: gsBoundaryConditions.h:416
virtual const gsBasis & source() const
Definition: gsBasis.h:704
const_citerator cornerEnd() const
Definition: gsBoundaryConditions.h:566
The density of the measure pull back.
Definition: gsForwardDeclarations.h:76
index_t bindex(index_t i, index_t k=0, index_t c=0) const
Returns the boundary index of local dof i of patch k.
Definition: gsDofMapper.h:334
Enable optimizations based on the assumption that all evaluation points are in the same bezier domain...
Definition: gsForwardDeclarations.h:89
Class containing a set of boundary conditions.
Definition: gsBoundaryConditions.h:341
Provides functions to generate structured point data.
Provides gsBoundaryConditions class.
#define GISMO_ERROR(message)
Definition: gsDebug.h:118
A basis represents a family of scalar basis functions defined over a common parameter domain...
Definition: gsBasis.h:78