G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsDirichletValues.h
Go to the documentation of this file.
1
14#include <gsUtils/gsPointGrid.h>
15#include <gsCore/gsDofMapper.h>
18
19namespace gismo {
20
21namespace expr
22{
23template<class T> class gsFeSpace;
24};
25
26template<class T>
27void 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
74template<class T>
75void 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
171template<class T> void
172gsDirichletValuesInterpolationTP(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
256template<class T>
257void 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
memory::unique_ptr< gsBasis > uPtr
Unique pointer for gsBasis.
Definition gsBasis.h:89
memory::unique_ptr< gsGeometry > uPtr
Unique pointer for gsGeometry.
Definition gsGeometry.h:100
Provides assembler and solver options.
Provides gsBoundaryConditions class.
#define index_t
Definition gsConfig.h:32
#define GISMO_ERROR(message)
Definition gsDebug.h:118
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Provides the gsDofMapper class for re-indexing DoFs.
Provides functions to generate structured point data.
The G+Smo namespace, containing all definitions for the library.
@ SAME_ELEMENT
Enable optimizations based on the assumption that all evaluation points are in the same bezier domain...
Definition gsForwardDeclarations.h:89
@ NEED_MEASURE
The density of the measure pull back.
Definition gsForwardDeclarations.h:76
S give(S &x)
Definition gsMemory.h:266