DGtal 1.3.0
Loading...
Searching...
No Matches
ATSolver2D.h
1
17#pragma once
18
31#if defined(ATSolver2D_RECURSES)
32#error Recursive header files inclusion detected in ATSolver2D.h
33#else // defined(ATSolver2D_RECURSES)
35#define ATSolver2D_RECURSES
36
37#if !defined ATSolver2D_h
39#define ATSolver2D_h
40
42// Inclusions
43#include <iostream>
44#include <sstream>
45#include <tuple>
46#include "DGtal/base/Common.h"
47#include "DGtal/base/ConstAlias.h"
48#include "DGtal/math/linalg/EigenSupport.h"
49#include "DGtal/dec/DiscreteExteriorCalculus.h"
50#include "DGtal/dec/DiscreteExteriorCalculusSolver.h"
51#include "DGtal/dec/DECHelpers.h"
53
54namespace DGtal
55{
56
58 // template class ATSolver2D
88 template < typename TKSpace,
89 typename TLinearAlgebra = EigenLinearAlgebraBackend >
91 {
92 // ----------------------- Standard services ------------------------------
93 public:
94
95 typedef TKSpace KSpace;
96 typedef TLinearAlgebra LinearAlgebra;
98
100
106 };
107 typedef typename KSpace::Space Space;
110 typedef typename KSpace::SCell SCell;
111 typedef typename KSpace::Cell Cell;
112 typedef typename KSpace::Surfel Surfel;
115 typedef typename KSpace::template SurfelMap<double>::Type SmallestEpsilonMap;
116 typedef typename Calculus::Index Index;
130 typedef typename KSpace::template SurfelMap<Index>::Type Surfel2IndexMap;
131
132 // SparseLU is so much faster than SparseQR
133 // SimplicialLLT is much faster than SparseLU
134 // SimplicialLDLT is as fast as SimplicialLLT but more robust
135 // typedef EigenLinearAlgebraBackend::SolverSparseQR LinearAlgebraSolver;
136 // typedef EigenLinearAlgebraBackend::SolverSparseLU LinearAlgebraSolver;
137 // typedef EigenLinearAlgebraBackend::SolverSimplicialLLT LinearAlgebraSolver;
141
142 protected:
160 std::vector<PrimalForm2> g2;
162 std::vector<PrimalForm2> alpha_g2;
164 std::vector<PrimalForm2> u2;
172
173 public:
174 // The map Surfel -> Index that gives the index of the surfel in 2-forms.
181 double alpha;
184 double lambda;
187 double epsilon;
192
193 // ----------------------- Standard services ------------------------------
196
202 ATSolver2D( ConstAlias< Calculus > aCalculus, int aVerbose = 0 )
203 : ptrCalculus( aCalculus ),
207 g2(), alpha_g2(), u2(), v0( *ptrCalculus ), former_v0( *ptrCalculus ),
208 l_1_over_4e( *ptrCalculus ), verbose( aVerbose )
209 {
210 if ( verbose >= 2 )
211 trace.info() << "[ATSolver::ATSolver] " << *ptrCalculus << std::endl;
213 const auto size2 = ptrCalculus->kFormLength( 2, PRIMAL );
214 for ( Index index = 0; index < size2; ++index) {
215 const auto& calculus_cell = ptrCalculus->getSCell( 2, PRIMAL, index );
216 surfel2idx[ calculus_cell ] = index;
217 }
218 }
219
223 ATSolver2D() = delete;
224
228 ~ATSolver2D() = default;
229
234 ATSolver2D ( const ATSolver2D & other ) = default;
235
240 ATSolver2D ( ATSolver2D && other ) = default;
241
247 ATSolver2D & operator= ( const ATSolver2D & other ) = default;
248
254 ATSolver2D & operator= ( ATSolver2D && other ) = default;
255
258 Index size( const int order ) const
259 {
260 return ptrCalculus->kFormLength(order, PRIMAL);
261 }
262
264
265
266 // ----------------------- Initialization services ------------------------------
267 public:
270
286 template <typename VectorFieldInput, typename SurfelRangeConstIterator>
287 void
288 initInputVectorFieldU2( const VectorFieldInput& input,
289 SurfelRangeConstIterator itB, SurfelRangeConstIterator itE,
290 bool normalize = false )
291 {
292 if ( verbose >= 1 )
293 trace.beginBlock( "[ATSolver2D::initInputVectorFieldU2] Initializing input data" );
294 ASSERT( ! input.empty() );
295 const Dimension N = input[ 0 ].size();
296 if ( verbose >= 2 ) trace.info() << "input g as " << N << " 2-forms." << std::endl;
297 g2 = std::vector<PrimalForm2>( N, PrimalForm2( *ptrCalculus ) );
298 alpha_g2 = std::vector<PrimalForm2>( N, PrimalForm2( *ptrCalculus ) );
299 Index i = 0;
300 for ( auto it = itB; it != itE; ++it, ++i )
301 {
302 Index idx = surfel2idx[ *it ];
303 for ( Dimension k = 0; k < N; ++k )
304 g2[ k ].myContainer( idx ) = input[ i ][ k ];
305 }
306 // u = g at the beginning
307 if ( verbose >= 2 )
308 trace.info() << "Unknown u[:] = g[:] at beginning." << std::endl;
309 u2 = g2;
310 // v = 1 at the beginning
311 if ( verbose >= 2 ) trace.info() << "Unknown v = 1" << std::endl;
313 if ( verbose >= 1 ) trace.endBlock();
314 normalize_u2 = normalize;
315 }
316
328 template <typename ScalarFieldInput, typename SurfelRangeConstIterator>
329 void
330 initInputScalarFieldU2( const ScalarFieldInput& input,
331 SurfelRangeConstIterator itB, SurfelRangeConstIterator itE )
332 {
333 if ( verbose >= 1 )
334 trace.beginBlock( "[ATSolver2D::initInputVectorFieldU2] Initializing input data" );
335 ASSERT( ! input.empty() );
336 if ( verbose >= 2 ) trace.info() << "input g as one 2-form." << std::endl;
337 g2 = std::vector<PrimalForm2>( 1, PrimalForm2( *ptrCalculus ) );
338 alpha_g2 = std::vector<PrimalForm2>( 1, PrimalForm2( *ptrCalculus ) );
339 Index i = 0;
340 for ( auto it = itB; it != itE; ++it, ++i )
341 {
342 Index idx = surfel2idx[ *it ];
343 g2[ 0 ].myContainer( idx ) = input[ i ];
344 }
345 // u = g at the beginning
346 if ( verbose >= 2 )
347 trace.info() << "Unknown u[:] = g[:] at beginning." << std::endl;
348 u2 = g2;
349 // v = 1 at the beginning
350 if ( verbose >= 2 ) trace.info() << "Unknown v = 1" << std::endl;
352 if ( verbose >= 1 ) trace.endBlock();
353 normalize_u2 = false;
354 }
355
356
369 template <typename ScalarVector>
370 Index
371 initInputVectorFieldU2( const std::map<Surfel,ScalarVector>& input,
372 bool normalize = false )
373 {
374 if ( verbose >= 1 ) trace.beginBlock( "[ATSolver2D::initVectorInput] Initializing input data" );
375 if ( verbose >= 2 ) trace.info() << "discontinuity 0-form v = 1." << std::endl;
376 const Dimension N = ScalarVector().size();
377 if ( verbose >= 2 ) trace.info() << "input g as " << N << " 2-forms." << std::endl;
378 g2 = std::vector<PrimalForm2>( N, PrimalForm2( *ptrCalculus ) );
379 alpha_g2 = std::vector<PrimalForm2>( N, PrimalForm2( *ptrCalculus ) );
380 const ScalarVector zero;
381 Index nbok = 0;
382 for ( Index index = 0; index < size(2); index++)
383 {
384 const SCell& cell = g2[ 0 ].getSCell( index );
385 const auto it = input.find( cell );
386 const auto n = ( it != input.end() ) ? it->second : zero;
387 nbok += ( it != input.end() ) ? 1 : 0;
388 for ( Dimension k = 0; k < N; ++k )
389 g2[ k ].myContainer( index ) = n[ k ];
390 }
391 // u = g at the beginning
392 if ( verbose >= 2 )
393 trace.info() << "Unknown u[:] = g[:] at beginning." << std::endl;
394 u2 = g2;
395 // v = 1 at the beginning
396 if ( verbose >= 2 ) trace.info() << "Unknown v = 1" << std::endl;
398 if ( verbose >= 1 ) trace.endBlock();
399 normalize_u2 = normalize;
400 return nbok;
401 }
402
409 template <typename Scalar>
410 Index
411 initInputScalarFieldU2( const std::map<Surfel,Scalar>& input )
412 {
413 if ( verbose >= 1 ) trace.beginBlock( "[ATSolver2D::initScalarInput] Initializing input data" );
414 if ( verbose >= 2 ) trace.info() << "discontinuity 0-form v = 1." << std::endl;
416 if ( verbose >= 2 ) trace.info() << "input g as one 2-form." << std::endl;
417 g2 = std::vector<PrimalForm2>( 1, PrimalForm2( *ptrCalculus ) );
418 alpha_g2 = std::vector<PrimalForm2>( 1, PrimalForm2( *ptrCalculus ) );
419 const Scalar zero;
420 Index nbok = 0;
421 for ( Index index = 0; index < size(2); index++)
422 {
423 const SCell& cell = g2[ 0 ].getSCell( index );
424 const auto it = input.find( cell );
425 const auto n = ( it != input.end() ) ? *it : zero;
426 nbok += ( it != input.end() ) ? 1 : 0;
427 g2[ 0 ].myContainer( index ) = n;
428 }
429 // u = g at the beginning
430 if ( verbose >= 2 ) trace.info() << "Unknown u[:] = g[:] at beginning." << std::endl;
431 u2 = g2;
432 // v = 1 at the beginning
433 if ( verbose >= 2 ) trace.info() << "Unknown v = 1" << std::endl;
435 if ( verbose >= 1 ) trace.endBlock();
436 normalize_u2 = false;
437 return nbok;
438 }
439
444 void setUp( double a, double l )
445 {
446 const Dimension N = g2.size();
447 alpha = a;
448 lambda = l;
449 alpha_Id2 = alpha * ptrCalculus->template identity<2, PRIMAL>();
450 for ( Dimension k = 0; k < N; ++k )
451 alpha_g2[ k ] = alpha * g2[ k ];
452 }
453
463 void setUp( double a, double l, const std::map<Surfel,Scalar>& weights )
464 {
465 const Dimension N = g2.size();
466 alpha = a;
467 lambda = l;
468 PrimalForm2 w_form( *ptrCalculus );
469 if ( verbose >= 2 )
470 trace.info() << "Using variable weights for fitting (alpha term)" << std::endl;
471 for ( Dimension k = 0; k < N; ++k )
472 alpha_g2[ k ] = alpha * g2[ k ];
473 for ( Index index = 0; index < size( 2 ); index++)
474 {
475 const SCell& cell = g2[ 0 ].getSCell( index );
476 const Scalar& w = weights[ cell ];
477 w_form.myContainer( index ) = w;
478 for ( Dimension k = 0; k < N; ++k )
479 alpha_g2[ k ].myContainer( index ) *= w;
480 }
481 alpha_Id2 = alpha * diagonal( w_form );
482 }
483
498 template <typename AlphaWeights, typename SurfelRangeConstIterator>
499 void setUp( double a, double l,
500 const AlphaWeights& weights,
501 SurfelRangeConstIterator itB, SurfelRangeConstIterator itE )
502 {
503 const Dimension N = g2.size();
504 alpha = a;
505 lambda = l;
506 PrimalForm2 w_form( *ptrCalculus );
507 if ( verbose >= 2 )
508 trace.info() << "Using variable weights for fitting (alpha term)" << std::endl;
509 for ( Dimension k = 0; k < N; ++k )
510 alpha_g2[ k ] = alpha * g2[ k ];
511 Index i = 0;
512 for ( auto it = itB; it != itE; ++it, ++i )
513 {
514 const Index idx = surfel2idx[ *it ];
515 const Scalar w = weights[ i ];
516 w_form.myContainer( idx ) = w;
517 for ( Dimension k = 0; k < N; ++k )
518 alpha_g2[ k ].myContainer( idx ) *= w;
519 }
520 alpha_Id2 = alpha * diagonal( w_form );
521 }
522
525 void setEpsilon( double e )
526 {
527 epsilon = e;
529 l_1_over_4e_Id0 = (lambda/4./epsilon)*ptrCalculus->template identity<0, PRIMAL>();
530 }
531
533
534 // ----------------------- Optimization services ------------------------------
535 public:
538
547 {
548 bool solve_ok = true;
549 if ( verbose >= 1 ) trace.beginBlock("Solving for u as a 2-form");
550 PrimalForm1 v1_squared = M01*v0;
551 v1_squared.myContainer.array() = v1_squared.myContainer.array().square();
552 const PrimalIdentity2 ope_u2 = alpha_Id2
554
555 if ( verbose >= 2 ) trace.info() << "Prefactoring matrix U associated to u" << std::endl;
556 SolverU2 solver_u2;
557 solver_u2.compute( ope_u2 );
558 for ( Dimension d = 0; d < u2.size(); ++d )
559 {
560 if ( verbose >= 2 ) trace.info() << "Solving U u[" << d << "] = a g[" << d << "]" << std::endl;
561 u2[ d ] = solver_u2.solve( alpha_g2[ d ] );
562 if ( verbose >= 2 ) trace.info() << " => " << ( solver_u2.isValid() ? "OK" : "ERROR" )
563 << " " << solver_u2.myLinearAlgebraSolver.info() << std::endl;
564 solve_ok = solve_ok && solver_u2.isValid();
565 }
566 if ( normalize_u2 ) normalizeU2();
567 if ( verbose >= 1 ) trace.endBlock();
568 if ( verbose >= 1 ) trace.beginBlock("Solving for v");
569 former_v0 = v0;
570 PrimalForm1 squared_norm_d_u2 = PrimalForm1::zeros(*ptrCalculus);
571 for ( Dimension d = 0; d < u2.size(); ++d )
572 squared_norm_d_u2.myContainer.array() += (primal_AD2 * u2[ d ] ).myContainer.array().square();
573 trace.info() << "build metric u2" << std::endl;
574 const PrimalIdentity0 ope_v0 = l_1_over_4e_Id0
576 + M01.transpose() * dec_helper::diagonal( squared_norm_d_u2 ) * M01;
577
578 if ( verbose >= 2 ) trace.info() << "Prefactoring matrix V associated to v" << std::endl;
579 SolverV0 solver_v0;
580 solver_v0.compute( ope_v0 );
581 if ( verbose >= 2 ) trace.info() << "Solving V v = l/4e * 1" << std::endl;
582 v0 = solver_v0.solve( l_1_over_4e );
583 if ( verbose >= 2 ) trace.info() << " => " << ( solver_v0.isValid() ? "OK" : "ERROR" )
584 << " " << solver_v0.myLinearAlgebraSolver.info() << std::endl;
585 solve_ok = solve_ok && solver_v0.isValid();
586 if ( verbose >= 1 ) trace.endBlock();
587 return solve_ok;
588 }
589
605 bool solveForEpsilon( double eps,
606 double n_oo_max = 1e-4,
607 unsigned int iter_max = 10 )
608 {
609 bool ok = true;
610 if ( verbose >= 1 ) {
611 std::ostringstream sstr;
612 sstr << "******* Solving AT for epsilon = " << eps << " **********";
613 trace.beginBlock( sstr.str() );
614 }
615 setEpsilon( eps );
616 for ( unsigned int i = 0; i < iter_max; ++i )
617 {
618 if ( verbose >= 1 )
619 trace.info() << "---------- Iteration "
620 << i << "/" << iter_max << " ---------------" << std::endl;
622 auto norms_v = checkV0();
623 auto diffs_v = diffV0();
624 if ( verbose >= 1 ) {
625 trace.info() << "Variation |v^k+1 - v^k|_oo = " << std::get<0>( diffs_v )
626 << std::endl;
627 if ( verbose >= 2 ) {
628 trace.info() << "Variation |v^k+1 - v^k|_2 = " << std::get<1>( diffs_v )
629 << std::endl;
630 trace.info() << "Variation |v^k+1 - v^k|_1 = " << std::get<2>( diffs_v )
631 << std::endl;
632 }
633 }
634 if ( std::get<0>( diffs_v ) < 1e-4 ) break;
635 }
636 if ( verbose >= 1 ) trace.endBlock();
637 return ok;
638 }
639
656 bool solveGammaConvergence( double eps1 = 2.0,
657 double eps2 = 0.25,
658 double epsr = 2.0,
659 bool compute_smallest_epsilon_map = false,
660 double n_oo_max = 1e-4,
661 unsigned int iter_max = 10 )
662 {
663 bool ok = true;
664 if ( epsr <= 1.0 ) epsr = 2.0;
665 if ( verbose >= 1 )
666 trace.beginBlock( "#### Solve AT by Gamma-convergence ##########" );
667 if ( compute_smallest_epsilon_map ) smallest_epsilon_map.clear();
668 for ( double eps = eps1; eps >= eps2; eps /= epsr )
669 {
670 solveForEpsilon( eps, n_oo_max, iter_max );
671 if ( compute_smallest_epsilon_map )
673 }
674 if ( verbose >= 1 )
675 trace.endBlock();
676 return ok;
677 }
678
684 {
685 for ( Index index = 0; index < size( 2 ); index++)
686 {
687 double n2 = 0.0;
688 for ( unsigned int d = 0; d < u2.size(); ++d )
689 n2 += u2[ d ].myContainer( index ) * u2[ d ].myContainer( index );
690 double norm = sqrt( n2 );
691 if (norm == 0.0) continue;
692 for ( unsigned int d = 0; d < u2.size(); ++d )
693 u2[ d ].myContainer( index ) /= norm;
694 }
695 }
696
701 std::tuple<double,double,double> diffV0() const
702 {
703 PrimalForm0 delta = v0 - former_v0;
704 delta.myContainer = delta.myContainer.cwiseAbs();
705 const double n_oo = delta.myContainer.maxCoeff();
706 const double n_2 = std::sqrt(delta.myContainer.squaredNorm()/delta.myContainer.size());
707 const double n_1 = delta.myContainer.mean();
708 return std::make_tuple( n_oo, n_2, n_1 );
709 }
710
712
713
714 // ----------------------- Access services ------------------------------
715 public:
718
722 std::tuple<double,double,double> checkV0() const
723 {
724 const double m1 = v0.myContainer.minCoeff();
725 const double m2 = v0.myContainer.maxCoeff();
726 const double ma = v0.myContainer.mean();
727 if ( verbose >= 1 )
728 trace.info() << "0-form v (should be in [0,1]): min=" << m1 << " avg=" << ma << " max=" << m2 << std::endl;
729 return std::make_tuple( m1, m2, ma );
730 }
731
732
735 {
736 return v0;
737 }
738
741 {
742 return M01*v0;
743 }
744
747 {
748 return M12*M01*v0;
749 }
750
754 {
755 return u2[ k ];
756 }
757
769 template <typename VectorFieldOutput, typename SurfelRangeConstIterator>
770 void
771 getOutputVectorFieldU2( VectorFieldOutput& output,
772 SurfelRangeConstIterator itB, SurfelRangeConstIterator itE )
773 {
774 const Dimension N = u2.size();
775 Index i = 0;
776 for ( auto it = itB; it != itE; ++it, ++i )
777 {
778 Index idx = surfel2idx[ *it ];
779 ASSERT( output[ i ].size() >= N );
780 for ( Dimension k = 0; k < N; ++k )
781 output[ i ][ k ] = u2[ k ].myContainer( idx );
782 }
783 }
784
795 template <typename ScalarFieldOutput, typename SurfelRangeConstIterator>
796 void
797 getOutputScalarFieldU2( ScalarFieldOutput& output,
798 SurfelRangeConstIterator itB, SurfelRangeConstIterator itE )
799 {
800 ASSERT( u2.size() == 1 && "[ATSolver2D::getOutputScalarFieldU2] "
801 "You try to output a scalar field from a vector field." );
802 Index i = 0;
803 for ( auto it = itB; it != itE; ++it, ++i )
804 {
805 Index idx = surfel2idx[ *it ];
806 output[ i ] = u2[ 0 ].myContainer( idx );
807 }
808 }
809
821 template <typename ScalarFieldOutput, typename CellRangeConstIterator>
822 void
823 getOutputScalarFieldV0( ScalarFieldOutput& output,
824 CellRangeConstIterator itB, CellRangeConstIterator itE,
826 {
827 const KSpace& K = ptrCalculus->myKSpace;
828 const Dimension k = K.uDim( *itB );
829 ASSERT( k <= 2 );
830 Index i = 0;
831 if ( k == 0 )
832 {
833 for ( auto it = itB; it != itE; ++it, ++i )
834 {
835 const Cell pointel = *it;
836 const Index idx = ptrCalculus->getCellIndex( pointel );
837 output[ i ] = v0.myContainer( idx );
838 }
839 }
840 else if ( k == 1 )
841 {
842 for ( auto it = itB; it != itE; ++it, ++i )
843 {
844 const Cell linel = *it;
845 const Dimension d = * K.uDirs( linel );
846 const Cell p0 = K.uIncident( linel, d, false );
847 const Cell p1 = K.uIncident( linel, d, true );
848 const Index idx0 = ptrCalculus->getCellIndex( p0 );
849 const Index idx1 = ptrCalculus->getCellIndex( p1 );
850 switch (policy) {
851 case CellOutputPolicy::Average: output[ i ] = 0.5 * ( v0.myContainer( idx0 ) + v0.myContainer( idx1 ) );
852 break;
853 case CellOutputPolicy::Minimum: output[ i ] = std::min( v0.myContainer( idx0 ), v0.myContainer( idx1 ) );
854 break;
855 case CellOutputPolicy::Maximum: output[ i ] = std::max( v0.myContainer( idx0 ), v0.myContainer( idx1 ) );
856 break;
857 }
858 }
859 }
860 else if ( k == 2 )
861 {
862 for ( auto it = itB; it != itE; ++it, ++i )
863 {
864 const Cell face = *it;
865 const Dimension d = * K.uDirs( face );
866 const Cell l0 = K.uIncident( face, d, false );
867 const Cell l1 = K.uIncident( face, d, true );
868 const Dimension j = * K.uDirs( l0 );
869 const Cell p00 = K.uIncident( l0, j, false );
870 const Cell p01 = K.uIncident( l0, j, true );
871 const Cell p10 = K.uIncident( l1, j, false );
872 const Cell p11 = K.uIncident( l1, j, true );
873 const Index idx00 = ptrCalculus->getCellIndex( p00 );
874 const Index idx01 = ptrCalculus->getCellIndex( p01 );
875 const Index idx10 = ptrCalculus->getCellIndex( p10 );
876 const Index idx11 = ptrCalculus->getCellIndex( p11 );
877 switch (policy) {
879 output[ i ] = 0.25 * ( v0.myContainer( idx00 ) + v0.myContainer( idx01 )
880 + v0.myContainer( idx10 ) + v0.myContainer( idx11 ) );
881 break;
883 output[ i ] = std::min( std::min( v0.myContainer( idx00 ), v0.myContainer( idx01 ) ),
884 std::min( v0.myContainer( idx10 ), v0.myContainer( idx11 ) ) );
885 break;
887 output[ i ] = std::max( std::max( v0.myContainer( idx00 ), v0.myContainer( idx01 ) ),
888 std::max( v0.myContainer( idx10 ), v0.myContainer( idx11 ) ) );
889 break;
890 }
891 }
892 }
893 }
894
902 void updateSmallestEpsilonMap( const double threshold = .5 )
903 {
904 const KSpace& K = ptrCalculus->myKSpace;
905 for ( const SCell surfel : ptrCalculus->template getIndexedSCells<2, PRIMAL>() )
906 {
907 const Cell face = K.unsigns( surfel );
908 const Dimension k1 = * K.uDirs( face );
909 const Cell l0 = K.uIncident( face, k1, false );
910 const Cell l1 = K.uIncident( face, k1, true );
911 const Dimension k2 = * K.uDirs( l0 );
912 const Cell ll0 = K.uIncident( face, k2, false );
913 const Cell ll1 = K.uIncident( face, k2, true );
914 const Cell p00 = K.uIncident( l0, k2, false );
915 const Cell p01 = K.uIncident( l0, k2, true );
916 const Cell p10 = K.uIncident( l1, k2, false );
917 const Cell p11 = K.uIncident( l1, k2, true );
918
919 std::vector<double> features( 4 );
920 features[ 0 ] = v0.myContainer( ptrCalculus->getCellIndex( p00 ) );
921 features[ 1 ] = v0.myContainer( ptrCalculus->getCellIndex( p01 ) );
922 features[ 2 ] = v0.myContainer( ptrCalculus->getCellIndex( p10 ) );
923 features[ 3 ] = v0.myContainer( ptrCalculus->getCellIndex( p11 ) );
924 std::sort( features.begin(), features.end() );
925
926 if ( features[ 1 ] <= threshold )
927 {
928 auto it = smallest_epsilon_map.find( surfel );
929 if ( it != smallest_epsilon_map.end() )
930 it->second = std::min( epsilon, it->second );
931 else smallest_epsilon_map[ surfel ] = epsilon;
932 }
933 }
934 }
935
937
938
939 // ----------------------- Interface --------------------------------------
940 public:
943
948 void selfDisplay ( std::ostream & out ) const
949 {
950 auto cv = checkV0();
951 out << "[ATSolver2D] v is between min/avg/max:"
952 << std::get<0>(cv) << "/"
953 << std::get<1>(cv) << "/"
954 << std::get<2>(cv) << std::endl;
955 }
956
961 bool isValid() const
962 {
963 return true;
964 }
965
967
968 // ------------------------- Hidden services ------------------------------
969 protected:
970
973
976 {
977 if ( verbose >= 1 ) trace.beginBlock( "[ATSolver2D::initOperators] Solver initialization" );
978 if ( verbose >= 2 ) trace.info() << "derivative of primal 0-forms: primal_D0" << std::endl;
979 primal_D0 = ptrCalculus->template derivative<0,PRIMAL>();
980 if ( verbose >= 2 ) trace.info() << "derivative of primal 1-forms: primal_D1" << std::endl;
981 primal_D1 = ptrCalculus->template derivative<1,PRIMAL>();
982 if ( verbose >= 2 ) trace.info() << "antiderivative of primal 2-forms: primal_AD2" << std::endl;
983 primal_AD2 = ptrCalculus->template antiderivative<2,PRIMAL>();
984 if ( verbose >= 2 ) trace.info() << "vertex to edge average operator: M01" << std::endl;
985 M01 = primal_D0;
986 M01.myContainer = .5 * M01.myContainer.cwiseAbs();
987 if ( verbose >= 2 ) trace.info() << "edge to face average operator: M12" << std::endl;
988 M12 = primal_D1;
989 M12.myContainer = .25 * M12.myContainer.cwiseAbs();
990 if ( verbose >= 1 ) trace.endBlock();
991 }
992
994
995 // ------------------------- Internals ------------------------------------
996 private:
997
998 }; // end of class ATSolver2D
999
1000
1007 template <typename T>
1008 std::ostream&
1009 operator<< ( std::ostream & out, const ATSolver2D<T> & object );
1010
1011} // namespace DGtal
1012
1013
1015// Includes inline functions.
1016
1017// //
1019
1020#endif // !defined ATSolver2D_h
1021
1022#undef ATSolver2D_RECURSES
1023#endif // else defined(ATSolver2D_RECURSES)
Aim: This class solves Ambrosio-Tortorelli functional on a two-dimensional digital space (a 2D grid o...
Definition: ATSolver2D.h:91
bool solveForEpsilon(double eps, double n_oo_max=1e-4, unsigned int iter_max=10)
Definition: ATSolver2D.h:605
Index initInputVectorFieldU2(const std::map< Surfel, ScalarVector > &input, bool normalize=false)
Definition: ATSolver2D.h:371
KSpace::Surfel Surfel
Definition: ATSolver2D.h:112
Calculus::PrimalHodge2 PrimalHodge2
Definition: ATSolver2D.h:129
Index initInputScalarFieldU2(const std::map< Surfel, Scalar > &input)
Definition: ATSolver2D.h:411
void getOutputScalarFieldU2(ScalarFieldOutput &output, SurfelRangeConstIterator itB, SurfelRangeConstIterator itE)
Definition: ATSolver2D.h:797
KSpace::Space Space
Definition: ATSolver2D.h:107
void setUp(double a, double l, const AlphaWeights &weights, SurfelRangeConstIterator itB, SurfelRangeConstIterator itE)
Definition: ATSolver2D.h:499
void getOutputScalarFieldV0(ScalarFieldOutput &output, CellRangeConstIterator itB, CellRangeConstIterator itE, CellOutputPolicy policy=CellOutputPolicy::Average)
Definition: ATSolver2D.h:823
Calculus::PrimalDerivative0 PrimalDerivative0
Definition: ATSolver2D.h:123
static const Dimension dimension
Definition: ATSolver2D.h:99
Calculus::PrimalHodge0 PrimalHodge0
Definition: ATSolver2D.h:127
bool solveOneAlternateStep()
Definition: ATSolver2D.h:546
PrimalForm2 getU2(Dimension k) const
Definition: ATSolver2D.h:753
void initInputScalarFieldU2(const ScalarFieldInput &input, SurfelRangeConstIterator itB, SurfelRangeConstIterator itE)
Definition: ATSolver2D.h:330
std::vector< PrimalForm2 > alpha_g2
The alpha-weighted N-array of input primal 2-forms g.
Definition: ATSolver2D.h:162
std::vector< PrimalForm2 > u2
The N-array of regularized primal 2-forms u.
Definition: ATSolver2D.h:164
void setUp(double a, double l)
Definition: ATSolver2D.h:444
PrimalIdentity2 alpha_Id2
The alpha-weighted identity operator for primal 2-forms (stored for performance)
Definition: ATSolver2D.h:156
Calculus::PrimalIdentity1 PrimalIdentity1
Definition: ATSolver2D.h:121
ATSolver2D(ConstAlias< Calculus > aCalculus, int aVerbose=0)
Definition: ATSolver2D.h:202
HyperRectDomain< Space > Domain
Definition: ATSolver2D.h:113
Calculus::PrimalForm0 PrimalForm0
Definition: ATSolver2D.h:117
int verbose
Tells the verbose level.
Definition: ATSolver2D.h:191
void updateSmallestEpsilonMap(const double threshold=.5)
Definition: ATSolver2D.h:902
RealVector::Component Scalar
Definition: ATSolver2D.h:109
KSpace::SCell SCell
Definition: ATSolver2D.h:110
Calculus::PrimalAntiderivative1 PrimalAntiderivative1
Definition: ATSolver2D.h:125
EigenLinearAlgebraBackend::SolverSimplicialLDLT LinearAlgebraSolver
Definition: ATSolver2D.h:138
TLinearAlgebra LinearAlgebra
Definition: ATSolver2D.h:96
void setEpsilon(double e)
Definition: ATSolver2D.h:525
void initInputVectorFieldU2(const VectorFieldInput &input, SurfelRangeConstIterator itB, SurfelRangeConstIterator itE, bool normalize=false)
Definition: ATSolver2D.h:288
PrimalDerivative1 M12
The primal edge to face average operator.
Definition: ATSolver2D.h:152
SmallestEpsilonMap smallest_epsilon_map
Definition: ATSolver2D.h:178
Calculus::PrimalForm1 PrimalForm1
Definition: ATSolver2D.h:118
std::tuple< double, double, double > diffV0() const
Definition: ATSolver2D.h:701
PrimalForm0 l_1_over_4e
The primal 0-form lambda/(4epsilon) (stored for performance)
Definition: ATSolver2D.h:171
PrimalForm0 getV0() const
Definition: ATSolver2D.h:734
PrimalAntiderivative2 primal_AD2
The antiderivative of primal 2-forms.
Definition: ATSolver2D.h:154
Index size(const int order) const
Definition: ATSolver2D.h:258
Calculus::PrimalIdentity2 PrimalIdentity2
Definition: ATSolver2D.h:122
ATSolver2D & operator=(const ATSolver2D &other)=default
PrimalForm1 getV1() const
Definition: ATSolver2D.h:740
Calculus::PrimalDerivative1 PrimalDerivative1
Definition: ATSolver2D.h:124
PrimalForm0 v0
Definition: ATSolver2D.h:167
DiscreteExteriorCalculus< 2, dimension, LinearAlgebra > Calculus
Definition: ATSolver2D.h:114
void initOperators()
Initializes the operators.
Definition: ATSolver2D.h:975
void setUp(double a, double l, const std::map< Surfel, Scalar > &weights)
Definition: ATSolver2D.h:463
Calculus::PrimalAntiderivative2 PrimalAntiderivative2
Definition: ATSolver2D.h:126
ATSolver2D(ATSolver2D &&other)=default
KSpace::template SurfelMap< double >::Type SmallestEpsilonMap
Definition: ATSolver2D.h:115
Surfel2IndexMap surfel2idx
Definition: ATSolver2D.h:175
bool isValid() const
Definition: ATSolver2D.h:961
Calculus::PrimalHodge1 PrimalHodge1
Definition: ATSolver2D.h:128
Space::RealVector RealVector
Definition: ATSolver2D.h:108
KSpace::template SurfelMap< Index >::Type Surfel2IndexMap
Definition: ATSolver2D.h:130
Calculus::PrimalIdentity0 PrimalIdentity0
Definition: ATSolver2D.h:120
bool solveGammaConvergence(double eps1=2.0, double eps2=0.25, double epsr=2.0, bool compute_smallest_epsilon_map=false, double n_oo_max=1e-4, unsigned int iter_max=10)
Definition: ATSolver2D.h:656
Calculus::PrimalForm2 PrimalForm2
Definition: ATSolver2D.h:119
PrimalForm2 getV2() const
Definition: ATSolver2D.h:746
PrimalDerivative1 primal_D1
the derivative operator for primal 1-forms
Definition: ATSolver2D.h:148
DiscreteExteriorCalculusSolver< Calculus, LinearAlgebraSolver, 0, PRIMAL, 0, PRIMAL > SolverV0
Definition: ATSolver2D.h:140
PrimalIdentity0 l_1_over_4e_Id0
The 1/(4epsilon)-weighted identity operator for primal 0-forms (stored for performance)
Definition: ATSolver2D.h:158
ATSolver2D< KSpace, LinearAlgebra > Self
Definition: ATSolver2D.h:97
void selfDisplay(std::ostream &out) const
Definition: ATSolver2D.h:948
bool normalize_u2
Indicates whether to normalize U (unit norm) at each iteration or not.
Definition: ATSolver2D.h:189
Calculus::Index Index
Definition: ATSolver2D.h:116
PrimalForm0 former_v0
The primal 0-form v at the previous iteration.
Definition: ATSolver2D.h:169
std::tuple< double, double, double > checkV0() const
Definition: ATSolver2D.h:722
KSpace::Cell Cell
Definition: ATSolver2D.h:111
DiscreteExteriorCalculusSolver< Calculus, LinearAlgebraSolver, 2, PRIMAL, 2, PRIMAL > SolverU2
Definition: ATSolver2D.h:139
std::vector< PrimalForm2 > g2
The N-array of input primal 2-forms g.
Definition: ATSolver2D.h:160
~ATSolver2D()=default
void getOutputVectorFieldU2(VectorFieldOutput &output, SurfelRangeConstIterator itB, SurfelRangeConstIterator itE)
Definition: ATSolver2D.h:771
PrimalDerivative0 primal_D0
the derivative operator for primal 0-forms
Definition: ATSolver2D.h:146
@ Maximum
compute maximum value at cell vertices
Definition: ATSolver2D.h:105
@ Average
compute average values at cell vertices
Definition: ATSolver2D.h:103
@ Minimum
compute minimum value at cell vertices,
Definition: ATSolver2D.h:104
CountedConstPtrOrConstPtr< Calculus > ptrCalculus
A smart (or not) pointer to a calculus object.
Definition: ATSolver2D.h:144
PrimalDerivative0 M01
The primal vertex to edge average operator.
Definition: ATSolver2D.h:150
ATSolver2D(const ATSolver2D &other)=default
Aim: This class encapsulates its parameter class so that to indicate to the user that the object/poin...
Definition: ConstAlias.h:187
Aim: Smart or simple const pointer on T. It can be a smart pointer based on reference counts or a sim...
Aim: This wraps a linear algebra solver around a discrete exterior calculus.
SolutionKForm solve(const InputKForm &input_kform) const
DiscreteExteriorCalculusSolver & compute(const Operator &linear_operator)
Aim: DiscreteExteriorCalculus represents a calculus in the dec package. This is the main structure in...
LinearAlgebraBackend::DenseVector::Index Index
Aim: Parallelepidec region of a digital space, model of a 'CDomain'.
Aim: KForm represents discrete kforms in the dec package.
Definition: KForm.h:66
Container myContainer
Definition: KForm.h:131
static KForm< TCalculus, order, duality > zeros(ConstAlias< Calculus > calculus)
static KForm< TCalculus, order, duality > ones(ConstAlias< Calculus > calculus)
static const constexpr Dimension dimension
Aim: LinearOperator represents discrete linear operator between discrete kforms in the DEC package.
TransposedLinearOperator transpose() const
Aim: Implements basic operations that will be used in Point and Vector classes.
Definition: PointVector.h:593
TEuclideanRing Component
Type for Vector elements.
Definition: PointVector.h:614
void beginBlock(const std::string &keyword="")
std::ostream & info()
double endBlock()
SMesh::Index Index
DGtal::LinearOperator< Calculus, dim, duality, dim, duality > diagonal(const DGtal::KForm< Calculus, dim, duality > &kform)
Definition: DECHelpers.h:60
DGtal is the top-level namespace which contains all DGtal functions and types.
std::ostream & operator<<(std::ostream &out, const ClosedIntegerHalfPlane< TSpace > &object)
DGtal::uint32_t Dimension
Definition: Common.h:137
Trace trace
Definition: Common.h:154
@ PRIMAL
Definition: Duality.h:61
Eigen::SimplicialLDLT< SparseMatrix > SolverSimplicialLDLT
Definition: EigenSupport.h:107
Represents a signed cell in a cellular grid space by its Khalimsky coordinates and a boolean value.
KSpace K