G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsFunction.hpp
Go to the documentation of this file.
1
15#include <gsCore/gsFuncData.h>
18
19#ifdef gsIpOpt_ENABLED
20#include <gsIpOpt/gsIpOpt.h>
21#endif
22
23#ifdef gsHLBFGS_ENABLED
24#include <gsHLBFGS/gsHLBFGS.h>
25#endif
26
28
30
31#pragma once
32
33
34namespace gismo
35{
36
37template <class T>
39{
40 return gsFuncCoordinate<T>(*this,c);
41}
42
43template <class T>
46{
47 gsMatrix<T> result;
48 this->jacobian_into( u, result );
49 return result;
50}
51
52template <class T>
54{
55 // Compute component gradients as columns of result
56 deriv_into(u, result);
57
58 // Reshape the matrix to get one Jacobian block per evaluation point
59 const short_t d = domainDim(); // dimension of domain
60 result.resize(d, result.size()/d); //transposed Jacobians
61 result.blockTransposeInPlace( targetDim() );
62}
63
64template <class T>
65void gsFunction<T>::div_into(const gsMatrix<T>& u, gsMatrix<T>& result) const
66{
67
68 // Compute component gradients as columns of result
69 deriv_into(u, result);
70 //gsDebug << "deriv_into result:\n" << result << "\n";
71
72
73 const index_t numPts = u.cols(); // number of points to compute at
74 const index_t d = domainDim(); // dimension of domain
75
76 gsVector<T> tmp_div(numPts); // tmp. divergence storage
77 tmp_div.setZero(); // initialize by zeros
78 gsVector<T> resCol(d * d);
79
80 for ( index_t p = 0; p < numPts; p++ ) { // for all evaluation points
81 resCol = result.col(p);
82 for ( index_t i = 0; i < d; i++ ) { tmp_div(p) += resCol(i * d + i); }
83 }
84 // Resizing the result to store the
85 result.resize(1, numPts);
86 result = tmp_div.transpose();
87
88 //gsDebug << "div_into:\n" << result << "\n";
89
90}
91
92template <class T>
94{
95
96 //gsDebug<< "Using finite differences (gsFunction::deriv_into) for derivatives.\n";
97 const index_t parDim = u.rows(); // dimension of domain
98 const index_t tarDim = targetDim(); // dimension of codomain
99 const index_t numPts = u.cols(); // number of points to compute at
100
101 gsVector<T> delta(parDim);
102 gsVector<T> tmp(tarDim);
103
104 gsMatrix<T> ev, uc(parDim,4);
105 result.resize( parDim * tarDim, numPts );
106
107 for ( index_t p = 0; p < numPts; p++ ) // for all evaluation points
108 {
109 for ( index_t j = 0; j<parDim; j++ ) // for all variables
110 {
111 delta.setZero();
112 delta(j) = (T)(0.00001);
113 uc.col(0) = u.col(p)+delta;
114 uc.col(1) = u.col(p)-delta;
115 delta(j) = (T)(0.00002);
116 uc.col(2) = u.col(p)+delta;
117 uc.col(3) = u.col(p)-delta;
118 //m_geo.eval_into(u, tmp);
119 this->eval_into(uc, ev );
120 tmp=(8*( ev.col(0)- ev.col(1)) + ev.col(3) - ev.col(2) ) / (T)(0.00012);
121
122 for (index_t c=0; c<tarDim; ++c) // for all components
123 result(c*parDim+j,p)=tmp(c);
124 }
125 }
126}
127
128
129template <class T>
131{
132 //gsDebug << "Using finite differences (gsFunction::deriv2_into) for second derivatives.\n";
133 const int d = u.rows(); // dimension of domain
134 const int n = targetDim(); // dimension of codomain
135 const int numPts = u.cols(); // number of points to compute at
136 gsVector<T> tmp( d );
137 gsMatrix<T> ev, uc( d, 3 ), ucm( d, 4 );
138 const int stride = d + d * ( d - 1 ) / 2; // number of second derivatives per component [= d(d+1)/2]
139 result.resize( n * stride , numPts );
140 for ( int thisPt = 0; thisPt < numPts; thisPt++ )
141 {
142 int r = d;
143 for ( int j = 0; j < d; j++ )
144 {
145 // pure 2nd derivs
146 tmp.setZero();
147 tmp( j ) = (T)( 0.00001 );
148 uc.col( 0 ) = u.col( thisPt ) + tmp;
149 uc.col( 1 ) = u.col( thisPt ) ;
150 uc.col( 2 ) = u.col( thisPt ) - tmp;
151 this->eval_into( uc, ev );
152 for ( int k = 0; k < n; k++ ) // for all coordinates
153 result( k * stride + j, thisPt ) =
154 ( ev( k, 0 ) - (T)(2) * ev( k, 1 ) + ev( k, 2 ) ) / (T)( 0.0000000001 ) ;
155 // mixed 2nd derivs
156 for ( int l = j + 1; l < d; l++ )
157 {
158 tmp( l ) = (T)( 0.00001 );
159 ucm.col( 0 ) = u.col( thisPt ) + tmp;
160 ucm.col( 3 ) = u.col( thisPt ) - tmp;
161 tmp( l ) = (T)( -0.00001 );
162 ucm.col( 1 ) = u.col( thisPt ) + tmp;
163 ucm.col( 2 ) = u.col( thisPt ) - tmp;
164 tmp( l ) = (T)( 0 );
165 this->eval_into( ucm, ev );
166 for ( int k = 0; k < n; k++ ) // for all coordinates
167 result( k * stride + r, thisPt ) =
168 ( ev( k, 0 ) - ev( k, 1 ) - ev( k, 2 ) + ev( k, 3 ) ) / (T)( 0.0000000004 ) ;
169 r++;
171 }
172 }
173}
174
176template <class T>
178{
179 //gsDebug << "Using finite differences (gsFunction::laplacian) for computing Laplacian.\n";
180 int d = u.rows();
181 gsVector<T> tmp( d );
182 gsMatrix<T> res( d, u.cols());
183 for ( int j = 0; j < d; j++ )
184 {
185 tmp.setZero();
186 tmp( j, 0 ) = (T)( 0.0000000001 );
187 res.row( j ) = 16 * ( this->eval(u.colwise() + tmp ) +
188 this->eval(u.colwise() - tmp ) ) -
189 30 * ( this->eval( u ) );
190 tmp( j, 0 ) = (T)( 0.0000000002 );
191 res.row( j ) -= ( this->eval( u.colwise() - tmp ) +
192 this->eval( u.colwise() + tmp ) ) ;
193 res.row( j ) /= (T)( 0.0000000012 ) ;
194 }
195 return res;
196}
198template<class T>
200 gsMatrix<T> & result,
201 const T accuracy, const bool useInitialPoint) const
202{
203 result.resize(this->domainDim(), points.cols() );
204 gsVector<T> arg;
205 for ( index_t i = 0; i!= points.cols(); ++i)
206 {
207 if (useInitialPoint)
208 arg = result.col(i);
209 else
210 arg = this->parameterCenter();
211 //arg = _argMinNormOnGrid(16);
212
213 const int iter = this->newtonRaphson(points.col(i), arg, true, accuracy, 250);
214 if (iter>100)
215 gsWarn<< "Inversion took "<<iter<<" steps for "<< points.col(i).transpose() <<" (result="<< arg.transpose()<< ")\n";
216
217 if (-1==iter)
218 {
219 gsWarn<< "Inversion failed for: "<< points.col(i).transpose() <<" (result="<< arg.transpose()<< ")\n";
220 result.col(i).setConstant( std::numeric_limits<T>::infinity() );
221 }
222 else
223 result.col(i) = arg;
224 }
225/* // alternative impl using closestPointTo
226 result.resize(parDim(), points.cols() );
227 gsVector<T> pt, arg;
228 for ( index_t i = 0; i!= points.cols(); ++i )
229 {
230 pt = points.col(i);
231 if (useInitialPoint)
232 arg = result.col(i);
233
234 this->closestPointTo(pt, arg, accuracy, useInitialPoint);
235 if ( (this->eval(arg)-pt).norm()<=accuracy )
236 result.col(i) = arg;
237 else
239 //result.col(i) = arg;
240 result.col(i).setConstant( std::numeric_limits<T>::infinity() );
241 }
242 }
243*/
244}
245
246template<class T>
247void gsFunction<T>::invertPointGrid(gsGridIterator<T,0> & git,
248 gsMatrix<T> & result, const T accuracy,
249 const bool useInitialPoint) const
250{
251 GISMO_UNUSED(useInitialPoint);
252 result.resize(this->domainDim(), git.numPoints() );
254 auto cw = git.numPointsCwise();
255 git.reset();
256 index_t i = 0;
257 int iter = -1;
258 gsInfo << "Iterations: ";
259 for(;git; ++git)
260 {
261 if (-1==iter)
262 arg = this->parameterCenter();
263 else
264 arg = (i%cw[0]==0 ? result.col(i-cw[0]) : result.col(i-1) );
265
266 iter = this->newtonRaphson(*git, arg, true, accuracy, 500);
267 if (100 < iter) gsInfo << " "<< iter;
268 if (-1==iter)
270 gsWarn<< "--- "<<i<<" Inversion failed for: "<< git->transpose() <<" ("
271 << (i%cw[0]==0 ? result.col(i-cw[0]) : result.col(i-1) ).transpose() << " -> " << arg.transpose()<< " )\n";
272 //result.col(i).setConstant( std::numeric_limits<T>::infinity() );
273 }
274 //else gsWarn<< "+Inversion OK "<< git->transpose() <<" (result="<< arg.transpose()<< ")\n";
275
276 result.col(i++) = arg;
277 }
278 gsInfo << "\n";
279}
280
281template <class T>
282template <int mode,int _Dim>
283int gsFunction<T>::newtonRaphson_impl(
284 const gsVector<T> & value,
285 gsVector<T> & arg,
286 bool withSupport,
287 const T accuracy,
288 int max_loop,
289 T damping_factor, T scale) const
290{
291 const index_t n = value.rows();
292 const bool squareJac = (n == domainDim());//assumed for _Dim!=-1
294 GISMO_ASSERT( arg.size() == domainDim(),
295 "Input argument has wrong dimensions: "<< arg.transpose() );
296
297 gsMatrix<T> supp;
298 gsMatrix<T,_Dim,(_Dim==-1?-1:1)> delta , residual;
300
301 if (withSupport)
302 {
303 supp = support();
304 GISMO_ASSERT( (arg.array()>=supp.col(0).array()).all() &&
305 (arg.array()<=supp.col(1).array()).all(),
306 "Initial point is outside the domain.\n point = "<<arg<<"\n domain = "<<supp);
307 }
308 int iter = 1;
309 T rnorm[2]; rnorm[0]=1e100;
310 //T alpha=.5, beta=.5;
311 gsFuncData<T> fd(0==mode?(NEED_VALUE|NEED_DERIV):(NEED_DERIV|NEED_HESSIAN));
312
313 do {
314 this->compute(arg,fd);
315 residual = (0==mode?fd.values[0]:fd.values[1]);
316
317 residual.noalias() = value - scale*residual;
318 rnorm[iter%2] = residual.norm();
319
320 if(rnorm[iter%2] <= accuracy) // residual below threshold
321 {
322 //gsInfo <<"--- OK: Accuracy "<<rnorm[iter%2]<<" reached after "<<iter <<"iterations.\n";
323 return iter;
324 }
325
326 // compute Jacobian
327 if (0==mode)
328 jac = scale * fd.jacobian(0);
329 else // (1==mode)
330 jac = scale * fd.hessian(0);
331
332 // Solve for next update
333 if (squareJac)
334 {
335 //const T ddet = jac.determinant();
336 //if (math::abs(ddet)<1e-4)
337 // gsWarn<< "Singular Jacobian: "<< ddet <<"\n";
338
339 if (-1==_Dim)
340 delta.noalias() = jac.partialPivLu().solve( residual );
341 else
342 delta.noalias() = jac.inverse() * residual;
343 }
344 else// use pseudo-inverse
345 delta.noalias() = jac.colPivHouseholderQr().solve(
346 gsMatrix<T>::Identity(n,n)) * residual;
347
348 const T rr = ( 1==iter ? (T)1.51 : rnorm[(iter-1)%2]/rnorm[iter%2] ); //important to start with small step
349 damping_factor = rr<1.5 ? math::max((T)0.1 + (rr/99),(rr-(T)0.5)*damping_factor) : math::min((T)1,rr*damping_factor);
350
351 //Line search
352 /*
353 real_t val = (this->eval(arg + damping_factor*delta)*scale - value).norm();
354
355 for(index_t i = 1; i!=11; ++i)
356 {
357 val = 0 ;
358 }
359 */
360
361 //gsInfo << "Newton it " << iter << " arg=" << arg.transpose() << ", f(arg)="
362 // << (0==mode?fd.values[0]:fd.values[1]).transpose() << ", res=" << residual.transpose()
363 // <<" ("<<rr<<" ~ "<<damping_factor<<"), norm=" << rnorm[iter%2] << "\n";
364
365 // update arg
366 arg += damping_factor * delta;
367
368 if ( withSupport )
369 {
370 // First bound the solution to the support
371 arg = arg.cwiseMax( supp.col(0) ).cwiseMin( supp.col(1) );
372 if ( delta.norm()<accuracy )
373 {
374 //gsInfo <<"OK: Newton reached boundary of support "<< delta.norm() <<"\n";
375 return iter;
376 }
377 }
378
379 } while (++iter <= max_loop);
380
381 gsWarn <<"--- Newton method did not converge after "<< max_loop
382 <<" iterations. Residual norm: "<< rnorm[max_loop%2]<<".\n";
383
384 return -1;
385}
386
387template <class T>
388gsVector<T> gsFunction<T>::_argMinOnGrid(index_t numpts) const
389{
390 gsVector<T> result;
391 gsMatrix<T> supp = this->support();
392 if (0!=supp.size())
393 {
394 result = this->parameterCenter();
395 gsGridIterator<T,CUBE> pt(supp, numpts);//per direction
396 T val, mval = this->eval(result).value();
397 for(;pt; ++pt)
398 {
399 val = this->eval(*pt).value();
400 if (val < mval )
401 {
402 mval = val;
403 result = *pt;
404 }
405 }
406 }
407 else
408 {
409 //take random points?
410 result.setZero( domainDim() );
411 }
412 return result;
413}
414
415template <class T>
416gsVector<T> gsFunction<T>::_argMinNormOnGrid(index_t numpts) const
417{
418 gsVector<T> result;
419 gsMatrix<T> supp = this->support();
420 if (0!=supp.size())
421 {
422 result = this->parameterCenter();
423 gsGridIterator<T,CUBE> pt(supp, numpts);//per direction
424 T val, mval = this->eval(result).squaredNorm();
425 for(;pt; ++pt)
426 {
427 if ( (val = this->eval(*pt).squaredNorm())<mval )
428 {
429 mval = val;
430 result = *pt;
431 }
432 }
433 }
434 else
435 {
436 //take random points?
437 result.setZero( domainDim() );
438 }
439 return result;
440}
441
442template <class T>
444 gsVector<T> & arg,
445 bool withSupport,
446 const T accuracy,
447 int max_loop,
448 T damping_factor) const
449{
450 GISMO_ASSERT( value.rows() == targetDim(),
451 "Invalid input values:"<< value.rows()<<"!="<<targetDim());
452 return newtonRaphson_impl<0>(value,arg,withSupport,accuracy,
453 max_loop,damping_factor);
454}
455
456template <class T>
457gsMatrix<T> gsFunction<T>::argMin(const T accuracy,
458 int max_loop,
459 gsMatrix<T> init,
460 T damping_factor) const
461{
462 GISMO_ASSERT(1==targetDim(), "Currently argMin works for scalar functions");
463 gsVector<T> result;
464
465 // Initial point
466 if ( 0 != init.size() )
467 result = give(init);
468 else
469 {
470 result = _argMinOnGrid(20);
471 }
472
473#ifdef gsHLBFGS_ENABLED
474 gsFunctionAdaptor<T> fmin(*this);
475 // gsIpOpt<T> solver( &fmin );
476 //gsGradientDescent<T> solver( &fmin );
477 gsHLBFGS<T> solver( &fmin );
478 solver.options().setInt("MaxIterations",100);
479 solver.options().setInt("Verbose",0);
480 //MinStep..1e-12
481 solver.solve(result);
482 result = solver.currentDesign();
483 return result;
484#else
485 int dd=domainDim();
486 switch (dd)
487 {
488 case 2:
489 newtonRaphson_impl<1,2>(gsVector<T>::Zero(dd), result, true,
490 accuracy,max_loop,damping_factor,(T)1);//argMax: (T)(-1)
491 break;
492 default:
493 newtonRaphson_impl<1>(gsVector<T>::Zero(dd), result, true,
494 accuracy,max_loop,damping_factor,(T)1);//argMax: (T)(-1)
495 }
496#endif
497
498 return result;
499}
500
501//argMax
502
503template<class T>
505 const T accuracy) const
506{
507 gsVector<index_t> ind(xyz.rows()-1);
508 for (index_t i = 0; i!= xyz.rows(); ++i)
509 if (i<k) ind[i]=i;
510 else if (i>k) ind[i-1]=i;
511
512 gsMatrix<T> pt = xyz(ind,gsEigen::all);
513 gsFuncCoordinate<T> fc(*this, give(ind));
514
515 //find low accuracy closest point
516 // uv.resize(this->domainDim(), xyz.cols() );
517 // for (index_t i = 0; i!= xyz.cols(); ++i)
518 // {
519 // gsSquaredDistance2<T> dist2(fc, pt.col(i));
520 // uv.col(i) = dist2.argMin(accuracy, 10000) ;
521 // }
522
523 fc.invertPoints(pt,uv,accuracy,false); //true
524 xyz = this->eval(uv);
525 //possible check: pt close to xyz
526}
527
528template<class T>
529void gsFunction<T>::recoverPointGrid(gsGridIterator<T,0> & git,
530 gsMatrix<T> & xyz, gsMatrix<T> & uv,
531 index_t k, const T accuracy) const
532{
533 gsVector<index_t> ind(xyz.rows()-1);
534 for (index_t i = 0; i!= xyz.rows(); ++i)
535 if (i<k) ind[i]=i;
536 else if (i>k) ind[i-1]=i;
537
538 gsMatrix<T> pt = xyz(ind,gsEigen::all);
539 gsFuncCoordinate<T> fc(*this, give(ind));
540
541 fc.invertPointGrid(git,uv,accuracy,false); //true
542 xyz = this->eval(uv);
543}
544
545template <class T>
550
551template<class T>
553{
554 gsMatrix<T> supp = this->support();
555 const index_t dim = supp.rows();
556 gsMatrix<T> coordinates(dim,1);
557 gsVector<bool> boxPar = bc.parameters(dim);
558 for (index_t d=0; d<dim;++d)
559 {
560 if (boxPar(d))
561 coordinates(d,0) = supp(d,1);
562 else
563 coordinates(d,0) = supp(d,0);
564 }
565 return coordinates;
566}
567
568template<class T>
570{
571 gsMatrix<T> supp = this->support();
572 const index_t dim = supp.rows();
573 gsMatrix<T> coordinates(dim,1);
574 const index_t dir = bc.direction();
575 for (index_t d=0; d<dim;++d)
576 {
577 if (d != dir)
578 coordinates(d,0) = ( supp(d,1) + supp(d,0) ) / (T)(2);
579 else if (bc.parameter())
580 coordinates(d,0) = supp(d,1);
581 else
582 coordinates(d,0) = supp(d,0);
583 }
584 return coordinates;
585}
586
587template <class T> void
589 index_t coord) const
590{
591 gsMatrix<T> secDers;
592 this->deriv2_into(u, secDers);
593 const index_t dim = this->domainDim();
594 const index_t nd = dim*(dim+1)/2;
595 result = util::secDerToHessian(secDers.middleCols(coord*nd,nd), dim);
596}
597
598template <typename T, short_t domDim, short_t tarDim>
599inline void computeAuxiliaryData(const gsFunction<T> &src, gsMapData<T> & InOut, int d, int n)
600{
601 //GISMO_ASSERT( domDim*tarDim == 1, "Both domDim and tarDim must have the same sign");
602 const index_t numPts = InOut.points.cols();
603
604 // If the measure on a boundary is requested, calculate the outer normal vector as well
605 if ( InOut.side!=boundary::none && (InOut.flags & NEED_MEASURE) ) InOut.flags|=NEED_OUTER_NORMAL;
606
607 // Outer normal vector
608 if ( InOut.flags & NEED_OUTER_NORMAL)
609 {
610 if (InOut.side==boundary::none)
611 gsWarn<< "Computing boundary normal without a valid side.\n";
612 // gsDebugVar( InOut.side);
613 const T sgn = sideOrientation(InOut.side);
614 // gsDebugVar( sgn );
615 const int dir = InOut.side.direction();
616 InOut.outNormals.resize(n,numPts);
617
618 if (tarDim!=-1 ? tarDim == domDim : n==d)
619 {
620 if ( 1==n ) { InOut.outNormals.setConstant(sgn); return; } // 1D case
621
622 T det_sgn = 0;
623 typename gsMatrix<T,domDim,tarDim>::FirstMinorMatrixType minor;
624 // Determine Jacobian determinant's sign, assume constant along boundary
625 if (InOut.flags & SAME_ELEMENT )
626 {
627 for (index_t p=0; p!=numPts; ++p)
628 {
629 const gsAsConstMatrix<T,domDim,tarDim> jacT(InOut.values[1].col(p).data(), d, n);
630 T detJacTcurr = jacT.determinant();
631 if ( math::abs(detJacTcurr) >= 1e-7 )
632 {
633 det_sgn = detJacTcurr < 0 ? -1 : 1;
634 break;
635 }
636 }
637 if ( 0 == det_sgn )
638 {
639 gsMatrix<T> parameterCenter = src.parameterCenter(InOut.side);
640 T detJacTcurr = src.jacobian(parameterCenter).determinant();
641 det_sgn = detJacTcurr < 0 ? -1 : 1;
642 }
643 }
644 for (index_t p=0; p!=numPts; ++p)
645 {
646 const gsAsConstMatrix<T,domDim,tarDim> jacT(InOut.values[1].col(p).data(), d, n);
647 // BUG: When the determinant is really close to zero but negative,
648 // the result might be the opposite of what is expected because of alt_sgn
649
650 if (! (InOut.flags &SAME_ELEMENT) )
651 {
652 T detJacTcurr = jacT.determinant();
653 det_sgn = math::abs(detJacTcurr) < 1e-7 ? 0 :
654 ( detJacTcurr < 0 ? -1 : 1 );
655 if ( 0 == det_sgn )
656 {
657 gsMatrix<T> parameterCenter = src.parameterCenter(InOut.side);
658 detJacTcurr = src.jacobian(parameterCenter).determinant();
659 det_sgn = detJacTcurr < 0 ? -1 : 1;
660 }
661 }
662 GISMO_ENSURE(det_sgn!=0, "Cannot find a non-zero Jacobian determinant.\n" << InOut.points);
663
664 T alt_sgn = sgn * det_sgn;
665 for (int i = 0; i != n; ++i) //for all components of the normal
666 {
667 jacT.firstMinor(dir, i, minor);
668 InOut.outNormals(i,p) = alt_sgn * minor.determinant();
669 alt_sgn *= -1;
670 }
671 }
672 }
673 else // lower-dim boundary case, d + 1 == n
674 {
675 gsMatrix<T,domDim,domDim> metric(d,d);
676 gsVector<T,domDim> param(d);
677 typename gsMatrix<T,domDim,domDim>::FirstMinorMatrixType minor;
678 for (index_t p=0; p!=numPts; ++p)
679 {
680 const gsAsConstMatrix<T,domDim,tarDim> jacT(InOut.values[1].col(p).data(), d, n);
681 metric= (jacT*jacT.transpose());
682 T alt_sgn = sgn;
683 for (int i = 0; i != (domDim!=-1?domDim:d); ++i) //for all components of the normal
684 {
685 metric.firstMinor(dir, i, minor);
686 param(i) = alt_sgn * minor.determinant();
687 alt_sgn *= -1;
688 }
689 InOut.outNormals.col(p)=jacT.transpose()*param/metric.determinant();
690 //InOut.outNormals.col(p)=(jacT.transpose()*param).normalized()*jacT.col(!dir).norm();
691 }
692 }
693
694 }
695
696 // Measure
697 if (InOut.flags & NEED_MEASURE)
698 {
699 InOut.measures.resize(1,numPts);
700 if (InOut.side==boundary::none) // If in the domain's interior
701 {
702 for (index_t p = 0; p < numPts; ++p) // for all points
703 {
704 typename gsAsConstMatrix<T,domDim,tarDim>::Tr jac =
705 gsAsConstMatrix<T,domDim,tarDim>(InOut.values[1].col(p).data(),d, n).transpose();
706 if ( tarDim!=-1 ? tarDim == domDim : n==d )
707 InOut.measures(0,p) = math::abs(jac.determinant());
708 else //unequal dimensions
709 InOut.measures(0,p) = math::sqrt( ( jac.transpose()*jac )
710 .determinant() );
711 }
712 }
713 else // If on boundary
714 {
715 GISMO_ASSERT(d==2, "Only works for boundary curves..");
716 const int dir = InOut.side.direction();
717 typename gsMatrix<T,domDim,tarDim>::ColMinorMatrixType minor;
718 InOut.measures.resize(1, numPts);
719 for (index_t p = 0; p != numPts; ++p) // for all points
720 {
721 const gsAsConstMatrix<T,domDim,tarDim> jacT(InOut.values[1].col(p).data(), d, n);
722 InOut.measures.at(p) = jacT.row(!dir).norm();
723 }
724 //InOut.measures = InOut.outNormals.colwise().norm(); // problematic on 3d curve boundary
725 }
726 }
727
728 if (InOut.flags & NEED_GRAD_TRANSFORM)
729 {
730 // domDim<=tarDim makes sense
731
732 InOut.jacInvTr.resize(d*n, numPts);
733 for (index_t p=0; p!=numPts; ++p)
734 {
735 const gsAsConstMatrix<T,domDim,tarDim> jacT(InOut.values[1].col(p).data(), d, n);
736
737 if ( tarDim!=-1 ? tarDim == domDim : n==d )
738 gsAsMatrix<T,tarDim,domDim>(InOut.jacInvTr.col(p).data(), n, d)
739 = jacT.cramerInverse();
740 else
741 {
742 gsAsMatrix<T,tarDim,domDim>(InOut.jacInvTr.col(p).data(), n, d)
743 = jacT.transpose()*(jacT*jacT.transpose()).cramerInverse();
744 }
745 }
746 }
747
748 // Normal vector of hypersurface
749 if ( (InOut.flags & NEED_NORMAL) && (tarDim!=-1 ? tarDim == domDim+1 : n==d+1) )
750 {
751 typename gsMatrix<T,domDim,tarDim>::ColMinorMatrixType minor;
752 InOut.normals.resize(n, numPts);
753
754 for (index_t p = 0; p != numPts; ++p) // for all points
755 {
756 const gsAsConstMatrix<T,domDim,tarDim> jacT(InOut.values[1].col(p).data(), d, n);
757 T alt_sgn(1);
758 for (int i = 0; i != tarDim; ++i) //for all components of the normal
759 {
760 jacT.colMinor(i, minor);
761 InOut.normals(i,p) = alt_sgn * minor.determinant();
762 alt_sgn = -alt_sgn;
763 }
764 }
765 //gsDebugVar(InOut.normals);
766 }
767
768 // Second Fundamantan form of surface
769 if (InOut.flags & NEED_2ND_FFORM)
770 {
771 // gsDebugVar(src);
772 // gsDebugVar(InOut.normals);
773 // gsDebugVar(n);
774 // gsDebugVar(d+1);
775 //domDim=2, tarDim=3
776 InOut.fundForms.resize(d*d, numPts);
777 const index_t sz = d*(d+1)/2;
778 for (index_t p=0; p!=numPts; ++p)
779 {
780 const gsAsConstMatrix<T,-1,tarDim> ddT(InOut.values[2].col(p).data(), sz, n);
781 const T nrm = InOut.normals.col(p).norm();
782 if (0!=nrm)
783 {
784 InOut.fundForms(0,p) = ddT.row(0).dot(InOut.normals.col(p)) / nrm;
785 InOut.fundForms(3,p) = ddT.row(1).dot(InOut.normals.col(p)) / nrm;
786 InOut.fundForms(1,p) = InOut.fundForms(2,p) =
787 ddT.row(2).dot(InOut.normals.col(p)) / nrm;
788 }
789 }
790 }
791
792
793
794 /*
795 // Curvature of isoparametric curve
796 if ( InOut.flags & NEED_CURVATURE)
797 {
798 //domDim=2, tarDim=3
799 const int dir = InOut.side.direction();
800 const index_t sz = domDim*(domDim+1)/2;
801 InOut.curvature.resize(1,numPts);
802 for (index_t p=0; p!=numPts; ++p)
803 {
804 const gsAsConstMatrix<T,domDim,tarDim> jacT(InOut.values[1].col(p).data(), d, n);
805 const gsAsConstMatrix<T,-1,tarDim> ddT(InOut.values[2].col(p).data(), sz, n);
806 const T nrm = ddT.row(dir).norm(); // (d^2/dir^2)G
807 if (0!=nrm)
808 InOut.curvature.at(p) = jacT.row(dir).cross(ddT.row(dir)).norm() / (nrm*nrm*nrm);
809 }
810 }
811 */
812}
813
814
815// Computes map data out of this map
816template <class T>
818{
819 // Fill function data
820 if ( InOut.flags & (NEED_GRAD_TRANSFORM|NEED_MEASURE|NEED_NORMAL|NEED_OUTER_NORMAL) ) //NEED_JACOBIAN
821 InOut.flags |= NEED_DERIV;
822 if ( InOut.flags & (NEED_2ND_FFORM) ) //NEED_HESSIAN
823 InOut.flags |= NEED_DERIV | NEED_DERIV2 | NEED_NORMAL;
824
825 this->compute(InOut.points, InOut);
826
827 // Fill extra data
828 std::pair<short_t, short_t> Dim = this->dimensions();
829
830 GISMO_ASSERT(Dim.first<10, "Domain dimension is too big");
831 GISMO_ASSERT(Dim.first<=Dim.second, "Singular map: target dimension is lower then the domain dimension");
832 switch (10 * Dim.second + Dim.first)
833 {
834 // curves
835 case 11: computeAuxiliaryData<T,1,1>(*this, InOut, Dim.first, Dim.second); break;
836 case 21: computeAuxiliaryData<T,1,2>(*this, InOut, Dim.first, Dim.second); break;
837// case 31: computeAuxiliaryData<T,1,3>(*this, InOut, Dim.first, Dim.second); break;
838// case 41: computeAuxiliaryData<T,1,4>(*this, InOut, Dim.first, Dim.second); break;
839 // surfaces
840// case 12: computeAuxiliaryData<T,2,1>(*this, InOut, Dim.first, Dim.second); break;
841 case 22: computeAuxiliaryData<T,2,2>(*this, InOut, Dim.first, Dim.second); break;
842 case 32: computeAuxiliaryData<T,2,3>(*this, InOut, Dim.first, Dim.second); break;
843// case 42: computeAuxiliaryData<T,2,4>(*this, InOut, Dim.first, Dim.second); break;
844// volumes
845// case 13: computeAuxiliaryData<T,3,1>(*this, InOut, Dim.first, Dim.second); break;
846// case 23: computeAuxiliaryData<T,3,2>(*this, InOut, Dim.first, Dim.second); break;
847 case 33: computeAuxiliaryData<T,3,3>(*this, InOut, Dim.first, Dim.second); break;
848// case 43: computeAuxiliaryData<T,3,4>(InOut, Dim.first, Dim.second); break;
849// 4D bulks
850// case 14: computeAuxiliaryData<T,4,1>(*this, InOut, Dim.first, Dim.second); break;
851// case 24: computeAuxiliaryData<T,4,2>(*this, InOut, Dim.first, Dim.second); break;
852// case 34: computeAuxiliaryData<T,4,3>(*this, InOut, Dim.first, Dim.second); break;
853 case 44: computeAuxiliaryData<T,4,4>(*this, InOut, Dim.first, Dim.second); break;
854 default: computeAuxiliaryData<T,-1,-1>(*this, InOut, Dim.first, Dim.second); break;
855 }
856
857}
858
859
860} // namespace gismo
Struct which represents a certain side of a box.
Definition gsBoundary.h:85
bool parameter() const
Returns the parameter value (false=0=start, true=1=end) that corresponds to this side.
Definition gsBoundary.h:128
short_t direction() const
Returns the parametric direction orthogonal to this side.
Definition gsBoundary.h:113
Represents a certain component of a vector-valued function.
Definition gsFuncCoordinate.h:35
A function from a n-dimensional domain to an m-dimensional image.
Definition gsFunction.h:60
virtual void deriv2_into(const gsMatrix< T > &u, gsMatrix< T > &result) const
Evaluate second derivatives of the function at points u into result.
Definition gsFunction.hpp:130
virtual gsMatrix< T > laplacian(const gsMatrix< T > &u) const
Evaluate the Laplacian at points u.
Definition gsFunction.hpp:177
gsFuncCoordinate< T > coord(const index_t c) const
Returns the scalar function giving the i-th coordinate of this function.
Definition gsFunction.hpp:38
void recoverPoints(gsMatrix< T > &xyz, gsMatrix< T > &uv, index_t k, const T accuracy=1e-6) const
Definition gsFunction.hpp:504
virtual void jacobian_into(const gsMatrix< T > &u, gsMatrix< T > &result) const
Computes for each point u a block of result containing the Jacobian matrix.
Definition gsFunction.hpp:53
void div_into(const gsMatrix< T > &u, gsMatrix< T > &result) const
Computes for each point u a block of result containing the divergence matrix.
Definition gsFunction.hpp:65
virtual void computeMap(gsMapData< T > &InOut) const
Computes map function data.
Definition gsFunction.hpp:817
virtual void invertPoints(const gsMatrix< T > &points, gsMatrix< T > &result, const T accuracy=1e-6, const bool useInitialPoint=false) const
Definition gsFunction.hpp:199
virtual void eval_component_into(const gsMatrix< T > &u, const index_t comp, gsMatrix< T > &result) const
Evaluate the function for component comp in the target dimension at points u into result.
Definition gsFunction.hpp:546
int newtonRaphson(const gsVector< T > &value, gsVector< T > &arg, bool withSupport=true, const T accuracy=1e-6, int max_loop=100, T damping_factor=1) const
Definition gsFunction.hpp:443
virtual void deriv_into(const gsMatrix< T > &u, gsMatrix< T > &result) const
Evaluate derivatives of the function at points u into result.
Definition gsFunction.hpp:93
virtual gsMatrix< T > parameterCenter() const
Returns a "central" point inside inside the parameter domain.
Definition gsFunction.h:261
the gsMapData is a cache of pre-computed function (map) values.
Definition gsFuncData.h:349
gsMatrix< T > points
input (parametric) points
Definition gsFuncData.h:372
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
void blockTransposeInPlace(const index_t colBlock)
Transposes in place the matrix block-wise. The matrix is.
Definition gsMatrix.h:468
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition gsVector.h:37
#define short_t
Definition gsConfig.h:35
#define index_t
Definition gsConfig.h:32
#define GISMO_NO_IMPLEMENTATION
Definition gsDebug.h:129
#define gsWarn
Definition gsDebug.h:50
#define GISMO_UNUSED(x)
Definition gsDebug.h:112
#define GISMO_ENSURE(cond, message)
Definition gsDebug.h:102
#define gsInfo
Definition gsDebug.h:43
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Provides definition of the FuncCoordinate class.
This object is a cache for computed values from an evaluator.
Class defining an adaptor for using a gsFunction in an optimization problem.
Provides declaration of the gradient descent method.
Provides iteration over integer or numeric points in a (hyper-)cube.
Provides declaration of an optimization problem.
This is the main header file that collects wrappers of Eigen for linear algebra.
Matrix< Scalar, Dynamic, Dynamic > cramerInverse() const
Inversion for small matrices using Cramer's Rule.
Definition gsMatrixAddons.h:55
EIGEN_STRONG_INLINE abs_expr< E > abs(const E &u)
Absolute value.
Definition gsExpressions.h:4486
EIGEN_STRONG_INLINE jac_expr< E > jac(const symbol_expr< E > &u)
The Jacobian matrix of a FE variable.
Definition gsExpressions.h:4528
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_HESSIAN
Hessian matrix.
Definition gsForwardDeclarations.h:82
@ NEED_VALUE
Value of the object.
Definition gsForwardDeclarations.h:72
@ NEED_DERIV2
Second derivatives.
Definition gsForwardDeclarations.h:80
@ NEED_DERIV
Gradient of the object.
Definition gsForwardDeclarations.h:73
@ NEED_GRAD_TRANSFORM
Gradient transformation matrix.
Definition gsForwardDeclarations.h:77
@ NEED_NORMAL
Normal vector of the object.
Definition gsForwardDeclarations.h:85
@ NEED_MEASURE
The density of the measure pull back.
Definition gsForwardDeclarations.h:76
@ NEED_OUTER_NORMAL
Outward normal on the boundary.
Definition gsForwardDeclarations.h:86
@ NEED_2ND_FFORM
Second fundamental form.
Definition gsForwardDeclarations.h:87
S give(S &x)
Definition gsMemory.h:266
int sideOrientation(short_t s)
Definition gsBoundary.h:1029
Struct which represents a certain corner of a hyper-cube.
Definition gsBoundary.h:292