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

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2012-2015:  G-CSC, Goethe University Frankfurt
       3              :  * Author: Martin Rupp
       4              :  * 
       5              :  * This file is part of UG4.
       6              :  * 
       7              :  * UG4 is free software: you can redistribute it and/or modify it under the
       8              :  * terms of the GNU Lesser General Public License version 3 (as published by the
       9              :  * Free Software Foundation) with the following additional attribution
      10              :  * requirements (according to LGPL/GPL v3 §7):
      11              :  * 
      12              :  * (1) The following notice must be displayed in the Appropriate Legal Notices
      13              :  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
      14              :  * 
      15              :  * (2) The following notice must be displayed at a prominent place in the
      16              :  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
      17              :  * 
      18              :  * (3) The following bibliography is recommended for citation and must be
      19              :  * preserved in all covered files:
      20              :  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
      21              :  *   parallel geometric multigrid solver on hierarchically distributed grids.
      22              :  *   Computing and visualization in science 16, 4 (2013), 151-164"
      23              :  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
      24              :  *   flexible software system for simulating pde based models on high performance
      25              :  *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
      26              :  * 
      27              :  * This program is distributed in the hope that it will be useful,
      28              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      29              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      30              :  * GNU Lesser General Public License for more details.
      31              :  */
      32              : 
      33              : #ifndef __H__LIB_ALGEBRA__LAPACK_AGGLOMERATING_LU_OPERATOR__
      34              : #define __H__LIB_ALGEBRA__LAPACK_AGGLOMERATING_LU_OPERATOR__
      35              : #include <iostream>
      36              : #include <sstream>
      37              : 
      38              : #include "lib_algebra/operator/interface/operator_inverse.h"
      39              : #include "lib_algebra/operator/interface/matrix_operator_inverse.h"
      40              : #include "lib_algebra/operator/interface/preconditioner.h"
      41              : 
      42              : #ifdef UG_PARALLEL
      43              :         #include "lib_algebra/parallelization/collect_matrix.h"
      44              :         #include "lib_algebra/parallelization/parallelization.h"
      45              :         #include "lib_algebra/parallelization/parallelization_util.h"
      46              : #endif
      47              : 
      48              : namespace ug{
      49              : 
      50              : 
      51              : #ifdef UG_PARALLEL
      52              : template<typename T>
      53              : void GatherVectorOnOne(HorizontalAlgebraLayouts &agglomerationLayout,
      54              :                 ParallelVector<T> &collectedVec, const ParallelVector<T> &vec,
      55              :                 ParallelStorageType type)
      56              : {
      57              :         bool bRoot = pcl::ProcRank() == vec.layouts()->proc_comm().get_proc_id(0);
      58              :         GatherVectorOnOne(agglomerationLayout.master(), agglomerationLayout.slave(), agglomerationLayout.comm(),
      59              :                         collectedVec, vec, type, bRoot);
      60              : }
      61              : 
      62              : 
      63              : 
      64              : template<typename T>
      65              : void BroadcastVectorFromOne(HorizontalAlgebraLayouts &agglomerationLayout,
      66              :                 ParallelVector<T> &vec, const ParallelVector<T> &collectedVec,
      67              :                 ParallelStorageType type)
      68              : {
      69              :         bool bRoot = pcl::ProcRank() == vec.layouts()->proc_comm().get_proc_id(0);
      70              :         BroadcastVectorFromOne(agglomerationLayout.master(), agglomerationLayout.slave(),
      71              :                         agglomerationLayout.comm(), vec, collectedVec, type, bRoot);
      72              : }
      73              : #endif
      74              : 
      75              : template <typename TBase, typename TAlgebra>
      76            0 : class AgglomeratingBase : public TBase
      77              : {
      78              :         public:
      79              :         //      Algebra type
      80              :                 typedef TAlgebra algebra_type;
      81              : 
      82              :         //      Vector type
      83              :                 typedef typename TAlgebra::vector_type vector_type;
      84              : 
      85              :         //      Matrix type
      86              :                 typedef typename TAlgebra::matrix_type matrix_type;
      87              : 
      88              :         public:
      89              :         //      Destructor
      90            0 :                 virtual ~AgglomeratingBase() {};
      91              : 
      92              :                 bool i_am_root()
      93              :                 {
      94              :                         return m_bRoot;
      95              :                         //m_bRoot = pcl::ProcRank() == agglomerationLayout.proc_comm().get_proc_id(0);;
      96              :                 }
      97              : 
      98              :                 bool empty()
      99              :                 {
     100              :                         return m_bEmpty;
     101              :                 }
     102              : 
     103              :                 bool init_mat(const matrix_type &A)
     104              :                 {
     105              :                         try{
     106              : #ifdef UG_PARALLEL
     107              :                         m_bEmpty = A.layouts()->proc_comm().empty();
     108              :                         if(m_bEmpty) return true;
     109              :                         m_bRoot = pcl::ProcRank() == A.layouts()->proc_comm().get_proc_id(0);
     110              :                         PROFILE_FUNC();
     111              : 
     112              :                         m_spCollectedOp = make_sp(new MatrixOperator<matrix_type, vector_type>());
     113              :                         matrix_type &collectedA = m_spCollectedOp->get_matrix();
     114              : 
     115              :                         CollectMatrixOnOneProc(A, collectedA, agglomerationLayout.master(), agglomerationLayout.slave());
     116              :                         agglomerationLayout.comm() = A.layouts()->comm();
     117              :                         agglomerationLayout.proc_comm() = A.layouts()->proc_comm();
     118              : 
     119              :                         m_spLocalAlgebraLayouts = CreateLocalAlgebraLayouts();
     120              :                         collectedA.set_layouts(m_spLocalAlgebraLayouts);
     121              : #else
     122              :                         m_bEmpty = false;
     123              :                         m_bRoot = true;
     124              : #endif
     125              :                         }UG_CATCH_THROW("AgglomeratingBase::" << __FUNCTION__ << " failed")
     126              :                         return true;
     127              :                 }
     128              : 
     129              : #ifdef UG_PARALLEL
     130              :                 void init_collected_vec(vector_type &collectedX)
     131              :                 {
     132              :                         if(i_am_root())
     133              :                         {
     134              :                                 matrix_type &collectedA = m_spCollectedOp->get_matrix();
     135              :                                 collectedX.resize(collectedA.num_rows());
     136              :                                 collectedX.set_layouts(m_spLocalAlgebraLayouts);
     137              :                         }
     138              :                 }
     139              : 
     140              :                 void gather_vector_on_one(vector_type &collectedB, const vector_type &b, ParallelStorageType type)
     141              :                 {
     142              :                         GatherVectorOnOne(agglomerationLayout, collectedB, b, PST_ADDITIVE);
     143              :                 }
     144              : 
     145              :                 void broadcast_vector_from_one(vector_type &x, const vector_type &collectedX, ParallelStorageType type)
     146              :                 {
     147              :                         BroadcastVectorFromOne(agglomerationLayout, x, collectedX, PST_CONSISTENT);
     148              :                 }
     149              : #endif
     150              : 
     151              :                 virtual bool init_agglomerated(SmartPtr<MatrixOperator<matrix_type, vector_type> > Op) = 0;
     152              :                 virtual bool apply_agglomerated(vector_type& x, const vector_type& b) = 0;
     153              : 
     154            0 :                 bool is_serial()
     155              :                 {
     156            0 :                         UG_COND_THROW(m_pMatrix == NULL, "ERROR: No Matrix given.");
     157              : #ifdef UG_PARALLEL
     158              :                         return m_pMatrix->layouts()->proc_comm().is_local() || m_pMatrix->layouts()->proc_comm().empty();
     159              : 
     160              : #else
     161            0 :                         return true;
     162              : #endif
     163              :                 }
     164              : 
     165              : ///     Preprocess routine
     166            0 :                 bool base_init(SmartPtr<MatrixOperator<matrix_type, vector_type> > Op)
     167              :                 {
     168              :                         try{
     169              :                         PROFILE_FUNC();
     170              :                 //      get matrix of Operator
     171            0 :                         m_pMatrix = &Op->get_matrix();
     172              : 
     173              : 
     174              : #ifdef UG_PARALLEL
     175              :                         if(is_serial())
     176              :                                 return init_agglomerated(Op);
     177              : 
     178              :                         PROFILE_BEGIN(AGGLOMERATING_Solver_BARRIER);
     179              :                                 m_pMatrix->layouts()->proc_comm().barrier();
     180              :                         PROFILE_END();
     181              : 
     182              :                 //      init LU operator
     183              :                         if(!init_mat(*m_pMatrix))
     184              :                                 {UG_LOG("ERROR in LUOperator::init: Cannot init LU Decomposition.\n"); return false;}
     185              : 
     186              :                         bool bSuccess=true;
     187              :                         if(i_am_root())
     188              :                         {
     189              :                                 init_collected_vec(collectedX);
     190              :                                 init_collected_vec(collectedB);
     191              :                                 bSuccess = init_agglomerated(m_spCollectedOp);
     192              :                                 //UG_DLOG(LIB_ALG_LINEAR_SOLVER, 1,
     193              :                                 if(collectedX.size() != m_pMatrix->num_rows()) {
     194              :                                         UG_LOG("Agglomerated on proc 0. Size is " << collectedX.size() << "(was on this proc: "
     195              :                                                 << m_pMatrix->num_rows() << ")\n");
     196              :                                 }
     197              :                         }
     198              :                         if(pcl::AllProcsTrue(bSuccess, m_pMatrix->layouts()->proc_comm()) == false) return false;
     199              :                         return true;
     200              : #else
     201            0 :                         return init_agglomerated(Op);
     202              : #endif
     203            0 :                         }UG_CATCH_THROW("AgglomeratingBase::" << __FUNCTION__ << " failed")
     204              :                 }
     205              : 
     206              : 
     207            0 :                 virtual bool base_init(SmartPtr<ILinearOperator<vector_type> > A)
     208              :                 {
     209              :                 //      cast operator
     210            0 :                         SmartPtr<MatrixOperator<matrix_type,vector_type> > op =
     211              :                                                                         A.template cast_dynamic<MatrixOperator<matrix_type,vector_type> >();
     212              : 
     213              :                 //      check if correct types are present
     214            0 :                         if(op.invalid())
     215            0 :                                 UG_THROW("IMatrixOperatorInverse::init:"
     216              :                                                 " Passed operator is not matrix-based.");
     217              : 
     218              :                 //      forward request
     219            0 :                         return base_init(op);
     220              :                 }
     221              : 
     222            0 :                 virtual bool apply(vector_type& x, const vector_type& b)
     223              :                 {
     224              :                         try{
     225              : 
     226            0 :                         if(is_serial())
     227            0 :                                 return apply_agglomerated(x, b);
     228              : #if UG_PARALLEL
     229              :                         if(empty()) return true;
     230              : 
     231              :                         gather_vector_on_one(collectedB, b, PST_ADDITIVE);
     232              : 
     233              :                         collectedX.set(0.0);
     234              :                         if(i_am_root())
     235              :                                 apply_agglomerated(collectedX, collectedB);
     236              : 
     237              :                         broadcast_vector_from_one(x, collectedX, PST_CONSISTENT);
     238              : #endif
     239            0 :                         }UG_CATCH_THROW("AgglomeratingBase::" << __FUNCTION__ << " failed")
     240              :                 //      we're done
     241              :                         return true;
     242              :                 }
     243              : 
     244              :         //      Compute u = L^{-1} * f AND return defect f := f - L*u
     245              : 
     246            0 :                 virtual bool apply_return_defect(vector_type& u, vector_type& f)
     247              :                 {
     248              :                         PROFILE_FUNC();
     249              :                 //      solve u
     250            0 :                         if(!apply(u, f)) return false;
     251              : 
     252              :                 //      calculate defect
     253              :                         f.set(0.0);
     254            0 :                         if(!m_pMatrix->matmul_minus(f, u))
     255              :                         {
     256              :                                 UG_LOG("ERROR in 'LUSolver::apply_return_defect': Cannot apply matmul_minus.\n");
     257              :                                 return false;
     258              :                         }
     259              : 
     260              :                 //      we're done
     261            0 :                         return true;
     262              :                 }
     263              : 
     264            0 :                 virtual bool apply_update_defect(vector_type& u, vector_type& f)
     265              :                 {
     266              :                         PROFILE_FUNC();
     267              :                 //      solve u
     268            0 :                         if(!apply(u, f)) return false;
     269              :                 //      update defect
     270            0 :                         if(!m_pMatrix->matmul_minus(f, u))
     271              :                         {
     272              :                                 UG_LOG("ERROR in 'LUSolver::apply_return_defect': Cannot apply matmul_minus.\n");
     273              :                                 return false;
     274              :                         }
     275              : 
     276              :                 //      we're done
     277            0 :                         return true;
     278              :                 }
     279              : 
     280            0 :                 virtual bool step(SmartPtr<MatrixOperator<matrix_type, vector_type> > pOp, vector_type& c, const vector_type& d)
     281              :                 {
     282            0 :                         return apply(c, d);
     283              :                 }
     284              : 
     285              : 
     286              : 
     287              :         protected:
     288              :                 // Operator to invert
     289              : 
     290              :                 // matrix to invert
     291              :                 matrix_type* m_pMatrix;
     292              : #ifdef UG_PARALLEL
     293              :                 vector_type collectedB, collectedX;
     294              :                 HorizontalAlgebraLayouts agglomerationLayout;
     295              :                 SmartPtr<MatrixOperator<matrix_type, vector_type> > m_spCollectedOp;
     296              :                 SmartPtr<AlgebraLayouts> m_spLocalAlgebraLayouts;
     297              : #endif
     298              : 
     299              :                 bool m_bRoot;
     300              :                 bool m_bEmpty;
     301              : 
     302              : };
     303              : 
     304              : 
     305              : 
     306              : template <typename TAlgebra>
     307              : class AgglomeratingSolver : public
     308              :         AgglomeratingBase<IMatrixOperatorInverse< typename TAlgebra::matrix_type, typename TAlgebra::vector_type>, TAlgebra >
     309              : {
     310              :         public:
     311              :         //      Algebra type
     312              :                 typedef TAlgebra algebra_type;
     313              : 
     314              :         //      Vector type
     315              :                 typedef typename TAlgebra::vector_type vector_type;
     316              : 
     317              :         //      Matrix type
     318              :                 typedef typename TAlgebra::matrix_type matrix_type;
     319              : 
     320              :         ///     Base type
     321              :                 typedef AgglomeratingBase<IMatrixOperatorInverse<matrix_type,vector_type>, algebra_type > base_type;
     322              : 
     323              : 
     324              :         public:
     325            0 :                 AgglomeratingSolver(SmartPtr<ILinearOperatorInverse<vector_type, vector_type> > linOpInverse)
     326            0 :                 {
     327            0 :                         UG_COND_THROW(linOpInverse.valid()==false, "linOpInverse has to be != NULL");
     328            0 :                         m_pLinOpInverse = linOpInverse;
     329            0 :                         m_name = std::string("AgglomeratingSolver(") + linOpInverse->name() + ")";
     330            0 :                 };
     331              : 
     332            0 :                 virtual bool init_agglomerated(SmartPtr<MatrixOperator<matrix_type, vector_type> > Op)
     333              :                 {
     334              :                         try{
     335            0 :                                 return m_pLinOpInverse->init(Op);
     336            0 :                         }UG_CATCH_THROW("AgglomeratingSolver::" << __FUNCTION__ << " failed")
     337              :                 }
     338            0 :                 virtual bool apply_agglomerated(vector_type& x, const vector_type& b)
     339              :                 {
     340              :                         try{
     341            0 :                                 return m_pLinOpInverse->apply(x, b);
     342            0 :                         }UG_CATCH_THROW("AgglomeratingSolver::" << __FUNCTION__ << " failed")
     343              :                 }
     344              : 
     345              :         //      Destructor
     346            0 :                 virtual ~AgglomeratingSolver() {};
     347              : 
     348              : 
     349            0 :                 virtual const char* name() const
     350              :                 {
     351            0 :                         return m_name.c_str();
     352              :                 }
     353              : 
     354            0 :                 virtual bool supports_parallel() const { return true; }
     355              : 
     356            0 :                 virtual std::string config_string() const
     357              :                 {
     358            0 :                         return std::string("AgglomeratingSolver: ") + m_pLinOpInverse->config_string();
     359              :                 }
     360              : 
     361            0 :                 virtual bool init(SmartPtr<ILinearOperator<vector_type> > A)
     362              :                 {
     363            0 :                         return base_type::base_init(A);
     364              :                 }
     365            0 :                 virtual bool init(SmartPtr<ILinearOperator<vector_type> > A, const vector_type& u)
     366              :                 {
     367            0 :                         return base_type::base_init(A);
     368              :                 }
     369            0 :                 virtual bool init(SmartPtr<MatrixOperator<matrix_type, vector_type> > Op)
     370              :                 {
     371            0 :                         return base_type::base_init(Op);
     372              :                 }
     373              : 
     374              : 
     375              :         protected:
     376              :                 SmartPtr<ILinearOperatorInverse<vector_type, vector_type> > m_pLinOpInverse;
     377              :                 std::string m_name;
     378              : };
     379              : 
     380              : 
     381              : 
     382              : template <typename TAlgebra>
     383              : class AgglomeratingIterator : public
     384              :         AgglomeratingBase<ILinearIterator<typename TAlgebra::vector_type>, TAlgebra >
     385              : {
     386              :         public:
     387              :         //      Algebra type
     388              :                 typedef TAlgebra algebra_type;
     389              : 
     390              :         //      Vector type
     391              :                 typedef typename TAlgebra::vector_type vector_type;
     392              : 
     393              :         //      Matrix type
     394              :                 typedef typename TAlgebra::matrix_type matrix_type;
     395              : 
     396              :         ///     Base type
     397              :                 typedef AgglomeratingBase<ILinearIterator<vector_type>, algebra_type > base_type;
     398              : 
     399              :         public:
     400            0 :                 AgglomeratingIterator(SmartPtr<ILinearIterator<vector_type> > splinIt)
     401            0 :                 {
     402            0 :                         UG_COND_THROW(splinIt.valid()==false, "linOpInverse has to be != NULL");
     403            0 :                         m_splinIt = splinIt;
     404            0 :                         m_name = std::string("AgglomeratingIterator(") + splinIt->name() + std::string(")");
     405            0 :                 }
     406              : 
     407            0 :                 virtual bool init_agglomerated(SmartPtr<MatrixOperator<matrix_type, vector_type> > Op)
     408              :                 {
     409              :                         try{
     410            0 :                                 return m_splinIt->init(Op);
     411            0 :                         }UG_CATCH_THROW("AgglomeratingIterator::" << __FUNCTION__ << " failed")
     412              :                 }
     413            0 :                 virtual bool apply_agglomerated(vector_type& x, const vector_type& b)
     414              :                 {
     415              :                         try{
     416            0 :                                 return m_splinIt->apply(x, b);
     417            0 :                         }UG_CATCH_THROW("AgglomeratingIterator::" << __FUNCTION__ << " failed")
     418              :                 }
     419              : 
     420              :         //      Destructor
     421            0 :                 virtual ~AgglomeratingIterator() {};
     422              : 
     423              : 
     424            0 :                 virtual const char* name() const
     425              :                 {
     426            0 :                         return m_name.c_str();
     427              :                 }
     428              : 
     429            0 :                 virtual bool supports_parallel() const { return true; }
     430              : 
     431              :                 ///     Clone
     432            0 :                 virtual SmartPtr<ILinearIterator<vector_type> > clone()
     433              :                 {
     434            0 :                         SmartPtr<ILinearIterator<vector_type> > linIt = m_splinIt->clone();
     435            0 :                         return make_sp(new AgglomeratingIterator<algebra_type>(linIt));
     436              :                 }
     437              : 
     438            0 :                 virtual std::string config_string() const
     439              :                 {
     440            0 :                         return std::string("AgglomeratingIterator: ") + m_splinIt->config_string();
     441              :                 }
     442              : 
     443              : 
     444            0 :                 virtual bool init(SmartPtr<ILinearOperator<vector_type> > A)
     445              :                 {
     446            0 :                         return base_type::base_init(A);
     447              :                 }
     448            0 :                 virtual bool init(SmartPtr<ILinearOperator<vector_type> > A, const vector_type& u)
     449              :                 {
     450            0 :                         return base_type::base_init(A);
     451              :                 }
     452              : 
     453              : 
     454              :         protected:
     455              :                 SmartPtr<ILinearIterator<vector_type> > m_splinIt;
     456              :                 std::string m_name;
     457              : };
     458              : 
     459              : template <typename TAlgebra>
     460              : class AgglomeratingPreconditioner: public
     461              :         AgglomeratingBase<IPreconditioner<TAlgebra>, TAlgebra >
     462              : {
     463              :         public:
     464              :         //      Algebra type
     465              :                 typedef TAlgebra algebra_type;
     466              : 
     467              :         //      Vector type
     468              :                 typedef typename TAlgebra::vector_type vector_type;
     469              : 
     470              :         //      Matrix type
     471              :                 typedef typename TAlgebra::matrix_type matrix_type;
     472              : 
     473              :         ///     Base type
     474              :                 typedef AgglomeratingBase<IPreconditioner<TAlgebra>, TAlgebra > base_type;
     475              : 
     476              :         public:
     477            0 :                 AgglomeratingPreconditioner(SmartPtr<ILinearIterator<vector_type> > splinIt)
     478            0 :                 {
     479            0 :                         UG_COND_THROW(splinIt.valid()==false, "linOpInverse has to be != NULL");
     480            0 :                         m_splinIt = splinIt;
     481            0 :                         m_name = std::string("AgglomeratingPreconditioner(") + splinIt->name() + std::string(")");
     482            0 :                 }
     483              : 
     484            0 :                 virtual bool init_agglomerated(SmartPtr<MatrixOperator<matrix_type, vector_type> > Op)
     485              :                 {
     486              :                         try{
     487            0 :                                 return m_splinIt->init(Op);
     488            0 :                         }UG_CATCH_THROW("AgglomeratingIterator::" << __FUNCTION__ << " failed")
     489              :                 }
     490            0 :                 virtual bool apply_agglomerated(vector_type& x, const vector_type& b)
     491              :                 {
     492              :                         try{
     493            0 :                                 return m_splinIt->apply(x, b);
     494            0 :                         }UG_CATCH_THROW("AgglomeratingIterator::" << __FUNCTION__ << " failed")
     495              :                 }
     496              : 
     497              :         //      Destructor
     498            0 :                 virtual ~AgglomeratingPreconditioner() {};
     499              : 
     500              : 
     501            0 :                 virtual const char* name() const
     502              :                 {
     503            0 :                         return m_name.c_str();
     504              :                 }
     505              : 
     506            0 :                 virtual bool supports_parallel() const { return true; }
     507              : 
     508              :                 ///     Clone
     509            0 :                 virtual SmartPtr<ILinearIterator<vector_type> > clone()
     510              :                 {
     511            0 :                         SmartPtr<ILinearIterator<vector_type> > linIt = m_splinIt->clone();
     512            0 :                         return make_sp(new AgglomeratingIterator<algebra_type>(linIt));
     513              :                 }
     514              : 
     515            0 :                 virtual std::string config_string() const
     516              :                 {
     517            0 :                         return std::string("AgglomeratingPreconditioner: ") + m_splinIt->config_string();
     518              :                 }
     519              : 
     520            0 :                 virtual bool postprocess() { return true; }
     521            0 :                 virtual bool preprocess(SmartPtr<MatrixOperator<typename TAlgebra::matrix_type, typename TAlgebra::vector_type> > pOp)
     522              :                 {
     523            0 :                         return base_type::base_init(pOp);
     524              :                 }
     525              : 
     526              : 
     527              :         protected:
     528              :                 SmartPtr<ILinearIterator<vector_type> > m_splinIt;
     529              :                 std::string m_name;
     530              : };
     531              : 
     532              : 
     533              : 
     534              : } // end namespace ug
     535              : 
     536              : #endif /* __H__LIB_ALGEBRA__LAPACK_LU_OPERATOR__ */
        

Generated by: LCOV version 2.0-1