LCOV - code coverage report
Current view: top level - ugbase/lib_algebra/operator/preconditioner - ilut.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 174 0
Test Date: 2025-09-21 23:31:46 Functions: 0.0 % 66 0

            Line data    Source code
       1              : 
       2              : #ifndef __H__UG__LIB_DISC__OPERATOR__LINEAR_OPERATOR__ILUT__
       3              : #define __H__UG__LIB_DISC__OPERATOR__LINEAR_OPERATOR__ILUT__
       4              : 
       5              : #include "common/util/smart_pointer.h"
       6              : #include "lib_algebra/operator/interface/preconditioner.h"
       7              : #ifdef UG_PARALLEL
       8              :         #include "lib_algebra/parallelization/parallelization.h"
       9              : #endif
      10              : #include "common/progress.h"
      11              : #include "common/util/ostream_util.h"
      12              : #include "common/profiler/profiler.h"
      13              : 
      14              : #include "lib_algebra/algebra_common/vector_util.h"
      15              : 
      16              : #include "lib_algebra/ordering_strategies/algorithms/IOrderingAlgorithm.h"
      17              : #include "lib_algebra/ordering_strategies/algorithms/native_cuthill_mckee.h" // for backward compatibility
      18              : 
      19              : #include "lib_algebra/algebra_common/permutation_util.h"
      20              : 
      21              : namespace ug{
      22              : 
      23              : template <typename TAlgebra>
      24              : class ILUTPreconditioner : public IPreconditioner<TAlgebra>
      25              : {
      26              :         public:
      27              :         //      Algebra type
      28              :                 typedef TAlgebra algebra_type;
      29              : 
      30              :         //      Vector type
      31              :                 typedef typename TAlgebra::vector_type vector_type;
      32              :                 typedef typename vector_type::value_type vector_value;
      33              : 
      34              :         //      Matrix type
      35              :                 typedef typename TAlgebra::matrix_type matrix_type;
      36              : 
      37              :                 typedef typename matrix_type::row_iterator matrix_row_iterator;
      38              :                 typedef typename matrix_type::const_row_iterator const_matrix_row_iterator;
      39              :                 typedef typename matrix_type::connection matrix_connection;
      40              : 
      41              :         ///     Ordering type
      42              :                 typedef std::vector<size_t> ordering_container_type;
      43              :                 typedef IOrderingAlgorithm<TAlgebra, ordering_container_type> ordering_algo_type;
      44              : 
      45              :         ///     Matrix Operator type
      46              :                 typedef typename IPreconditioner<TAlgebra>::matrix_operator_type matrix_operator_type;
      47              :                 using IPreconditioner<TAlgebra>::set_debug;
      48              : 
      49              :         protected:
      50              :                 typedef typename matrix_type::value_type block_type;
      51              : 
      52              :                 using IPreconditioner<TAlgebra>::debug_writer;
      53              :                 using IPreconditioner<TAlgebra>::write_debug;
      54              : 
      55              :         private:
      56              :                 typedef IPreconditioner<TAlgebra> base_type;
      57              : 
      58              :         public:
      59              :         ///     Constructor
      60            0 :                 ILUTPreconditioner(double eps=1e-6)
      61            0 :                         : m_eps(eps), m_info(false), m_show_progress(true), m_bSortIsIdentity(false)
      62              :                 {
      63              :                         //default was set true
      64            0 :                         m_spOrderingAlgo = make_sp(new NativeCuthillMcKeeOrdering<TAlgebra, ordering_container_type>());
      65            0 :                 };
      66              : 
      67              :         /// clone constructor
      68            0 :                 ILUTPreconditioner(const ILUTPreconditioner<TAlgebra> &parent)
      69            0 :                         : base_type(parent), m_spOrderingAlgo(parent.m_spOrderingAlgo)
      70              :                 {
      71            0 :                         m_eps = parent.m_eps;
      72            0 :                         set_info(parent.m_info);
      73            0 :                         m_bSortIsIdentity = parent.m_bSortIsIdentity;
      74            0 :                 }
      75              : 
      76              :         ///     Clone
      77            0 :                 virtual SmartPtr<ILinearIterator<vector_type> > clone()
      78              :                 {
      79            0 :                         return make_sp(new ILUTPreconditioner<algebra_type>(*this));
      80              :                 }
      81              : 
      82              : 
      83              :         ///     Destructor
      84            0 :                 virtual ~ILUTPreconditioner()
      85            0 :                 {};
      86              : 
      87              :         ///     returns if parallel solving is supported
      88            0 :                 virtual bool supports_parallel() const {return true;}
      89              : 
      90              :         ///     sets threshold for incomplete LU factorisation (added 01122010ih)
      91            0 :                 void set_threshold(number thresh)
      92              :                 {
      93            0 :                         m_eps = thresh;
      94            0 :                 }
      95              :                 
      96              :         ///     sets storage information output to true or false
      97            0 :                 void set_info(bool info)
      98              :                 {
      99            0 :                         m_info = info;
     100            0 :                 }
     101              :                 
     102              :         ///     set whether the progress meter should be shown
     103              :                 void set_show_progress(bool s)
     104              :                 {
     105            0 :                         m_show_progress = s;
     106              :                 }
     107              : 
     108            0 :                 virtual std::string config_string() const
     109              :                 {
     110            0 :                         std::stringstream ss;
     111            0 :                         ss << "ILUT(threshold = " << m_eps << ", sort = " << (m_spOrderingAlgo.valid()?"true":"false") << ")";
     112            0 :                         if(m_eps == 0.0) ss << " = Sparse LU";
     113            0 :                         return ss.str();
     114            0 :                 }
     115              : 
     116              :         ///     sets an ordering algorithm
     117            0 :                 void set_ordering_algorithm(SmartPtr<ordering_algo_type> ordering_algo){
     118            0 :                         m_spOrderingAlgo = ordering_algo;
     119            0 :                 }
     120              : 
     121              :         /// set cuthill-mckee sort on/off
     122            0 :                 void set_sort(bool b)
     123              :                 {
     124            0 :                         if(b){
     125            0 :                                 m_spOrderingAlgo = make_sp(new NativeCuthillMcKeeOrdering<TAlgebra, ordering_container_type>());
     126              :                         }
     127              :                         else{
     128            0 :                                 m_spOrderingAlgo = SPNULL;
     129              :                         }
     130              : 
     131              :                         UG_LOG("\nILUT: please use 'set_ordering_algorithm(..)' in the future\n");
     132            0 :                 }
     133              : 
     134              : 
     135              :         protected:
     136              :         //      Name of preconditioner
     137            0 :                 virtual const char* name() const {return "ILUT";}
     138              : 
     139              :         protected:
     140            0 :                 virtual bool init(SmartPtr<ILinearOperator<vector_type> > J,
     141              :                                   const vector_type& u)
     142              :                 {
     143              :                 //      cast to matrix based operator
     144            0 :                         SmartPtr<MatrixOperator<matrix_type, vector_type> > pOp =
     145              :                                         J.template cast_dynamic<MatrixOperator<matrix_type, vector_type> >();
     146              : 
     147              :                 //      Check that matrix if of correct type
     148            0 :                         if(pOp.invalid())
     149            0 :                                 UG_THROW(name() << "::init': Passed Operator is "
     150              :                                                 "not based on matrix. This Preconditioner can only "
     151              :                                                 "handle matrix-based operators.");
     152              : 
     153            0 :                         m_u = &u;
     154              : 
     155              :                 //      forward request to matrix based implementation
     156            0 :                         return base_type::init(pOp);
     157              :                 }
     158              : 
     159            0 :                 bool init(SmartPtr<ILinearOperator<vector_type> > L)
     160              :                 {
     161              :                 //      cast to matrix based operator
     162            0 :                         SmartPtr<MatrixOperator<matrix_type, vector_type> > pOp =
     163              :                                         L.template cast_dynamic<MatrixOperator<matrix_type, vector_type> >();
     164              : 
     165              :                 //      Check that matrix if of correct type
     166            0 :                         if(pOp.invalid())
     167            0 :                                 UG_THROW(name() << "::init': Passed Operator is "
     168              :                                                 "not based on matrix. This Preconditioner can only "
     169              :                                                 "handle matrix-based operators.");
     170              : 
     171            0 :                         m_u = NULL;
     172              : 
     173              :                 //      forward request to matrix based implementation
     174            0 :                         return base_type::init(pOp);
     175              :                 }
     176              : 
     177              :                 bool init(SmartPtr<MatrixOperator<matrix_type, vector_type> > Op)
     178              :                 {
     179              :                         m_u = NULL;
     180              : 
     181              :                         return base_type::init(Op);
     182              :                 }
     183              : 
     184              :         //      Preprocess routine
     185            0 :                 virtual bool preprocess(SmartPtr<MatrixOperator<matrix_type, vector_type> > pOp)
     186              :                 {
     187            0 :                         return preprocess_mat(*pOp);
     188              :                 }
     189              : 
     190              :         public:
     191            0 :                 virtual bool preprocess_mat(matrix_type &mat)
     192              :                 {
     193              : #ifdef  UG_PARALLEL
     194              :                         matrix_type m2;
     195              :                         m2 = mat;
     196              : 
     197              :                         MatAddSlaveRowsToMasterRowOverlap0(m2);
     198              : 
     199              :                 //      set zero on slaves
     200              :                         std::vector<IndexLayout::Element> vIndex;
     201              :                         CollectUniqueElements(vIndex,  mat.layouts()->slave());
     202              :                         SetDirichletRow(m2, vIndex);
     203              : 
     204              :                         // Even after this setting of Dirichlet rows, it is possible that there are
     205              :                         // zero rows on a proc because of the distribution:
     206              :                         // For example, if one has a horizontal grid interface between two SHADOW_RIM_COPY
     207              :                         // vertices, but the shadowing element for the hSlave side is vMaster (without being in
     208              :                         // any horizontal interface). Then, as the horizontal interface (on the shadowed level)
     209              :                         // is not part of the algebraic layouts, the hSlave is not converted into a Dirichlet row
     210              :                         // by the previous commands.
     211              :                         // As a first aid, we will simply convert any zero row on the current proc into a
     212              :                         // Dirichlet row.
     213              :                         // TODO: The corresponding rhs vector entry could be non-zero!
     214              :                         // It is definitely not set to zero by change_storage_type(PST_UNIQUE) as the index is not contained
     215              :                         // in the vector layouts either. Still, the defect assembling process might contain a vertex
     216              :                         // loop and assemble something that is not solution-dependent! What do we do then?
     217              :                         size_t nInd = m2.num_rows();
     218              :                         size_t cnt = 0;
     219              :                         for (size_t i = 0; i < nInd; ++i)
     220              :                         {
     221              :                                 if (!m2.num_connections(i))
     222              :                                 {
     223              :                                         m2(i,i) = 1.0;
     224              :                                         ++cnt;
     225              :                                 }
     226              :                         }
     227              : #ifndef NDEBUG
     228              :                         if (cnt) UG_LOG_ALL_PROCS("Converted "<<cnt<<" zero rows into Dirichlet rows.\n");
     229              : #endif
     230              : 
     231              :                         return preprocess_mat2(m2);
     232              : #else
     233            0 :                         return preprocess_mat2(mat);
     234              : #endif
     235              :                 }
     236              : 
     237            0 :                 virtual bool preprocess_mat2(matrix_type &mat)
     238              :                 {
     239              :                         PROFILE_BEGIN_GROUP(ILUT_preprocess, "ilut algebra");
     240              :                         //matrix_type &mat = *pOp;
     241              :                         STATIC_ASSERT(matrix_type::rows_sorted, Matrix_has_to_have_sorted_rows);
     242            0 :                         write_debug(mat, "ILUT_PreprocessIn");
     243              : 
     244              :                         matrix_type* A;
     245            0 :                         matrix_type permA;
     246              : 
     247            0 :                         if(m_spOrderingAlgo.valid()){
     248            0 :                                 if(m_u){
     249            0 :                                         m_spOrderingAlgo->init(&mat, *m_u);
     250              :                                 }
     251              :                                 else{
     252            0 :                                         m_spOrderingAlgo->init(&mat);
     253              :                                 }
     254              :                         }
     255              : 
     256            0 :                         if(m_spOrderingAlgo.valid())
     257              :                         {
     258            0 :                                 m_spOrderingAlgo->compute();
     259            0 :                                 m_ordering = m_spOrderingAlgo->ordering();
     260              : 
     261            0 :                                 m_bSortIsIdentity = GetInversePermutation(m_ordering, m_old_ordering);
     262              : 
     263            0 :                                 if(!m_bSortIsIdentity){
     264            0 :                                         SetMatrixAsPermutation(permA, mat, m_ordering);
     265              :                                         A = &permA;
     266              :                                 }
     267              :                                 else{
     268              :                                         A = &mat;
     269              :                                 }
     270              :                         }
     271              :                         else
     272              :                         {
     273              :                                 A = &mat;
     274              :                         }
     275              : 
     276            0 :                         m_L.resize_and_clear(A->num_rows(), A->num_cols());
     277            0 :                         m_U.resize_and_clear(A->num_rows(), A->num_cols());
     278              : 
     279              :                         size_t totalentries=0;
     280              :                         size_t maxentries=0;
     281              : 
     282            0 :                         if((A->num_rows() > 0) && (A->num_cols() > 0)){
     283              :                                 // con is the current line of L/U
     284              :                                 // i also tried using std::list here or a special custom vector-based linked list
     285              :                                 // but vector is fastest, even with the insert operation.
     286              :                                 std::vector<matrix_connection> con;
     287            0 :                                 con.reserve(300);
     288            0 :                                 con.resize(0);
     289              : 
     290              :                                 // init row 0 of U
     291            0 :                                 for(matrix_row_iterator i_it = A->begin_row(0); i_it != A->end_row(0); ++i_it)
     292            0 :                                         con.push_back(matrix_connection(i_it.index(), i_it.value()));
     293            0 :                                 m_U.set_matrix_row(0, &con[0], con.size());
     294              : 
     295            0 :                                 Progress prog;
     296            0 :                                 if(m_show_progress)
     297            0 :                                         PROGRESS_START_WITH(prog, A->num_rows(),
     298              :                                                 "Using ILUT(" << m_eps << ") on " << A->num_rows() << " x " << A->num_rows() << " matrix...");
     299              :                                 
     300            0 :                                 for(size_t i=1; i<A->num_rows(); i++)
     301              :                                 {
     302            0 :                                         if(m_show_progress) {PROGRESS_UPDATE(prog, i);}
     303            0 :                                         con.resize(0);
     304              :                                         size_t u_part=0;
     305              : 
     306            0 :                                         UG_COND_THROW(A->num_connections(i) == 0, "row " << i << " has no connections");
     307              : 
     308              :                                         // get the row A(i, .) into con
     309              :                                         double dmax=0;
     310            0 :                                         for(matrix_row_iterator i_it = A->begin_row(i); i_it != A->end_row(i); ++i_it)
     311              :                                         {
     312            0 :                                                 con.push_back(matrix_connection(i_it.index(), i_it.value()));
     313            0 :                                                 if(dmax < BlockNorm(i_it.value()))
     314            0 :                                                         dmax = BlockNorm(i_it.value());
     315              :                                         }
     316              : 
     317              :                                         // eliminate all entries A(i, k) with k<i with rows U(k, .) and k<i
     318            0 :                                         for(size_t i_it = 0; i_it < con.size(); ++i_it)
     319              :                                         {
     320            0 :                                                 size_t k = con[i_it].iIndex;
     321            0 :                                                 if(k >= i)
     322              :                                                 {
     323              :                                                         // safe where U begins / L ends in con
     324              :                                                         u_part = i_it;
     325            0 :                                                         break;
     326              :                                                 }
     327            0 :                                                 if(con[i_it].dValue == 0.0) continue;
     328            0 :                                                 UG_COND_THROW(!(m_U.num_connections(k) != 0 && m_U.begin_row(k).index() == k), "");
     329              :                                                 block_type &ukk = m_U.begin_row(k).value();
     330              : 
     331              :                                                 // add row k to row i by A(i, .) -= U(k,.)  A(i,k) / U(k,k)
     332              :                                                 // so that A(i,k) is zero.
     333              :                                                 // safe A(i,k)/U(k,k) in con, (later L(i,k) )
     334            0 :                                                 con[i_it].dValue = con[i_it].dValue / ukk;
     335              :                                                 block_type d = con[i_it].dValue;
     336            0 :                                                 UG_COND_THROW(!BlockMatrixFiniteAndNotTooBig(d, 1e40), "i = " << i << " " << d);
     337              : 
     338              :                                                 matrix_row_iterator k_it = m_U.begin_row(k); // upper row iterator
     339              :                                                 ++k_it; // skip diag
     340            0 :                                                 size_t j = i_it+1;
     341            0 :                                                 while(k_it != m_U.end_row(k) && j < con.size())
     342              :                                                 {
     343              :                                                         // (since con and U[k] is sorted, we can do sth like a merge on the two lists)
     344            0 :                                                         if(k_it.index() == con[j].iIndex)
     345              :                                                         {
     346              :                                                                 // match
     347            0 :                                                                 con[j].dValue -= k_it.value() * d;
     348            0 :                                                                 ++k_it; ++j;
     349              :                                                         }
     350            0 :                                                         else if(k_it.index() < con[j].iIndex)
     351              :                                                         {
     352              :                                                                 // we have a value in U(k, (*k_it).iIndex), but not in A.
     353              :                                                                 // check tolerance criteria
     354              : 
     355            0 :                                                                 matrix_connection c(k_it.index(), k_it.value() * d * -1.0);
     356              : 
     357            0 :                                                                 UG_COND_THROW(!BlockMatrixFiniteAndNotTooBig(c.dValue, 1e40), "i = " << i << " " << c.dValue);
     358            0 :                                                                 if(BlockNorm(c.dValue) > dmax * m_eps)
     359              :                                                                 {
     360              :                                                                         // insert sorted
     361            0 :                                                                         con.insert(con.begin()+j, c);
     362            0 :                                                                         ++j; // don't do this when using iterators
     363              :                                                                 }
     364              :                                                                 // else do some lumping
     365              :                                                                 ++k_it;
     366              :                                                         }
     367              :                                                         else
     368              :                                                         {
     369              :                                                                 // we have a value in A(k, con[j].iIndex), but not in U.
     370            0 :                                                                 ++j;
     371              :                                                         }
     372              :                                                 }
     373              :                                                 // insert new connections after last connection of row i
     374            0 :                                                 if (k_it!=m_U.end_row(k)){
     375            0 :                                                         for (;k_it!=m_U.end_row(k);++k_it){
     376            0 :                                                                 matrix_connection c(k_it.index(),-k_it.value()*d);
     377            0 :                                                         if(BlockNorm(c.dValue) > dmax * m_eps)
     378              :                                                         {
     379            0 :                                                                 con.push_back(c);
     380              :                                                         }
     381              :                                                     }
     382              :                                                 };
     383              :                                         }
     384              : 
     385              : 
     386            0 :                                         totalentries+=con.size();
     387              :                                         if(maxentries < con.size()) maxentries = con.size();
     388              : 
     389              :                                         // safe L and U
     390            0 :                                         m_L.set_matrix_row(i, &con[0], u_part);
     391            0 :                                         m_U.set_matrix_row(i, &con[u_part], con.size()-u_part);
     392              : 
     393              :                                 }
     394            0 :                                 if(m_show_progress) {PROGRESS_FINISH(prog);}
     395              : 
     396            0 :                                 m_L.defragment();
     397            0 :                                 m_U.defragment();
     398            0 :                         }
     399              : 
     400            0 :                         if (m_info==true)
     401              :                         {
     402            0 :                                 m_L.print("L");
     403            0 :                                 m_U.print("U");
     404              :                                 UG_LOG("\n ILUT storage information:\n");
     405              :                                 UG_LOG("   A is " << A->num_rows() << " x " << A->num_cols() << " matrix.\n");
     406              :                                 UG_LOG("   A nr of connections: " << A->total_num_connections()  << "\n");
     407            0 :                                 UG_LOG("   L+U nr of connections: " << m_L.total_num_connections()+m_U.total_num_connections() << "\n");
     408            0 :                                 UG_LOG("   Increase factor: " << (float)(m_L.total_num_connections() + m_U.total_num_connections() )/A->total_num_connections() << "\n");
     409            0 :                                 UG_LOG(reset_floats << "     Total entries: " << totalentries << " (" << ((double)totalentries) / (A->num_rows()*A->num_rows()) << "% of dense)\n");
     410            0 :                                 if(m_spOrderingAlgo.valid())
     411              :                                 {
     412            0 :                                         UG_LOG("   Using " <<  m_spOrderingAlgo->name() << "\n");
     413              :                                 }
     414              :                                 else
     415              :                                 {
     416              :                                         UG_LOG("Not using sort.");
     417              :                                 }
     418              :                         }
     419              : 
     420            0 :                         return true;
     421            0 :                 }
     422              : 
     423              :         //      Stepping routine
     424            0 :                 virtual bool step(SmartPtr<MatrixOperator<matrix_type, vector_type> > pOp, vector_type& c, const vector_type& d)
     425              :                 {
     426              : #ifdef UG_PARALLEL
     427              :                         SmartPtr<vector_type> spDtmp = d.clone();
     428              :                         spDtmp->change_storage_type(PST_UNIQUE);
     429              :                         bool b = solve(c, *spDtmp);
     430              : 
     431              :                         c.set_storage_type(PST_ADDITIVE);
     432              :                         c.change_storage_type(PST_CONSISTENT);
     433              :                         return b;
     434              : #else
     435            0 :                         return solve(c, d);
     436              : #endif
     437              :                         return true;
     438              :                 }
     439              : 
     440            0 :                 virtual bool solve(vector_type& c, const vector_type& d)
     441              :                 {
     442            0 :                         if(m_spOrderingAlgo.invalid()|| m_bSortIsIdentity)
     443              :                         {
     444            0 :                                 if(applyLU(c, d) == false) return false;
     445              :                         }
     446              :                         else
     447              :                         {
     448              :                                 PROFILE_BEGIN_GROUP(ILUT_StepWithReorder, "ilut algebra");
     449              : 
     450            0 :                                 SetVectorAsPermutation(c, d, m_ordering);
     451            0 :                                 c2.resize(c.size());
     452            0 :                                 if(applyLU(c2, c) == false) return false;
     453            0 :                                 SetVectorAsPermutation(c, c2, m_old_ordering);
     454              :                         }
     455              :                         return true;
     456              :                 }
     457              : 
     458              : 
     459            0 :                 virtual bool applyLU(vector_type& c, const vector_type& d)
     460              :                 {
     461              :                         PROFILE_BEGIN_GROUP(ILUT_step, "ilut algebra");
     462              :                         // apply iterator: c = LU^{-1}*d (damp is not used)
     463              :                         // L
     464            0 :                         for(size_t i=0; i < m_L.num_rows(); i++)
     465              :                         {
     466              :                                 // c[i] = d[i] - m_L[i]*c;
     467            0 :                                 c[i] = d[i];
     468            0 :                                 for(matrix_row_iterator it = m_L.begin_row(i); it != m_L.end_row(i); ++it)
     469            0 :                                         MatMultAdd(c[i], 1.0, c[i], -1.0, it.value(), c[it.index()] );
     470              :                                 // lii = 1.0.
     471              :                         }
     472              : 
     473              :                         // U
     474              :                         //
     475              :                         // last row diagonal U entry might be close to zero with corresponding zero rhs 
     476              :                         // when solving Navier Stokes system, therefore handle separately
     477            0 :                         if(m_U.num_rows() > 0)
     478              :                         {
     479            0 :                                 size_t i=m_U.num_rows()-1;
     480            0 :                                 matrix_row_iterator it = m_U.begin_row(i);
     481              :                                 UG_ASSERT(it != m_U.end_row(i), i);
     482              :                                 UG_ASSERT(it.index() == i, i);
     483              :                                 block_type &uii = it.value();
     484            0 :                                 vector_value s = c[i];
     485              :                                 // check if diag part is significantly smaller than rhs
     486              :                                 // This may happen when matrix is indefinite with one eigenvalue
     487              :                                 // zero. In that case, the factorization on the last row is
     488              :                                 // nearly zero due to round-off errors. In order to allow ill-
     489              :                                 // scaled matrices (i.e. small matrix entries row-wise) this
     490              :                                 // is compared to the rhs, that is small in this case as well.
     491              :                                 if (false && BlockNorm(uii) <= m_small * m_eps * BlockNorm(s)){
     492              :                                         UG_LOG("ILUT("<<m_eps<<") Warning: Near-zero diagonal entry "
     493              :                                                         "with norm "<<BlockNorm(uii)<<" in last row of U "
     494              :                                                         " with corresponding non-near-zero rhs with norm "
     495              :                                                         << BlockNorm(s) << ". Setting rhs to zero.\n");
     496              :                                         // set correction to zero
     497              :                                         c[i] = 0;
     498              :                                 } else {
     499              :                                         // c[i] = s/uii;
     500              :                                         InverseMatMult(c[i], 1.0, uii, s);
     501              :                                 }
     502              :                         }
     503              : 
     504              :                         // handle all other rows
     505            0 :                         if(m_U.num_rows() > 1){
     506            0 :                                 for(size_t i=m_U.num_rows()-2; ; i--)
     507              :                                 {
     508            0 :                                         matrix_row_iterator it = m_U.begin_row(i);
     509              :                                         UG_ASSERT(it != m_U.end_row(i), i);
     510              :                                         UG_ASSERT(it.index() == i, i);
     511              :                                         block_type &uii = it.value();
     512              : 
     513            0 :                                         vector_value s = c[i];
     514              :                                         ++it; // skip diag
     515            0 :                                         for(; it != m_U.end_row(i); ++it){
     516              :                                                 // s -= it.value() * c[it.index()];
     517            0 :                                                 MatMultAdd(s, 1.0, s, -1.0, it.value(), c[it.index()] );
     518              :                                         }
     519              :                                         // c[i] = s/uii;
     520              :                                         InverseMatMult(c[i], 1.0, uii, s);
     521              : 
     522            0 :                                         if(i==0) break;
     523              :                                 }
     524              :                         }
     525            0 :                         return true;
     526              :                 }
     527              : 
     528            0 :                 virtual bool multi_apply(std::vector<vector_type> &vc, const std::vector<vector_type> &vd)
     529              :                 {
     530              :                         PROFILE_BEGIN_GROUP(ILUT_step, "ilut algebra");
     531              :                         // apply iterator: c = LU^{-1}*d (damp is not used)
     532              :                         // L
     533            0 :                         for(size_t i=0; i < m_L.num_rows(); i++)
     534              :                         {
     535              : 
     536            0 :                                 for(size_t e=0; e<vc.size(); e++)
     537              :                                 {
     538              :                                         vector_type &c = vc[e];
     539              :                                         const vector_type &d = vd[e];
     540              :                                         // c[i] = d[i] - m_L[i]*c;
     541            0 :                                         c[i] = d[i];
     542            0 :                                         for(matrix_row_iterator it = m_L.begin_row(i); it != m_L.end_row(i); ++it)
     543            0 :                                                 MatMultAdd(c[i], 1.0, c[i], -1.0, it.value(), c[it.index()] );
     544              :                                         // lii = 1.0.
     545              :                                 }
     546              :                         }
     547              : 
     548              :                         // U
     549              :                         //
     550              :                         // last row diagonal U entry might be close to zero with corresponding zero rhs
     551              :                         // when solving Navier Stokes system, therefore handle separately
     552            0 :                         if(m_U.num_rows() > 0)
     553              :                         {
     554            0 :                                 for(size_t e=0; e<vc.size(); e++)
     555              :                                 {
     556              :                                         vector_type &c = vc[e];
     557            0 :                                         size_t i=m_U.num_rows()-1;
     558            0 :                                         matrix_row_iterator it = m_U.begin_row(i);
     559              :                                         UG_ASSERT(it != m_U.end_row(i), i);
     560              :                                         UG_ASSERT(it.index() == i, i);
     561              :                                         block_type &uii = it.value();
     562            0 :                                         vector_value s = c[i];
     563              :                                         // check if diag part is significantly smaller than rhs
     564              :                                         // This may happen when matrix is indefinite with one eigenvalue
     565              :                                         // zero. In that case, the factorization on the last row is
     566              :                                         // nearly zero due to round-off errors. In order to allow ill-
     567              :                                         // scaled matrices (i.e. small matrix entries row-wise) this
     568              :                                         // is compared to the rhs, that is small in this case as well.
     569              :                                         if (false && BlockNorm(uii) <= m_small * m_eps * BlockNorm(s)){
     570              :                                                 UG_LOG("ILUT("<<m_eps<<") Warning: Near-zero diagonal entry "
     571              :                                                                 "with norm "<<BlockNorm(uii)<<" in last row of U "
     572              :                                                                 " with corresponding non-near-zero rhs with norm "
     573              :                                                                 << BlockNorm(s) << ". Setting rhs to zero.\n");
     574              :                                                 // set correction to zero
     575              :                                                 c[i] = 0;
     576              :                                         } else {
     577              :                                                 // c[i] = s/uii;
     578              :                                                 InverseMatMult(c[i], 1.0, uii, s);
     579              :                                         }
     580              :                                 }
     581              :                         }
     582              : 
     583              :                         // handle all other rows
     584            0 :                         if(m_U.num_rows() > 1){
     585            0 :                                 for(size_t i=m_U.num_rows()-2; ; i--)
     586              :                                 {
     587            0 :                                         for(size_t e=0; e<vc.size(); e++)
     588              :                                         {
     589              :                                                 vector_type &c = vc[e];
     590            0 :                                                 matrix_row_iterator it = m_U.begin_row(i);
     591              :                                                 UG_ASSERT(it != m_U.end_row(i), i);
     592              :                                                 UG_ASSERT(it.index() == i, i);
     593              :                                                 block_type &uii = it.value();
     594              : 
     595            0 :                                                 vector_value s = c[i];
     596              :                                                 ++it; // skip diag
     597            0 :                                                 for(; it != m_U.end_row(i); ++it){
     598              :                                                         // s -= it.value() * c[it.index()];
     599            0 :                                                         MatMultAdd(s, 1.0, s, -1.0, it.value(), c[it.index()] );
     600              :                                                 }
     601              :                                                 // c[i] = s/uii;
     602              :                                                 InverseMatMult(c[i], 1.0, uii, s);
     603              : 
     604            0 :                                                 if(i==0) break;
     605              :                                         }
     606              :                                 }
     607              :                         }
     608            0 :                         return true;
     609              :                 }
     610              : 
     611              :         //      Postprocess routine
     612            0 :                 virtual bool postprocess() {return true;}
     613              : 
     614              :         protected:
     615              :                 vector_type c2;
     616              :                 matrix_type m_L;
     617              :                 matrix_type m_U;
     618              :                 double m_eps;
     619              :                 bool m_info;
     620              :                 bool m_show_progress;
     621              :                 static const number m_small;
     622              :                 std::vector<size_t> newIndex, oldIndex;
     623              : 
     624              :         /// for ordering algorithms
     625              :                 SmartPtr<ordering_algo_type> m_spOrderingAlgo;
     626              :                 ordering_container_type m_ordering, m_old_ordering;
     627              : 
     628              :                 bool m_bSortIsIdentity;
     629              : 
     630              :                 const vector_type* m_u;
     631              : };
     632              : 
     633              : // define constant
     634              : template <typename TAlgebra>
     635              : const number ILUTPreconditioner<TAlgebra>::m_small = 1e-8;
     636              : 
     637              : } // end namespace ug
     638              : 
     639              : #endif
        

Generated by: LCOV version 2.0-1