1 /*
2 XLiFE++ is an extended library of finite elements written in C++
3     Copyright (C) 2014  Lunéville, Eric; Kielbasiewicz, Nicolas; Lafranche, Yvon; Nguyen, Manh-Ha; Chambeyron, Colin
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13     You should have received a copy of the GNU General Public License
14     along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 /*!
18   \file TermMatrix.cpp
19   \author E. Lunéville
20   \authors D. Martin, E. Lunéville
21   \since 03 apr 2012
22   \date 20 mar 2013
23 
24   \brief Implementation of xlifepp::TermMatrix class members
25 */
26 
27 #include "TermMatrix.hpp"
28 
29 namespace xlifepp
30 {
31 
32 //===============================================================================
33 //member functions of TermMatrix class
34 //===============================================================================
35 //constructors
TermMatrix(const string_t & na)36 TermMatrix::TermMatrix(const string_t& na)
37 {
38   termType_ = _termMatrix;
39   name_ = na;
40   entries_p = 0;
41   scalar_entries_p=0;
42   rhs_matrix_p=0;
43   constraints_u_p = 0;
44   constraints_v_p = 0;
45 }
46 
TermMatrix(const BilinearForm & blf,const string_t & na,bool noass)47 TermMatrix::TermMatrix(const BilinearForm& blf, const string_t& na, bool noass)
48 {
49   initFromBlf(blf, na, noass);
50   constraints_u_p = 0;
51   constraints_v_p = 0;
52 }
53 
54 //! constructor with no essential boundary conditions
TermMatrix(const BilinearForm & blf,const string_t & na)55 TermMatrix::TermMatrix(const BilinearForm& blf, const string_t& na)
56 {
57   std::vector<TermOption> opts;
58   build(blf,0,0,ReductionMethod(_noReduction),opts,na);
59 }
60 
TermMatrix(const BilinearForm & blf,TermOption op1,const string_t & na)61 TermMatrix::TermMatrix(const BilinearForm& blf, TermOption op1, const string_t& na)
62 {
63   std::vector<TermOption> opts(1,op1);
64   build(blf,0,0,ReductionMethod(_noReduction),opts,na);
65 }
66 
TermMatrix(const BilinearForm & blf,TermOption op1,TermOption op2,const string_t & na)67 TermMatrix::TermMatrix(const BilinearForm& blf, TermOption op1, TermOption op2, const string_t& na)
68 {
69   std::vector<TermOption> opts(2,op1); opts[1]=op2;
70   build(blf,0,0,ReductionMethod(_noReduction),opts,na);
71 }
72 
TermMatrix(const BilinearForm & blf,TermOption op1,TermOption op2,TermOption op3,const string_t & na)73 TermMatrix::TermMatrix(const BilinearForm& blf, TermOption op1, TermOption op2, TermOption op3, const string_t& na)
74 {
75   std::vector<TermOption> opts(3,op1); opts[1]=op2; opts[2]=op3;
76   build(blf,0,0,ReductionMethod(_noReduction),opts,na);
77 }
78 
79 //! constructor with one essential boundary conditions
TermMatrix(const BilinearForm & blf,const EssentialConditions & ec,const string_t & na)80 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ec, const string_t& na)
81 {
82   std::vector<TermOption> opts;
83   build(blf,&ec,0,ReductionMethod(_pseudoReduction),opts,na);
84 }
85 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ec,TermOption op1,const string_t & na)86 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ec, TermOption op1, const string_t& na)
87 {
88   std::vector<TermOption> opts(1,op1);
89   build(blf,&ec,0,ReductionMethod(_pseudoReduction),opts,na);
90 }
91 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ec,TermOption op1,TermOption op2,const string_t & na)92 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ec, TermOption op1, TermOption op2, const string_t& na)
93 {
94   std::vector<TermOption> opts(2,op1); opts[1]=op2;
95   build(blf,&ec,0,ReductionMethod(_pseudoReduction),opts,na);
96 }
97 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ec,TermOption op1,TermOption op2,TermOption op3,const string_t & na)98 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ec, TermOption op1, TermOption op2, TermOption op3, const string_t& na)
99 {
100   std::vector<TermOption> opts(3,op1); opts[1]=op2; opts[2]=op3;
101   build(blf,&ec,0,ReductionMethod(_pseudoReduction),opts,na);
102 }
103 
104 //! constructor with essential boundary condition and explicit reduction method
TermMatrix(const BilinearForm & blf,const EssentialConditions & ec,const ReductionMethod & rm,const string_t & na)105 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ec, const ReductionMethod& rm, const string_t& na)
106 {
107   std::vector<TermOption> opts;
108   build(blf,&ec,0,rm,opts,na);
109 }
110 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ec,const ReductionMethod & rm,TermOption op1,const string_t & na)111 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ec, const ReductionMethod& rm, TermOption op1, const string_t& na)
112 {
113   std::vector<TermOption> opts(1,op1);
114   build(blf,&ec,0,rm,opts,na);
115 }
116 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ec,const ReductionMethod & rm,TermOption op1,TermOption op2,const string_t & na)117 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ec, const ReductionMethod& rm, TermOption op1, TermOption op2, const string_t& na)
118 {
119   std::vector<TermOption> opts(2,op1); opts[1]=op2;
120   build(blf,&ec,0,rm,opts,na);
121 }
122 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ec,const ReductionMethod & rm,TermOption op1,TermOption op2,TermOption op3,const string_t & na)123 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ec, const ReductionMethod& rm, TermOption op1, TermOption op2, TermOption op3, const string_t& na)
124 {
125   std::vector<TermOption> opts(3,op1); opts[1]=op2; opts[2]=op3;
126   build(blf,&ec,0,rm,opts,na);
127 }
128 
129 //! constructor with two essential boundary conditions
TermMatrix(const BilinearForm & blf,const EssentialConditions & ecu,const EssentialConditions & ecv,const string_t & na)130 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ecu, const EssentialConditions& ecv, const string_t& na)
131 {
132   std::vector<TermOption> opts;
133   build(blf,&ecu,&ecv,ReductionMethod(_pseudoReduction),opts,na);
134 }
135 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ecu,const EssentialConditions & ecv,TermOption op1,const string_t & na)136 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ecu, const EssentialConditions& ecv, TermOption op1, const string_t& na)
137 {
138   std::vector<TermOption> opts(1,op1);
139   build(blf,&ecu,&ecv,ReductionMethod(_pseudoReduction),opts,na);
140 }
141 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ecu,const EssentialConditions & ecv,TermOption op1,TermOption op2,const string_t & na)142 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ecu, const EssentialConditions& ecv, TermOption op1, TermOption op2, const string_t& na)
143 {
144   std::vector<TermOption> opts(2,op1); opts[1]=op2;
145   build(blf,&ecu,&ecv,ReductionMethod(_pseudoReduction),opts,na);
146 }
147 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ecu,const EssentialConditions & ecv,TermOption op1,TermOption op2,TermOption op3,const string_t & na)148 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ecu, const EssentialConditions& ecv, TermOption op1, TermOption op2, TermOption op3, const string_t& na)
149 {
150   std::vector<TermOption> opts(3,op1); opts[1]=op2; opts[2]=op3;
151   build(blf,&ecu,&ecv,ReductionMethod(_pseudoReduction),opts,na);
152 }
153 
154 //! constructor with two essential boundary conditions and explicit reduction method
TermMatrix(const BilinearForm & blf,const EssentialConditions & ecu,const EssentialConditions & ecv,const ReductionMethod & rm,const string_t & na)155 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ecu, const EssentialConditions& ecv, const ReductionMethod& rm, const string_t& na)
156 {
157   std::vector<TermOption> opts;
158   build(blf,&ecu,&ecv,rm,opts,na);
159 }
160 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ecu,const EssentialConditions & ecv,const ReductionMethod & rm,TermOption op1,const string_t & na)161 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ecu, const EssentialConditions& ecv, const ReductionMethod& rm, TermOption op1, const string_t& na)
162 {
163   std::vector<TermOption> opts(1,op1);
164   build(blf,&ecu,&ecv,rm,opts,na);
165 }
166 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ecu,const EssentialConditions & ecv,const ReductionMethod & rm,TermOption op1,TermOption op2,const string_t & na)167 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ecu, const EssentialConditions& ecv, const ReductionMethod& rm,TermOption op1, TermOption op2, const string_t& na)
168 {
169   std::vector<TermOption> opts(2,op1); opts[1]=op2;
170   build(blf,&ecu,&ecv,rm,opts,na);
171 }
172 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ecu,const EssentialConditions & ecv,const ReductionMethod & rm,TermOption op1,TermOption op2,TermOption op3,const string_t & na)173 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ecu, const EssentialConditions& ecv, const ReductionMethod& rm, TermOption op1, TermOption op2, TermOption op3, const string_t& na)
174 {
175   std::vector<TermOption> opts(3,op1); opts[1]=op2; opts[2]=op3;
176   build(blf,&ecu,&ecv,rm,opts,na);
177 }
178 
179 
180 //! effective constructor
build(const BilinearForm & blf,const EssentialConditions * ecu,const EssentialConditions * ecv,const ReductionMethod & rm,const std::vector<TermOption> & opts,const string_t & na)181 void TermMatrix::build(const BilinearForm& blf, const EssentialConditions* ecu, const EssentialConditions* ecv, const ReductionMethod& rm,
182                        const std::vector<TermOption>& opts, const string_t& na)
183 {
184   std::vector<TermOption>::const_iterator ito=opts.begin();
185   computingInfo_.isComputed=false;
186   computingInfo_.noAssembly=false;
187   bool toCompute=true, toAssemble=true;
188   StorageType st=_noStorage;  AccessType ac=_noAccess;
189   SymType sym=_undefSymmetry;
190   computingInfo_.reductionMethod = rm;
191   for (; ito!=opts.end(); ++ito)
192   {
193     switch (*ito)
194     {
195       case _compute    : break;
196       case _notCompute : toCompute=false; break;
197       case _assembled   : break;
198       case _unassembled : toAssemble=false; break;
199       case _csRowStorage : st=_cs; ac=_row; break;
200       case _csColStorage : st=_cs; ac=_col; break;
201       case _csDualStorage: st=_cs; ac=_dual; break;
202       case _csSymStorage : st=_cs; ac=_sym; break;
203       case _denseRowStorage : st=_dense; ac=_row; break;
204       case _denseColStorage : st=_dense; ac=_col; break;
205       case _denseDualStorage: st=_dense; ac=_dual; break;
206       case _skylineSymStorage : st=_skyline; ac=_sym; break;
207       case _skylineDualStorage: st=_skyline; ac=_dual; break;
208       case _nonSymmetricMatrix : sym=_noSymmetry; break;
209       case _symmetricMatrix    : sym=_symmetric; break;
210       case _selfAdjointMatrix  : sym=_selfAdjoint; break;
211       case _skewSymmetricMatrix: sym=_skewSymmetric; break;
212       case _skewAdjointMatrix  : sym=_skewAdjoint; break;
213       case _pseudoReductionMethod : computingInfo_.reductionMethod.method=_pseudoReduction; break;
214       case _realReductionMethod   : computingInfo_.reductionMethod.method=_realReduction; break;
215       case _penalizationReductionMethod : computingInfo_.reductionMethod.method=_penalizationReduction; break;
216       default:
217         where("TermMatrix::build(...)");
218         error("undef_option");
219     }
220   }
221 
222   initFromBlf(blf, na, !toAssemble);
223   constraints_u_p = 0;
224   if (ecu!=0) constraints_u_p = new SetOfConstraints(buildConstraints(*ecu));
225   constraints_v_p = constraints_u_p;
226   if (ecv!=0 && ecv!=ecu) constraints_v_p = new SetOfConstraints(buildConstraints(*ecv));
227   if (sym!=_undefSymmetry)
228   {
229     where("TermMatrix::build(...)");
230     error("symmetry_not_handled", words("symmetry", sym));
231   }
232   if (st!=_noStorage) setStorage(st,ac);
233   if (toCompute) compute();
234 }
235 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ec,const string_t & na,bool noass)236 TermMatrix::TermMatrix(const BilinearForm& blf,  const EssentialConditions& ec, const string_t& na, bool noass)
237 {
238   initFromBlf(blf, na, noass);
239   constraints_u_p = new SetOfConstraints(buildConstraints(ec));
240   constraints_v_p = constraints_u_p;
241   computingInfo_.reductionMethod.method=_pseudoReduction;
242 }
243 
TermMatrix(const BilinearForm & blf,const EssentialConditions & ecu,const EssentialConditions & ecv,const string_t & na,bool noass)244 TermMatrix::TermMatrix(const BilinearForm& blf, const EssentialConditions& ecu, const EssentialConditions& ecv, const string_t& na, bool noass)
245 {
246   initFromBlf(blf, na, noass);
247   constraints_u_p = new SetOfConstraints(buildConstraints(ecu));
248   constraints_v_p = new SetOfConstraints(buildConstraints(ecv));
249   computingInfo_.reductionMethod.method=_pseudoReduction;
250 }
251 
TermMatrix(const BilinearForm & blf,const SetOfConstraints & soc,const string_t & na,bool noass)252 TermMatrix::TermMatrix(const BilinearForm& blf, const SetOfConstraints& soc, const string_t& na, bool noass)
253 {
254   initFromBlf(blf, na, noass);
255   constraints_u_p = new SetOfConstraints(soc);   //full copy of soc !!!
256   constraints_v_p = constraints_u_p;
257   computingInfo_.reductionMethod.method=_pseudoReduction;
258 }
259 
TermMatrix(const BilinearForm & blf,const SetOfConstraints & socu,const SetOfConstraints & socv,const string_t & na,bool noass)260 TermMatrix::TermMatrix(const BilinearForm& blf, const SetOfConstraints& socu, const SetOfConstraints& socv,
261                        const string_t& na, bool noass)
262 {
263   initFromBlf(blf, na, noass);
264   constraints_u_p = new SetOfConstraints(socu);
265   constraints_v_p = new SetOfConstraints(socv);
266   computingInfo_.reductionMethod.method=_pseudoReduction;
267 }
268 
269 //create suTermMatrix's
initFromBlf(const BilinearForm & blf,const string_t & na,bool noass)270 void TermMatrix::initFromBlf(const BilinearForm& blf, const string_t& na, bool noass)
271 {
272   bilinForm_ = blf; //copy the linearform
273   computingInfo_.noAssembly = noass;
274   termType_ = _termMatrix;
275   name_ = na;
276   entries_p = 0;
277   scalar_entries_p=0;
278   rhs_matrix_p=0;
279   for(it_mublc it = bilinForm_.begin(); it != bilinForm_.end(); it++)  //travel the map of single unknown bilinear forms
280   {
281     string_t nam = name_ + "_" + it->second.up()->name() + "_" + it->second.vp()->name();
282     // string_t nam = name_ + "_sub";
283     suTerms_[it->first] = new SuTermMatrix(&(it->second), nam, computingInfo_); //construct SuTermMatrix objects
284   }
285 }
286 
287 //constructor from a linear combination of TermVector's
TermMatrix(const LcTerm<TermMatrix> & lc,const string_t & na)288 TermMatrix::TermMatrix(const LcTerm<TermMatrix>& lc, const string_t& na)
289 {
290   trace_p->push("TermMatrix::TermMatrix(LcTerm)");
291   entries_p = 0;
292   scalar_entries_p=0;
293   rhs_matrix_p=0;
294   constraints_u_p = 0;
295   constraints_v_p = 0;
296   termType_ = _termMatrix;
297   compute(lc, na);
298   trace_p->pop();
299 }
300 
301 // destructor
~TermMatrix()302 TermMatrix::~TermMatrix()
303 {
304   for(it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++) delete it->second;
305   if(suTerms_.size()>1 && entries_p != 0) delete entries_p;
306   if(scalar_entries_p != entries_p && scalar_entries_p != 0) delete scalar_entries_p;
307   if(rhs_matrix_p != 0) delete rhs_matrix_p;
308   if(constraints_u_p!=0) delete constraints_u_p;
309   if(constraints_v_p!=0 && constraints_v_p!= constraints_u_p) delete constraints_v_p;
310 }
311 
312 //copy constructor
TermMatrix(const TermMatrix & mat,const string_t & na)313 TermMatrix::TermMatrix(const TermMatrix& mat, const string_t& na)
314 {
315   computingInfo_.noAssembly = false;
316   termType_ = _termMatrix;
317   name_ = na;
318   entries_p = 0;
319   scalar_entries_p=0;
320   rhs_matrix_p=0;
321   constraints_u_p = 0;
322   constraints_v_p = 0;
323   copy(mat);
324   if(na != "") name_ = na;
325 }
326 
327 //! constructor from a SuTermMatrix, create a one block TermMatrix
TermMatrix(const SuTermMatrix & sutm,const string_t & na)328 TermMatrix::TermMatrix(const SuTermMatrix& sutm, const string_t& na)
329 {
330   trace_p->push("TermMatrix::TermMatrix(SuTermMatrix)");
331   computingInfo_.noAssembly = false;
332   termType_ = _termMatrix;
333   name_ = na;
334   entries_p = 0;
335   scalar_entries_p=0;
336   rhs_matrix_p=0;
337   constraints_u_p = 0;
338   constraints_v_p = 0;
339   suTerms_[uvPair(sutm.up(),sutm.vp())]=new SuTermMatrix(sutm);  //full copy
340   computingInfo_.isComputed=sutm.computed();
341   trace_p->pop();
342 }
343 
TermMatrix(SuTermMatrix * sutm,const string_t & na)344 TermMatrix::TermMatrix(SuTermMatrix* sutm, const string_t& na)
345 {
346   trace_p->push("TermMatrix::TermMatrix(SuTermMatrix*)");
347   computingInfo_.noAssembly = false;
348   termType_ = _termMatrix;
349   name_ = na;
350   entries_p = 0;
351   scalar_entries_p=0;
352   rhs_matrix_p=0;
353   constraints_u_p = 0;
354   constraints_v_p = 0;
355   suTerms_[uvPair(sutm->up(),sutm->vp())]=sutm;  //pointer copy
356   computingInfo_.isComputed=sutm->computed();
357   trace_p->pop();
358 }
359 
360 // insert a SuTermMatrix  with full copy
insert(const SuTermMatrix & sutm)361 void TermMatrix::insert(const SuTermMatrix& sutm)
362 {
363   trace_p->push("TermMatrix::insert(SuTermMatrix)");
364   suTerms_[uvPair(sutm.up(),sutm.vp())]=new SuTermMatrix(sutm);  //full copy
365   if(!sutm.computed()) computingInfo_.isComputed= false;
366   trace_p->pop();
367 }
368 
369 // insert a SuTermMatrix with pointer copy
insert(SuTermMatrix * sutm)370 void TermMatrix::insert(SuTermMatrix* sutm)
371 {
372   trace_p->push("TermMatrix::insert(SuTermMatrix*)");
373   suTerms_[uvPair(sutm->up(),sutm->vp())]=sutm;       //pointer copy
374   if(!sutm->computed()) computingInfo_.isComputed= false;
375   trace_p->pop();
376 }
377 
378 
379 /*! constructor of a diagonal TermMatrix from a TermVector
380     if TermVector is a multiple unknowns vector, the matrix will be a multiple unknowns TermMatrix, each block being diagonal !
381 */
TermMatrix(const TermVector & tv,const string_t & na)382 TermMatrix::TermMatrix(const TermVector& tv, const string_t& na)
383 {
384   trace_p->push("TermMatrix::TermMatrix(TermVector)");
385   computingInfo_.noAssembly = false;
386   termType_ = _termMatrix;
387   name_ = na;
388   entries_p = 0;
389   scalar_entries_p=0;
390   rhs_matrix_p=0;
391   constraints_u_p = 0;
392   constraints_v_p = 0;
393   for(cit_mustv it = tv.begin(); it != tv.end(); it++)
394     {
395       const Unknown* u=it->first;
396       suTerms_[uvPair(u,u)]=new SuTermMatrix(*it->second,na+"_"+u->name()+"_"+u->name());
397     }
398   computingInfo_.isComputed=true;
399   trace_p->pop();
400 }
401 
402 /*! constructor of matrix opker(xi,yj) - Lagrange interpolation -
403     opker is evaluated on dof coordinates linked to Unknown and GeomDomains
404      ux, domx is associated to matrix rows and  uy, domy to matrix columns
405      NOTE : do not use this constructor if kernel is singular on some couple of points
406 */
TermMatrix(const Unknown & ux,const GeomDomain & domx,const Unknown & uy,const GeomDomain & domy,const OperatorOnKernel & opk,const string_t & na)407 TermMatrix::TermMatrix(const Unknown& ux, const GeomDomain& domx,
408                        const Unknown& uy, const GeomDomain& domy, const OperatorOnKernel& opk, const string_t& na)
409 {
410   trace_p->push("TermMatrix::TermMatrix(Unknown, GeomDomain, Unknown, GeomDomain, OperatorOnKernel)");
411   computingInfo_.noAssembly = false;
412   termType_ = _termMatrix;
413   name_ = na;
414   entries_p = 0;
415   scalar_entries_p=0;
416   rhs_matrix_p=0;
417   constraints_u_p = 0;
418   constraints_v_p = 0;
419   suTerms_[uvPair(&uy,&ux)]=new SuTermMatrix(ux, domx, uy, domy, opk, na+"_"+uy.name()+"_"+ux.name());
420   computingInfo_.isComputed=true;
421   trace_p->pop();
422 }
423 
424 /*! construct special matrix from a structure given by a TermMatrix
425   up to now, only IdMatrix is available
426 */
TermMatrix(const TermMatrix & A,SpecialMatrix sm,const string_t & na)427 TermMatrix::TermMatrix(const TermMatrix& A, SpecialMatrix sm, const string_t& na)
428 {
429   trace_p->push("TermMatrix(TermMatrix, SpecialMatrix)");
430   if (sm!=_idMatrix) error("matrix_type_not_handled", words("matrix", sm));
431   computingInfo_.noAssembly = false;
432   termType_ = _termMatrix;
433   if (na=="") name_="Id"; else name_ = na;
434   entries_p = 0;
435   scalar_entries_p=0;
436   rhs_matrix_p=0;
437   constraints_u_p = 0;
438   constraints_v_p = 0;
439   for (cit_mustm it = A.begin(); it != A.end(); it++)  //travel the map of single unknown linear forms
440   {
441     uvPair uv = it->first;
442     if(uv.first==uv.second || uv.first->dual_p()==uv.second)  suTerms_[uv] = new SuTermMatrix(*it->second, sm);
443   }
444   computingInfo_ .isComputed=true;;
445   if (A.scalar_entries_p != 0)
446   {
447     cdofs_c= A.cdofs_c;
448     cdofs_r= A.cdofs_r;
449   }
450   trace_p->pop();
451 }
452 
453 //assign operator
operator =(const TermMatrix & mat)454 TermMatrix& TermMatrix::operator=(const TermMatrix& mat)
455 {
456   if(this==&mat) return *this;
457   clear();
458   copy(mat);
459   return *this;
460 }
461 
462 // specify the storage of SuTermMatrix's of TermMatrix
463 // induce a storage conversion if terms are computed
setStorage(StorageType st,AccessType at)464 void TermMatrix::setStorage(StorageType st, AccessType at)
465 {
466   trace_p->push("TermMatrix::setStorage(...)");
467   computingInfo_.storageType = st;
468   computingInfo_.storageAccess = at;
469   for(it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)
470     it->second->setStorage(st, at);
471   if(entries_p!=0)
472     {
473       if(entries_p->storageType()!=st || entries_p->accessType()!=at)
474         {
475           std::vector<std::vector<number_t> > colIndices = entries_p->storagep()->scalarColIndices();  //retry column indices
476           MatrixStorage* mstorage = buildStorage(st, at, entries_p->nbOfRows(), entries_p->nbOfCols(), colIndices);
477           entries_p->toStorage(mstorage);
478         }
479     }
480   if(scalar_entries_p!=0)
481     {
482       if(scalar_entries_p->storageType()!=st || scalar_entries_p->accessType()!=at)
483         {
484           std::vector<std::vector<number_t> > colIndices = scalar_entries_p->storagep()->scalarColIndices();  //retry column indices
485           MatrixStorage* mstorage = buildStorage(st, at, scalar_entries_p->nbOfRows(), scalar_entries_p->nbOfCols(), colIndices);
486           scalar_entries_p->toStorage(mstorage);
487         }
488     }
489   trace_p->pop();
490 }
491 
492 // copy a TermMatrix into current TermMatrix
copy(const TermMatrix & mat)493 void TermMatrix::copy(const TermMatrix& mat)
494 {
495   trace_p->push("TermMatrix::copy(TermMatrix)");
496   bilinForm_ = mat.bilinForm_;
497   //if(name_=="" || name_=="?") name_ = mat.name_ + "_copy";
498   if(name_=="" || name_=="?") name_ = mat.name_ + "@";
499   termType_ = _termMatrix;
500   for(cit_mustm it = mat.begin(); it != mat.end(); it++)  //travel the map of single unknown linear forms
501     {
502       uvPair uv = it->first;
503       SuTermMatrix* sutm = it->second;
504       suTerms_[uv] = new SuTermMatrix(*sutm);
505       suTerms_[uv]->sublfp() = bilinForm_.subLfp(uv);   //maintain links between bilinearform and sublinearforms
506     }
507   computingInfo_ = mat.computingInfo_;
508   if(mat.entries_p != 0) entries_p = new MatrixEntry(*mat.entries_p);
509   if(mat.scalar_entries_p != 0)
510     {
511       if(mat.scalar_entries_p!=mat.entries_p) scalar_entries_p = new MatrixEntry(*mat.scalar_entries_p);
512       else scalar_entries_p = entries_p;
513       cdofs_c= mat.cdofs_c;
514       cdofs_r= mat.cdofs_r;
515     }
516   if(mat.rhs_matrix_p != 0) rhs_matrix_p = new MatrixEntry(*mat.rhs_matrix_p);
517   if(mat.constraints_u_p !=0) constraints_u_p = new SetOfConstraints(*mat.constraints_u_p);
518   if(mat.constraints_v_p !=0)
519     {
520       if(mat.constraints_v_p == mat.constraints_u_p) constraints_v_p = constraints_u_p;
521       else constraints_v_p = new SetOfConstraints(*mat.constraints_v_p);
522     }
523   trace_p->pop();
524 }
525 
526 //deallocate memory used by a TermMatrix
clear()527 void TermMatrix::clear()
528 {
529   trace_p->push("TermMatrix::clear");
530   if(entries_p != 0) delete entries_p;
531   if(scalar_entries_p!=entries_p && scalar_entries_p != 0) delete scalar_entries_p;
532   if(rhs_matrix_p != 0) delete rhs_matrix_p;
533   if(constraints_u_p!=0) delete constraints_u_p;
534   if(constraints_v_p!=0 && constraints_v_p!= constraints_u_p) delete constraints_v_p;
535   entries_p = 0;
536   scalar_entries_p = 0;
537   rhs_matrix_p =0;
538   constraints_u_p = 0;
539   constraints_v_p = 0;
540   cdofs_r.clear();
541   cdofs_c.clear();
542   for(it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++) it->second->clear();
543   //suTerms_.clear();
544   computed() = false;
545   trace_p->pop();
546 }
547 
548 /*! compute a LcTerm (linear combination of TermMatrix's) to a TermMatrix
549  all the TermMatrix's have to be computed before
550  and the current TermMatrix is 'void'
551 
552  NOTE : this current version works only for "standard" representation (entries pointers) but NOT for scalar representation (scalar_entries pointers)
553         it means that TermMatrix that have been converted using toScalar or toGlobal functions cannot be used in linear combinations.
554         Such conversions occur when essential conditions have been applied to a TermMatrix
555         To be improved in future !
556 */
compute(const LcTerm<TermMatrix> & lc,const string_t & na)557 void TermMatrix::compute(const LcTerm<TermMatrix>& lc, const string_t& na)
558 {
559   trace_p->push("TermMatrix::compute(LcTerm)");
560   if(lc.size() == 0) error("is_void", "LcTerm");  //abnormal !!
561   if(lc.size() == 1)
562     {
563       const TermMatrix* tM = dynamic_cast<const TermMatrix*>(lc.begin()->first);
564       if(tM == 0) error("null_pointer", "TermMatrix");
565       complex_t a = lc.begin()->second;
566       for(cit_mustm it = tM->suTerms_.begin(); it != tM->suTerms_.end(); it++)
567         {
568           SuTermMatrix* sut = new SuTermMatrix(*it->second);   //copy SuTermMatrix
569           sut->name() = tostring(a) + " * " + it->second->name();
570           if(a != complex_t(1., 0)) *sut *= a;                    //product if a!=1
571           suTerms_[it->first] = sut;
572         }
573       name_ = na;
574       if(na == "")
575         {
576           if(a.imag() == 0) name_ = tostring(a.real());
577           else name_ = tostring(a);
578           name_ += " * ( " + tM->name() + " )" ;
579         }
580       computed() = true;
581       trace_p->pop();
582       return;
583     }
584 
585   //case of a linear combination
586   //create linear combinations of SuTermMatrix indexed by unknown pairs
587   std::map<uvPair, LcTerm<SuTermMatrix> > lcs;
588   std::map<uvPair, LcTerm<SuTermMatrix> >::iterator itm;
589   name_ = na;
590   string_t pl = "";
591   for(LcTerm<TermMatrix>::const_iterator itt = lc.begin(); itt != lc.end(); itt++)
592     {
593       const TermMatrix* tM = dynamic_cast<const TermMatrix*>(itt->first);
594       if(tM == 0) error("null_pointer", "TermMatrix");
595       complex_t a = itt->second;
596       for(cit_mustm it = tM->suTerms_.begin(); it != tM->suTerms_.end(); it++)
597         {
598           uvPair uv = it->first;
599           SuTermMatrix* sut = it->second;
600           itm = lcs.find(uv);
601           if(itm == lcs.end()) lcs.insert(std::pair<uvPair, LcTerm<SuTermMatrix> >(uv, LcTerm<SuTermMatrix>(sut, a)));
602           else
603             {
604               LcTerm<SuTermMatrix> lci = itm->second;
605               lci.push_back(sut, a);
606               itm->second = lci;
607             }
608         }
609       if(na == "")
610         {
611           if(a.imag() == 0) name_ += pl + tostring(a.real()) ;
612           else  name_ += pl + tostring(a) ;
613           name_ += " * ( " + tM->name() + " )" ;
614           pl = " + ";
615         }
616     }
617 
618   //compute linear combination of SuTermMatrix's
619   for(itm = lcs.begin(); itm != lcs.end(); itm++)
620     {
621       SuTermMatrix* sut = new SuTermMatrix(itm->second);   //create SuTermMatrix
622       suTerms_[itm->first] = sut;
623     }
624 
625   computed() = true;
626   trace_p->pop();
627   return;
628 }
629 
630 // assign operator from a linear combinations of TermVector's
operator =(const LcTerm<TermMatrix> & lc)631 TermMatrix& TermMatrix::operator=(const LcTerm<TermMatrix>& lc)
632 {
633   trace_p->push("TermMatrix::operator =(LcTerm)");
634   //prevent self adding case (for instance Tm=Tm+Tm2+...), Tm has to be copied before cleared !!!
635   LcTerm<TermMatrix> lcc = lc;
636   TermMatrix* clone = 0;
637   for(LcTerm<TermMatrix>::iterator it = lcc.begin(); it != lcc.end(); it++)
638     {
639       if(it->first == const_cast<const TermMatrix*>(this))   //self adding
640         {
641           if(clone == 0) clone = new TermMatrix(*this);  //full copy !!!
642           complex_t a = it->second;
643           *it = std::pair<const TermMatrix*, complex_t>(clone, a); //modify linear combination by replacing current TermMatrix by its copy
644         }
645     }
646 
647   //clear current TermMatrix
648   bilinForm_.clear();
649   if(entries_p != 0)
650     {
651       delete entries_p;
652       entries_p = 0;
653     }
654   for(it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++) delete it->second;  //delete SuTermMatrix's
655 
656   //compute linear combination
657   compute(lcc);
658 
659   if(clone != 0) delete clone;
660   trace_p->pop();
661   return *this;
662 }
663 
664 // value type (_real,_complex)
valueType() const665 ValueType TermMatrix::valueType() const
666 {
667   if(scalar_entries_p!=0) return scalar_entries_p->valueType_;
668   if(entries_p!=0) return entries_p->valueType_;
669   if(suTerms_.size() > 0)
670     {
671       for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)   //travel the map of single unknown matrices
672         {
673           if(it->second!=0 && it->second->valueType() == _complex) return _complex;
674         }
675     }
676   return _real;
677 }
678 
679 // is scalar if all SuTermMatrix's are scalar matrices
isScalar() const680 bool TermMatrix::isScalar() const
681 {
682     if(suTerms_.size() > 0)
683     {
684       for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)   //travel the map of single unknown matrices
685         {
686           if(it->first.first->nbOfComponents()>1 || it->first.second->nbOfComponents()>1) return false;
687         }
688     }
689   return true;
690 }
691 
692 // TermMatrix and SutermMatrix's computed state = true or false
markAsComputed(bool c)693 void TermMatrix::markAsComputed(bool c)
694 {
695   computingInfo_.isComputed=c;
696   for(it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)  //travel the map of single unknown matrices
697     it->second->computed()=c;
698 }
699 
700 // return factorization type if factorized else return _noFactorization
factorization() const701 FactorizationType TermMatrix::factorization() const
702 {
703   if(scalar_entries_p!=0) return scalar_entries_p->factorization();
704   if(entries_p!=0) return entries_p->factorization();
705   if(suTerms_.size()==1) return suTerms_.begin()->second->factorization();
706   return _noFactorization;
707 }
708 
709 // return set of row/col Unknowns (say v/u unknowns)
rowUnknowns() const710 std::set<const Unknown*> TermMatrix::rowUnknowns() const
711 {
712   std::set<const Unknown*> sun;
713   for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)  //travel the map of single unknown matrices
714     sun.insert(it->first.second);
715   return sun;
716 }
717 
colUnknowns() const718 std::set<const Unknown*> TermMatrix::colUnknowns() const
719 {
720   std::set<const Unknown*> sun;
721   for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)  //travel the map of single unknown matrices
722     sun.insert(it->first.first);
723   return sun;
724 }
725 
726 //! list of involved unknown spaces
unknownSpaces() const727 std::set<const Space*> TermMatrix::unknownSpaces() const
728 {
729   std::set<const Space*> sps;
730   for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)  //travel the map of single unknown matrices
731     {
732       sps.insert(it->first.first->space());
733       sps.insert(it->first.second->space());
734     }
735   return sps;
736 }
737 
738 /*!
739   update the name of a TermMatrix and its SuTermMatrixs
740   SuTermMatrix name is defined as follows: name(TermMatrix)_name(row_Unknown)_name(col_Unknown)
741  */
name(const string_t & nam)742 void TermMatrix::name(const string_t& nam)
743 {
744   name_=nam;
745   for(it_mustm it = begin(); it != end(); it++)  //travel the map of single unknown linear forms
746   {
747     it->second->name() = nam + "_" + it->second->up()->name() + "_" + it->second->vp()->name();
748   }
749 }
750 
751 // return the actual pointer to entries (priority to scalar entry), return 0 is no allocated pointer
actual_entries() const752 MatrixEntry* TermMatrix::actual_entries() const
753 {
754   MatrixEntry* me = scalar_entries_p;
755   if (me != 0) return me;
756   if (suTerms_.size() == 1)
757   {
758     me = firstSut()->scalar_entries();
759     if (me == 0) me = firstSut()->entries();
760   }
761   return me;
762 }
763 
764 /*! return global symmetry property (_noSymmetry, _symmetric, _adjoint, _skewAdjoint, _skewSymmetric)
765     that is same symmetry property of diagonal unknowns blocks it there are no non diagonal blocks
766     if there are non diagonal blocks, their symmetry is not checked (to do later)
767     NOTE : this function works only for allocated SCALAR entries
768 */
symmetry() const769 SymType TermMatrix::symmetry() const
770 {
771   SymType sy=_symmetric;
772   if(suTerms_.size()==0) return sy;
773   bool unset = true;  //symmetry property not set
774   //identify symmetry property from diagonal block
775   for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)  //travel the map of single unknown matrices
776     {
777       const Unknown* u=it->first.first, *v=it->first.second;
778       SuTermMatrix* sut = it->second;
779       if((u==v || u==v->dual_p()))   //block diagonal
780         {
781           if(sut->scalar_entries()!=0)  //priority to scalar entries
782             {
783               if(unset) {sy=sut->scalar_entries()->symmetry(); unset=false;}
784               else if(sut->scalar_entries()->symmetry()!=sy) return _noSymmetry;
785             }
786           else if(sut->entries()!=0)  //matrix of matrices, use entries
787             {
788               if(unset) {sy=sut->entries()->symmetry(); unset=false;}
789               else if(sut->entries()->symmetry()!=sy) return _noSymmetry;
790             }
791         }
792       else return _noSymmetry;  //TermMatrix has non diagonal blocks (symmetry test not yet performed)
793     }
794   return sy;
795 }
796 
797 // number of rows (counted in scalar dof)
numberOfRows() const798 number_t TermMatrix::numberOfRows() const
799 {
800   if(scalar_entries_p!=0) return cdofs_r.size();
801   if(suTerms_.size()==1) return begin()->second->numberOfRows();
802   number_t n=0;
803   std::map<const Unknown*,std::set<number_t> > rowdofs;
804   std::map<const Unknown*,std::set<number_t> >::iterator itr;
805   for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)
806     {
807       const Unknown* v=it->first.second;
808       std::vector<number_t> dofs=it->second->space_vp()->dofIds();
809       itr=rowdofs.find(v);
810       if(itr==rowdofs.end()) rowdofs[v]=std::set<number_t>(dofs.begin(),dofs.end());
811       else  rowdofs[v].insert(dofs.begin(),dofs.end());
812     }
813   for(itr=rowdofs.begin(); itr!=rowdofs.end(); itr++)
814     n+=itr->second.size() * itr->first->nbOfComponents();
815   return n;
816 }
817 
818 // number of columns (counted in scalar dof)
numberOfCols() const819 number_t TermMatrix::numberOfCols() const
820 {
821   if(scalar_entries_p!=0) return cdofs_c.size();
822   if(suTerms_.size()==1) return begin()->second->numberOfCols();
823   number_t n=0;
824   std::map<const Unknown*,std::set<number_t> > coldofs;
825   std::map<const Unknown*,std::set<number_t> >::iterator itc;
826   for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)
827     {
828       const Unknown* u=it->first.first;
829       std::vector<number_t> dofs=it->second->space_up()->dofIds();
830       itc=coldofs.find(u);
831       if(itc==coldofs.end()) coldofs[u]=std::set<number_t>(dofs.begin(),dofs.end());
832       else  coldofs[u].insert(dofs.begin(),dofs.end());
833     }
834   for(itc=coldofs.begin(); itc!=coldofs.end(); itc++)
835     n+=itc->second.size() * itc->first->nbOfComponents();
836   return n;
837 }
838 
nnz() const839 number_t TermMatrix::nnz() const
840 {
841   if (scalar_entries_p != 0) return scalar_entries_p->size();
842   if (entries_p != 0) return entries_p->scalarSize();
843   number_t n=0;
844   for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)
845     n+=it->second->nnz();
846   return n;
847 }
848 
849 // -----------------------------------------------------------------------------------------------------------
850 // access to matrix element
851 // -----------------------------------------------------------------------------------------------------------
852 
853 //access to single unknown term matrix (internal use)
subMatrix(const Unknown * up,const Unknown * vp)854 SuTermMatrix& TermMatrix::subMatrix(const Unknown* up, const Unknown* vp)
855 {
856   if (up == 0)
857   {
858     where("TermMatrix::subMatrix(Unknown*, Unknown*)");
859     error("termmatrix_submatrix_not_found", "up=0");
860   }
861   if (vp == 0)
862   {
863     where("TermMatrix::subMatrix(Unknown*, Unknown*)");
864     error("termmatrix_submatrix_not_found", "vp=0");
865   }
866   uvPair uv(up, vp);
867   it_mustm it = suTerms_.find(uv);
868   if (it == suTerms_.end())
869   {
870     where("TermMatrix::subMatrix(Unknown*, Unknown*)");
871     error("termmatrix_submatrix_not_found", "(" + up->name() + " " + vp->name() + ")");
872   }
873   return *(it->second);
874 }
875 
subMatrix(const Unknown * up,const Unknown * vp) const876 const SuTermMatrix& TermMatrix::subMatrix(const Unknown* up, const Unknown* vp) const
877 {
878   if (up == 0)
879   {
880     where("TermMatrix::subMatrix(Unknown*, Unknown*) const");
881     error("termmatrix_submatrix_not_found", "up=0");
882   }
883   if (vp == 0)
884   {
885 
886     where("TermMatrix::subMatrix(Unknown*, Unknown*) const");
887     error("termmatrix_submatrix_not_found", "vp=0");
888   }
889   uvPair uv(up, vp);
890   cit_mustm it = suTerms_.find(uv);
891   if (it == suTerms_.end())
892   {
893     where("TermMatrix::subMatrix(Unknown*, Unknown*) const");
894     error("termmatrix_submatrix_not_found", "(" + up->name() + " " + vp->name() + ")");
895   }
896   return *(it->second);
897 }
898 
899 //access to single unknown term matrix (internal use)
subMatrix_p(const Unknown * up,const Unknown * vp)900 SuTermMatrix* TermMatrix::subMatrix_p(const Unknown* up, const Unknown* vp)
901 {
902   if (up == 0)
903   {
904     where("TermMatrix::subMatrix_p(Unknown*, Unknown*)");
905     error("termmatrix_submatrix_not_found", "up=0");
906   }
907   if (vp == 0)
908   {
909     where("TermMatrix::subMatrix_p(Unknown*, Unknown*)");
910     error("termmatrix_submatrix_not_found", "vp=0");
911   }
912   uvPair uv(up, vp);
913   it_mustm it = suTerms_.find(uv);
914   if(it != suTerms_.end()) return it->second;
915   return 0;
916 }
subMatrix_p(const Unknown * up,const Unknown * vp) const917 const SuTermMatrix* TermMatrix::subMatrix_p(const Unknown* up, const Unknown* vp) const
918 {
919   if (up == 0)
920   {
921     where("TermMatrix::subMatrix_p(Unknown*, Unknown*) const");
922     error("termmatrix_submatrix_not_found", "up=0");
923   }
924   if (vp == 0)
925   {
926     where("TermMatrix::subMatrix_p(Unknown*, Unknown*) const");
927     error("termmatrix_submatrix_not_found", "vp=0");
928   }
929   uvPair uv(up, vp);
930   cit_mustm it = suTerms_.find(uv);
931   if(it != suTerms_.end()) return it->second;
932   return 0;
933 }
934 
935 /*!return single unknown term matrix as TermMatrix (copy constructor like),
936    useful to extract single unknown term from multiple unknowns term
937    induce a full copy !!!
938 */
operator ()(const Unknown & u,const Unknown & v) const939 TermMatrix TermMatrix::operator()(const Unknown& u, const Unknown& v) const
940 {
941   const SuTermMatrix& sut = this->subMatrix(&u, &v);
942   //create a new single unknown TermVector
943   string_t na = name_ + "_" + u.name() + "_" + v.name();
944   BilinearForm blf(*sut.sublf_p);                         //linear form from single unknown linear form
945   TermMatrix tm(blf, na, sut.computingInfo_.noAssembly);  //create new TermMatrix
946   SuTermMatrix& tmsu = *tm.suTerms_.begin()->second;
947   tmsu.entries_p=0;
948   if(sut.entries_p!=0)   //suTermMatrix is computed
949     {
950       tmsu.entries_p = new MatrixEntry(*sut.entries_p);       //copy MatrixEntries
951       tmsu.computed()=true;
952       tm.computed()=true;
953     }
954   tm.entries_p = tmsu.entries_p;                          //update MatrixEntry pointer of TermMatrix
955   return tm;
956 }
957 
958 // return the i-th row or col as a TermVector (r=1,...)
959 // restrict to single unknown TermMatrix or multiple unknown TermMatrix having global representation
getRowCol(number_t i,AccessType at,TermVector & R) const960 TermVector& TermMatrix::getRowCol(number_t i, AccessType at, TermVector& R) const
961 {
962   bool single=isSingleUnknown();
963   if (!single && scalar_entries_p==0 && entries_p==0)
964   {
965     where("TermMatrix::getRowCol(Nuber, AccessType, TermVector");
966     error("term_not_global_rep", name());
967   }
968 
969   //initTermVector(R,valueType(),at==_col);
970   initTermVector(R,valueType(),at==_row);  // init using row unknown if at=col and col unknown if at=row
971   //retry matrix pointer
972   MatrixEntry* mat=scalar_entries_p;
973   bool scal = true;
974   if (single && suTerms_.size()==1)
975   {
976     mat = suTerms_.begin()->second->scalar_entries();
977     if (mat==0) {mat = suTerms_.begin()->second->entries(); scal=false;}
978 
979   }
980   else if (mat==0) {mat=entries_p; scal=false;}
981   if (mat==0)
982   {
983     where("TermMatrix::getRowCol(Nuber, AccessType, TermVector");
984     error("term_no_entries");
985   }
986 
987   number_t nbrc = mat->nbOfRows();
988   if (at==_col) nbrc = mat->nbOfCols();
989   if (i<1 || i>nbrc)
990   {
991     where("TermMatrix::getRowCol(Nuber, AccessType, TermVector");
992     error("index_out_of_range",i, 1, nbrc);
993   }
994 
995   VectorEntry vr = mat->getRowCol(i,at);
996   if (single)
997   {
998     if (scal) R.firstSut()->scalar_entries() = new VectorEntry(vr);
999     else R.firstSut()->entries() = new VectorEntry(vr);
1000   }
1001   else
1002   {
1003     if (scal) R.scalar_entries() = new VectorEntry(vr);
1004     else R.entries() = new VectorEntry(vr);
1005   }
1006   return R;
1007 }
1008 
row(number_t r) const1009 TermVector TermMatrix::row(number_t r) const
1010 {
1011   TermVector R;
1012   return getRowCol(r,_row, R);
1013 }
1014 
column(number_t c) const1015 TermVector TermMatrix::column(number_t c) const
1016 {
1017   TermVector C;
1018   return getRowCol(c,_col, C);
1019 }
1020 
1021 //initialize a TermVector consistent with matrix column unknown (col=true), with matrix row unknown (col=false)
initTermVector(TermVector & tv,ValueType vt,bool col) const1022 void TermMatrix::initTermVector(TermVector& tv, ValueType vt, bool col) const
1023 {
1024   string_t na = tv.name(); //preserving only name
1025   tv.clear();
1026   tv.name() = na;
1027   //make list of row unknowns
1028   std::map<const Unknown*, SuTermMatrix*> terms;
1029   for(cit_mustm itA = begin(); itA != end(); itA++)
1030     {
1031       const Unknown* u;
1032       if(col) u = itA->first.first;
1033       else    u = itA->first.second;
1034       SuTermMatrix* Auv = itA->second;
1035       if(terms.find(u) == terms.end()) terms[u] = Auv;
1036       else //update terms if u-space is larger than previous one
1037         {
1038           if(terms[u]->space_up()->dimSpace() < Auv->space_up()->dimSpace()) terms[u] = Auv;
1039           //to be improved : determine the largest space
1040         }
1041     }
1042   std::map<const Unknown*, SuTermMatrix*>::iterator it;
1043   for(it = terms.begin(); it != terms.end(); it++)
1044     {
1045       const Unknown* u = it->first;
1046       SuTermMatrix* sut = it->second;
1047       dimen_t nv = u->nbOfComponents();
1048       Space* sp = sut->space_up();
1049       if(!col) sp = sut->space_vp();
1050       number_t n = sp->dimSpace();
1051       SuTermVector* sutX = new SuTermVector("", u, sp, vt, n, nv);
1052       sutX->computed()=true;
1053       tv.insert(u, sutX);
1054     }
1055   tv.computed() = true;
1056 }
1057 
1058 // -----------------------------------------------------------------------------------------------------------
1059 // compute the matrix term from bilinear form
1060 // -----------------------------------------------------------------------------------------------------------
compute()1061 void TermMatrix::compute()
1062 {
1063   if (computed()) return;  //already computed
1064   trace_p->push("TermMatrix::compute()");
1065   //compute each block
1066   for (it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)  //travel the map of single unknown linear forms
1067     { it->second->compute(); }
1068   /* merge blocks
1069     to avoid complexity and efficiency lost in elementary computation, some blocks have to be merged after
1070     this is the case when a block has a component of unknown (say u_1) and an other block refers to u
1071     we have to merge them using the mergeBlocks function
1072   */
1073   mergeBlocks();
1074 
1075   if (constraints_u_p==0 && constraints_v_p==0)
1076   {
1077     computed() = true;
1078     if(theVerboseLevel>0) printSummary(std::cout);
1079     trace_p->pop();
1080     return;
1081   }
1082 
1083   /* deal with essential conditions (constraints data)
1084      first, we have to move the matrix into scalar representation if there are some vector unknowns
1085      and may be to global scalar representation if there are some coupled unknowns condition
1086      then four methods are handled :
1087       - pseudo reduction : replace some matrix coefficients, see pseudoReduction function for details
1088       - real reduction : remove some matrix coefficients, see realReduction function for details (storage is modified)
1089       - penalisation : add large coefficients to some matrix coefficients, see penalizationReduction function for details
1090       - duality : introduce new dual unknown in matrix, see dualReduction function for details
1091   */
1092   if (computingInfo_.reductionMethod.method!=_pseudoReduction)
1093     error("reduction_method_not_handled", words("reduction method",computingInfo_.reductionMethod.method));
1094   bool global=false;
1095 
1096   //basic consistancy tests
1097   if (constraints_u_p!=0)
1098   {
1099     if (constraints_u_p->size()==0) error("is_void","SetOfConstraints");
1100     if (constraints_u_p->begin()->second==0) error("null_pointer","constraints_u_p");
1101     global=constraints_u_p->isGlobal();
1102   }
1103   if (constraints_v_p!=0)
1104   {
1105     if (constraints_v_p->size()==0) error("is_void","SetOfConstraints");
1106     if (constraints_v_p->begin()->second==0) error("null_pointer","constraints_v_p");
1107     if (!global) global=constraints_u_p->isGlobal();
1108   }
1109 
1110   //convert matrix to scalar representation and to global if constraints are global
1111   if (global) toGlobal(storageType(), storageAccess(), _noSymmetry, true);   //go to global scalar representation
1112   else toScalar();        //go to scalar representation
1113 
1114   switch (computingInfo_.reductionMethod.method)
1115   {
1116     case _noReduction              :  break;
1117     case _pseudoReduction          :  pseudoReduction(); break;
1118     // case _realReduction         : realReduction(); trace_p->pop(); break;
1119     // case _penalizationReduction : penalizationReduction(); trace_p->pop(); break;
1120     // case _dualReduction         : dualReduction(); trace_p->pop(); break;
1121     default :
1122       error("reduction_method_not_handled", words("reduction method",computingInfo_.reductionMethod.method));
1123   }
1124 
1125   computed() = true;
1126   if (theVerboseLevel>0)
1127    {
1128       printSummary(std::cout);
1129       if (theCout.traceOnFile)  printSummary(theCout.printStream->currentStream());
1130    }
1131   trace_p->pop();
1132 }
1133 
1134 // -----------------------------------------------------------------------------------------------------------
1135 // merge blocks referring to same vector unknown
1136 //   - when a block has a component of unknown as row or col unknown, it is convert to its vector representation
1137 //   - when some blocks have different components of same unknown as row or col unknown, the blocks are really merged
1138 //     into a block with vector unknowns
1139 // see the function mergeSuTermMatrix
1140 // -----------------------------------------------------------------------------------------------------------
mergeBlocks()1141 void TermMatrix::mergeBlocks()
1142 {
1143   trace_p->push("TermMatrix::mergeBlocks()");
1144   std::map<uvPair, std::list<SuTermMatrix*> > suts; //to collect block by vector unknowns
1145   std::map<uvPair, std::list<SuTermMatrix*> >::iterator itm;
1146   bool mergeFlag=false;
1147   for(it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)  //travel the map of single unknown SuTermMatrix
1148     {
1149       SuTermMatrix* sut=it->second;
1150       const Unknown* up=sut->up(), *vp=sut->vp();
1151       if(up->isComponent()) {up=up->parent(); mergeFlag=true;}
1152       if(vp->isComponent()) {vp=vp->parent(); mergeFlag=true;}
1153       itm=suts.find(uvPair(up,vp));
1154       if(itm!=suts.end()) itm->second.push_back(sut);
1155       else suts[uvPair(up,vp)]=std::list<SuTermMatrix*>(1,sut);
1156     }
1157   if(!mergeFlag) {trace_p->pop(); return;}   //nothing to merge
1158 
1159   //now merge each collected block
1160   for(itm=suts.begin(); itm!=suts.end(); itm++)
1161     {
1162       std::list<SuTermMatrix*>::iterator itl;
1163       std::vector<uvPair> uvel(itm->second.size());
1164       std::vector<uvPair>::iterator ituv=uvel.begin();
1165       for(itl=itm->second.begin(); itl!=itm->second.end(); itl++,ituv++)  //memorize uv pairs
1166         *ituv= uvPair((*itl)->up(),(*itl)->vp());
1167       SuTermMatrix* msut=mergeSuTermMatrix(itm->second);   //merge blocks, NO DELETION
1168       if(msut!=0)  //real merging
1169         {
1170           std::list<SuTermMatrix*>::iterator itl;
1171           ituv=uvel.begin();
1172           for(itl=itm->second.begin(); itl!=itm->second.end(); itl++, ituv++)  //delete old SuTermMatrix's
1173             {
1174               suTerms_.erase(*ituv);
1175               delete *itl;
1176             }
1177           suTerms_[itm->first]=msut;  //assign the merged SuTermMatrix
1178         }
1179     }
1180 
1181   trace_p->pop();
1182 }
1183 
1184 // -----------------------------------------------------------------------------------------------------------
1185 // deal with essential condition (constraints)
1186 // -----------------------------------------------------------------------------------------------------------
1187 
1188 /*!
1189   perform pseudo reduction of reduced essential conditions in a matrix. Essential conditions have the following form  :
1190                           U_E + F*U_R = s   for column unknown U
1191                           V_E + G*V_R = 0   for row test function V (generally related to unknown U)
1192   where E are the eliminated unknown/test function indices and R are the reduced unknown/test function indices
1193   The pseudo reduction of matrix consists in
1194     - modifying column A.j for j in R by adding -Fjk*A.k for k in E and replacing column A.k for k in E by a 0 column
1195     - modifying row Ai. for i in R by adding -Gik*Ak. for k in E and replacing row Ak. for k in E by a 0 row
1196     - if eliminated v unknowns are dual of eliminated u unknowns, the VE rows are replaced by the equation (or a part of)
1197                                       U_E + F*U_R = s
1198   to delay the right hand side modification, the (A.k) columns (k in E) are stored in a new structure
1199 
1200   At the end of the process, the eliminated system looks like
1201                    U_E     U_R    U_S       RHS
1202                  ----------------------   ------
1203                  |      |       |     |   |    |
1204             V_E  |  Id  |   F   |  0  |   |  S |
1205                  |      |       |     |   |    |
1206                  ---------------------    -----
1207                  |      |       |     |   |    |
1208             V_R  |  0   |  ARR  | ARS |   | FR |
1209                  |      |       |     |   |    |
1210                  ----------------------   ------
1211                  |      |       |     |   |    |
1212             V_S  |  0   |  ASR  | ASS |   | FS |
1213                  |      |       |     |   |    |
1214                  ----------------------   ------
1215 
1216   In some cases (F=G=0 or local conditions u^n=g, ...) the storage is not modified but in other cases (transmission condition for instance)
1217   the storage is modified
1218 
1219 */
pseudoReduction()1220 void TermMatrix::pseudoReduction()
1221 {
1222   trace_p->push("TermMatrix::pseudoReduction()");
1223   if (constraints_u_p == 0 && constraints_v_p ==0)   //no essential condition
1224     {
1225       warning("free_warning", " in TermMatrix::pseudoReduction, no essential conditions to deal with");
1226       return;
1227     }
1228 
1229   bool global = false;
1230   complex_t alpha=computingInfo().reductionMethod.alpha;
1231   if(constraints_u_p != 0 && constraints_u_p->isGlobal()) global=true;
1232   else if(constraints_v_p != 0 && constraints_v_p->isGlobal()) global=true;
1233   Constraints* cons_u=0, *cons_v=0;
1234 
1235   if(global)  //global reduction
1236     {
1237       //modify matrix storage and symmetry
1238       if(constraints_u_p != 0) cons_u=(*constraints_u_p)(0);
1239       if(constraints_v_p != 0) cons_v=(*constraints_v_p)(0);
1240       if(scalar_entries_p->symmetry()!=_noSymmetry && constraints_u_p != constraints_v_p) scalar_entries_p->toUnsymmetric(_sym);
1241       extendStorage(scalar_entries_p, cdofs_r, cdofs_c, cons_u, cons_v);  //extend storage if required
1242       if(cons_u!=0)  cons_u->pseudoColReduction(scalar_entries_p, cdofs_r, cdofs_c, rhs_matrix_p);
1243       else error("global_sub_reduction_not_yet_handled", words("column"));
1244       //if (cons_v!=0 && scalar_entries_p->symmetry()==_noSymmetry) //row reduction
1245       if(cons_v!=0)  //row reduction
1246         cons_v->pseudoRowReduction(scalar_entries_p, cdofs_r, cdofs_c, alpha);
1247       else if(constraints_v_p!=0 && cons_v==0)
1248         error("global_sub_reduction_not_yet_handled", words("row"));
1249     }
1250   else //sub reduction (i.e on SuTermMatrix's)
1251     {
1252       for(it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)
1253         {
1254           SuTermMatrix* sutm=it->second;
1255           const Unknown* u=it->first.first, *v=it->first.second;
1256           Constraints* cons_u = (*constraints_u_p)(u), *cons_v = 0;
1257           if(constraints_v_p ==0) cons_v = (*constraints_v_p)(v->dual_p());
1258           if(cons_v == 0) cons_v = (*constraints_v_p)(v->dual_p());  //try with dual unknown
1259           MatrixEntry* submat=sutm->scalar_entries_p;
1260           if(submat->symmetry()!=_noSymmetry && cons_u != cons_v)  submat->toUnsymmetric(_sym);  //goto non symmetric matrix stored with a symmetric storage
1261           extendStorage(submat, sutm->cdofs_v, sutm->cdofs_u, cons_u, cons_v);                  //extend storage if required
1262           if(cons_u!=0)   //col reduction
1263             cons_u->pseudoColReduction(submat, sutm->cdofs_v, sutm->cdofs_u, sutm->rhs_matrix_p);
1264           //if (cons_v!=0 && submat->symmetry()==_noSymmetry)  //row reduction
1265           if(cons_v!=0)   //row reduction
1266             cons_v->pseudoRowReduction(submat, sutm->cdofs_v, sutm->cdofs_u, alpha);
1267         }
1268     }
1269   trace_p->pop();
1270 }
1271 
1272 // -----------------------------------------------------------------------------------------------------------
1273 // change representation of matrix (entries and storage)
1274 // -----------------------------------------------------------------------------------------------------------
1275 /*! regarding a multiple unknowns TermMatrix, suggest a storage according to the following rules:
1276       if dense part > 10*(cs part+skyline part) -> dense storage  else -> cs storage
1277       if umfpack installed -> column access else dual row/col access
1278       if matrix has symmetry -> symmetric access */
findGlobalStorageType() const1279 std::pair<StorageType,AccessType> TermMatrix::findGlobalStorageType() const
1280 {
1281   number_t densePart=0, csPart=0, skyPart=0;
1282   number_t denseFull = numberOfRows()*numberOfCols();
1283   StorageType st=_noStorage; AccessType at=_noAccess;
1284   for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)
1285     {
1286       StorageType sts=it->second->storageType();
1287       number_t s = it->second->nnz();
1288       if(sts==_dense) densePart+=s;
1289       if(sts==_cs) csPart+=s;
1290       if(sts==_skyline) skyPart+=s;
1291     }
1292   at=_dual;
1293   //if(densePart > 10*(csPart+skyPart)) {st=_dense; at=_row;}
1294   if(4*densePart > denseFull) {st=_dense; at=_row;}  //dense part represents 25% of the matrix, choose dense
1295   else
1296     {
1297       st=_cs;
1298 #ifdef XLIFEPP_WITH_UMFPACK
1299       at=_col;     //well adapted to umfpack
1300 #endif
1301     }
1302 
1303   //if(symmetry()!=_noSymmetry) at=_sym;     //raises a bug in toglobal, sym -> sym
1304   return std::make_pair(st,at);
1305 }
1306 
toSkyline()1307 void TermMatrix::toSkyline()
1308 {
1309   trace_p->push("TermMatrix::toSkyline()");
1310   if(!computed()) error("not_computed_term", name());
1311   if(isSingleUnknown())
1312     {
1313       SuTermMatrix* sutm = begin()->second;
1314       if(sutm->entries()->storageType() == _skyline)
1315         {
1316           warning("free_warning", "TermMatrix" + name() + " is already a skyline matrix, nothing to do!");
1317           trace_p->pop();
1318           return;
1319         }
1320       if(sutm->entries()->storageType() == _dense)
1321         error("storage_not_implemented", "TermMatrix::toSkyline", words("storage type",_dense));
1322       if(sutm->entries()->storageType() == _cs) sutm->entries()->toSkyline();  //convert entries to skyline storage
1323     }
1324   else
1325     {
1326       error("block_conversion_not_yet_implemented", words("storage type",_skyline));
1327     }
1328   trace_p->pop();
1329 }
1330 
1331 /*! create scalar representation of TermMatrix
1332     for each SuTermMatrix (if computed, entries_!=0), if not exists create its scalar representation (set scalar_entries_p and cdofs vectors)
1333       if SuTermMatrix is already scalar, scalar_entries_p = entries_p
1334     NOTE : scalar_entries_p of TermMatrix is not update by this function (see toGlobal function)
1335 
1336 */
toScalar(bool keepEntries)1337 void TermMatrix::toScalar(bool keepEntries)
1338 {
1339   trace_p->push("TermMatrix::toScalar()");
1340   for(it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++) it->second->toScalar(keepEntries);
1341   trace_p->pop();
1342 }
1343 
1344 /*! create scalar global representation of TermMatrix
1345     make scalar representations of SuTermMatrix's if not exist and merge it in a scalar global representation by allocating
1346     scalar_entries_p and setting the cdofs vectors
1347 
1348     st, at : storage and access type of global matrix, if st = _nosStorage try to identify "best" storage
1349     symt   : to force symmetry of matrix (default = _noSymmetry)
1350     keepSuterms : if false (default value), SutermMatrix entries are deleted
1351 */
toGlobal(StorageType st,AccessType at,SymType symt,bool keepSuTerms)1352 void TermMatrix::toGlobal(StorageType st, AccessType at, SymType symt, bool keepSuTerms)
1353 {
1354   if (scalar_entries_p!=0) return;  //already done, delete it outside if you want to rebuild
1355   trace_p->push("TermMatrix::toGlobal()");
1356 
1357   //create scalar representation
1358   toScalar();   //nothing is done if SuTermMatrix's already scalar !
1359 
1360   //cpuTime("toGlobal:toScalar");
1361   if (suTerms_.size()==1) {trace_p->pop(); return;}  //nothing to merge
1362 
1363   //cpuTime("toGlobal:enter to");
1364   //merge all SutermMatrix's
1365   // compare row and col unknowns
1366   bool sameRowColUnknowns = true;
1367   std::set<const Unknown*> vs=rowUnknowns(), us=colUnknowns();
1368   std::set<const Unknown*>::iterator itvs=vs.begin(), itus;
1369   if (us.size()!=vs.size()) sameRowColUnknowns = false;
1370   else
1371     for (; itvs!=vs.end() && sameRowColUnknowns; itvs++)
1372     {
1373       itus=us.find(*itvs);
1374       if (itus==us.end()) itus=us.find((*itvs)->dual_p());
1375       if (itus==us.end()) sameRowColUnknowns=false;
1376     }
1377 
1378   if (!sameRowColUnknowns && symt!=_noSymmetry) error("symmetry_not_handled", words("symmetry", symt));
1379 
1380   //try to find storage type if not set (has to be improved)
1381   if (st==_noStorage)
1382   {
1383     std::pair<StorageType,AccessType> stat=findGlobalStorageType();
1384     st=stat.first; at=stat.second;
1385   }
1386 
1387   //create numbering of blocks in global numbering (row and size)
1388   std::map<const Unknown*, std::list<SuTermMatrix*> > rowsut, colsut;  //list of SuTermMatrix by row/col unknown
1389   std::map<SuTermMatrix*, std::vector<number_t> > rownum, colnum;      //block row/col numbering map for each SuTermMatrix
1390   ValueType vt=_real;
1391   for (it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)
1392   {
1393     SuTermMatrix* sut= it->second;
1394     rowsut[it->first.second].push_back(sut);
1395     colsut[it->first.first].push_back(sut);
1396     if(sut->scalar_entries_p->valueType_ ==_complex) vt=_complex;
1397   }
1398   mergeNumberingFast(rowsut, rownum, cdofs_r,_row);
1399   mergeNumberingFast(colsut, colnum, cdofs_c,_col);
1400   //cpuTime("toGlobal:mergeNumbering");
1401 
1402   //buiding row indices of global matrix and calling buildstorage
1403   MatrixStorage* ms=0;
1404   if (st!=_dense)   //update storage pointer
1405   {
1406     std::vector<std::set<number_t> > indices(cdofs_r.size());  //col indices by row
1407     for (it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)
1408     {
1409       SuTermMatrix* sut= it->second;
1410       MatrixStorage* msu=sut->scalarStoragep();
1411       std::vector<number_t>& rowmap=rownum[sut];
1412       std::vector<number_t>& colmap=colnum[sut];
1413       addIndices(indices, msu, rowmap, colmap);
1414     }
1415     //cpuTime("toGlobal:prepare buildstorage");
1416     ms=buildStorage(st,at,cdofs_r.size(), cdofs_c.size(),indices);
1417     //cpuTime("toGlobal:buildstorage");
1418   }
1419   else ms=buildStorage(st,at,cdofs_r.size(), cdofs_c.size());
1420 
1421   //cpuTime("toGlobal:create_storage");
1422   scalar_entries_p=new MatrixEntry(vt, _scalar, ms, dimPair(1,1), symt);
1423   //merge SutermMatrix's
1424   for (it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)
1425   {
1426     SuTermMatrix* sut= it->second;
1427     scalar_entries_p->assign(*sut->scalar_entries_p, rownum[sut], colnum[sut]);
1428   }
1429   //cpuTime("toGlobal:merge_submatrices "+tostring(suTerms_.size()));
1430 
1431   if (!keepSuTerms)   //clear SuTermMatrix's
1432     for (it_mustm it = suTerms_.begin(); it != suTerms_.end(); it++) it->second->clear();
1433 
1434   if (theVerboseLevel>0)
1435      theCout<<"multiple unknown TermMatrix "<<name()<<" moves to global representation : "
1436             << words("value",scalar_entries_p->valueType())<<" scalar matrix "<<numberOfRows()<< " X "<<numberOfCols()
1437             <<" in "<<scalar_entries_p->storagep()->name()<<" ("<< scalar_entries_p->storagep()->size()<<" coefficients)"<< eol;
1438   trace_p->pop();
1439 }
1440 
1441 // Turns to scalar representation in case of multiple unknowns and returns pointer to data held in the matrix
matrixData()1442 MatrixEntry* TermMatrix::matrixData() {
1443   MatrixEntry* matA=0;
1444 
1445   if (isSingleUnknown()) {
1446     SuTermMatrix* sutmA = begin()->second;
1447     if (sutmA->space_up() != sutmA->space_vp())
1448       error("term_inconsistent_unknown_spaces", name());
1449     matA = sutmA->entries();
1450     if (sutmA->scalar_entries()!=0) matA= sutmA->scalar_entries();
1451   }
1452   else {  //multiple unknowns (goto scalar global representation)
1453     SymType syA=symmetry();  //detect global symmetry of TermMatrix
1454     if (entries()==0 && scalar_entries()==0) toGlobal(storageType(), storageAccess(), syA, true);
1455     else if (scalar_entries()==0) toScalar(false);
1456     matA = scalar_entries();
1457   }
1458   return matA;
1459 }
1460 
1461 //toGlobal tool : add col indices of a matrix storage to current set of col indices with index mapping
addIndices(std::vector<std::set<number_t>> & indices,MatrixStorage * msu,const std::vector<number_t> & rowmap,const std::vector<number_t> & colmap)1462 void TermMatrix::addIndices(std::vector<std::set<number_t> >& indices, MatrixStorage* msu,
1463                             const std::vector<number_t>& rowmap, const std::vector<number_t>& colmap)
1464 {
1465   std::vector<number_t>::const_iterator itrc;
1466   std::set<number_t>::iterator its;
1467   number_t k=1, shr=0, shc=0, nbc=msu->nbOfColumns(), nbr=msu->nbOfRows(), m;
1468   AccessType msuat=msu->accessType();
1469   if(rowmap.size()==1) shr=rowmap[0];
1470   if(colmap.size()==1) shc=colmap[0];
1471 
1472   if(msuat==_row || msuat==_dual || msuat==_sym)   //row in row
1473     {
1474       m = nbc;
1475       for(k=1; k<=nbr; ++k)
1476         {
1477           if(msuat!=_row) m=k;    //restrict to lower part
1478           std::set<number_t> cols=msu->getCols(k,1,m);      // retry col indices of row k in ms storage
1479           std::set<number_t>* indr=&indices[k+shr-1];
1480           if(rowmap.size()>1) indr=&indices[rowmap[k-1]-1];
1481           if(colmap.size()==1)
1482             {
1483               if(shc==0) indr->insert(cols.begin(), cols.end());
1484               else
1485                 for(its=cols.begin(); its!=cols.end(); ++its)  indr->insert((*its)+shc);     // insert col numbering shift
1486             }
1487           else
1488             for(its=cols.begin(); its!=cols.end(); ++its)  indr->insert(colmap[(*its)-1]);  // insert col numbering map
1489         }
1490     }
1491   if(msuat==_col || msuat==_dual || msuat==_sym)   //col in row
1492     {
1493       m = nbr;
1494       number_t d=2;
1495       if(msuat==_col) d=1;
1496       for(k=d; k<=nbc; ++k)
1497         {
1498           number_t c=k+shc;
1499           if(colmap.size()>1) c=colmap[k-1];
1500           if(msuat!=_col) m=k-1;   // restrict to upper part, diag term has been already taken into account
1501           std::set<number_t> rows=msu->getRows(k,1,m);    // retry row indices of col k in msu storage
1502           if(rowmap.size()==1)
1503             for(its=rows.begin(); its!=rows.end(); ++its)  indices[(*its)+shr-1].insert(c);   // insert col numbering map
1504           else
1505             for(its=rows.begin(); its!=rows.end(); ++its)  indices[rowmap[(*its)-1]-1].insert(c);  // insert col numbering map
1506         }
1507     }
1508 }
1509 
1510 //tool for TermMatrix::toGlobal function
1511 //  create the list of merged row/col dofs
1512 //  and for each SuTermMatrix the map between is row/col numbering and the global row/col numbering
mergeNumbering(std::map<const Unknown *,std::list<SuTermMatrix * >> & rcsut,std::map<SuTermMatrix *,std::vector<number_t>> & rcnum,std::vector<DofComponent> & rcdof,AccessType rc)1513 void TermMatrix::mergeNumbering(std::map<const Unknown*, std::list<SuTermMatrix*> >& rcsut,
1514                                 std::map<SuTermMatrix*, std::vector<number_t > >& rcnum,
1515                                 std::vector<DofComponent>& rcdof, AccessType rc)
1516 {
1517   //order unknowns according to their ranks
1518   std::map<const Unknown*, std::list<SuTermMatrix*> >::iterator itmus;
1519   std::map<number_t,const Unknown*> order;
1520   for(itmus=rcsut.begin(); itmus!=rcsut.end(); itmus++)
1521     {
1522       const Unknown* u=itmus->first;
1523       number_t r=u->rank();
1524       if(order.find(r)==order.end()) order.insert(std::make_pair(r,u));
1525     }
1526   //merge global numbering
1527   std::vector<DofComponent>::iterator itd;
1528   std::map<number_t,const Unknown*>::iterator itmnu;
1529   for(itmnu=order.begin(); itmnu!=order.end(); itmnu++)
1530     {
1531       const Unknown* u=itmnu->second;
1532       std::list<SuTermMatrix* >::iterator itl=rcsut[u].begin(), itle=rcsut[u].end();
1533       if(rcsut[u].size()==1)  //simple case only one SutermMatrix
1534         {
1535           SuTermMatrix* sut = *itl;
1536           std::vector<DofComponent>* cd=&sut->cdofsu();
1537           if(rc==_row) cd=&sut->cdofsv();
1538           number_t nbr=cd->size();
1539           rcnum[sut]=trivialNumbering<number_t>(rcdof.size()+1,rcdof.size()+nbr);
1540           rcdof.insert(rcdof.end(),cd->begin(),cd->end());
1541         }
1542       else //merge local numbering
1543         {
1544           std::map<DofComponent, number_t> dofmap;
1545           std::map<DofComponent, number_t>::iterator itmc;
1546           number_t ld=rcdof.size();
1547           for(; itl!=itle; itl++)  //travel SuTermMatrix list
1548             {
1549               SuTermMatrix* sut = *itl;
1550               std::vector<DofComponent>* cd=&sut->cdofsu();
1551               if(rc==_row) cd=&sut->cdofsv();
1552               number_t nbcd=cd->size();
1553               std::vector<DofComponent> locd(nbcd);
1554               std::vector<number_t >& num = rcnum[sut];
1555               num.resize(nbcd);
1556               std::vector<number_t >::iterator itc=num.begin();
1557               number_t k=0;
1558               for(itd=cd->begin(); itd!=cd->end(); itd++, itc++)
1559                 {
1560                   itmc=dofmap.find(*itd);
1561                   if(itmc==dofmap.end())
1562                     {
1563                       ld++;            //increase global dof index
1564                       dofmap[*itd]=ld; //update dofmap
1565                       *itc=ld;         //update local->global numbering
1566                       locd[k]=*itd;    //update local cdof
1567                       k++;
1568                     }
1569                   else *itc=itmc->second;
1570                 }
1571               locd.resize(k);
1572               rcdof.insert(rcdof.end(),locd.begin(),locd.end());
1573             }
1574         }
1575     }
1576 }
1577 
1578 //tool for TermMatrix::toGlobal function, fast version
1579 //  create the list of merged row/col dofs
1580 //  and for each SuTermMatrix the map between is row/col numbering and the global row/col numbering
1581 //  trivial list n->n+p are encoded only using the shift n : rcnum[sut]=[n]
mergeNumberingFast(std::map<const Unknown *,std::list<SuTermMatrix * >> & rcsut,std::map<SuTermMatrix *,std::vector<number_t>> & rcnum,std::vector<DofComponent> & rcdof,AccessType rc)1582 void TermMatrix::mergeNumberingFast(std::map<const Unknown*, std::list<SuTermMatrix*> >& rcsut,
1583                                     std::map<SuTermMatrix*, std::vector<number_t > >& rcnum,
1584                                     std::vector<DofComponent>& rcdof, AccessType rc)
1585 {
1586   //order unknowns according to their ranks
1587   std::map<const Unknown*, std::list<SuTermMatrix*> >::iterator itmus;
1588   std::map<number_t,const Unknown*> order;
1589   for(itmus=rcsut.begin(); itmus!=rcsut.end(); itmus++)
1590     {
1591       const Unknown* u=itmus->first;
1592       number_t r=u->rank();
1593       if(order.find(r)==order.end()) order.insert(std::make_pair(r,u));
1594     }
1595   //merge global numbering
1596   std::vector<DofComponent>::iterator itd;
1597   std::map<number_t,const Unknown*>::iterator itmnu;
1598   for(itmnu=order.begin(); itmnu!=order.end(); itmnu++)
1599     {
1600       const Unknown* u=itmnu->second;
1601       //order u-SuTermMatrix's by their row/col sizes largest to smallest
1602       std::vector<SuTermMatrix*> ordsut(rcsut[u].begin(),rcsut[u].end());
1603       //std::sort(ordsut.begin(),ordsut.end(),compNnzSutermMatrix);     //rearrange from the largest to the smallest SuTermMatrix
1604       if(rc==_row) std::sort(ordsut.begin(),ordsut.end(),compRowSize);  //rearrange from the largest to the smallest row sizes
1605       else          std::sort(ordsut.begin(),ordsut.end(),compColSize); //rearrange from the largest to the smallest col sizes
1606 
1607       //deal with first SuTermMatrix
1608       std::vector<SuTermMatrix* >::iterator itl=ordsut.begin(), itle=ordsut.end();
1609       SuTermMatrix* sut = *itl;
1610       std::vector<DofComponent>* cd=&sut->cdofsu();
1611       if(rc==_row) cd=&sut->cdofsv();
1612       number_t ld=rcdof.size()+1;
1613       rcnum[sut]=std::vector<number_t >(1,rcdof.size());   //trivial numbering
1614       rcdof.insert(rcdof.end(),cd->begin(),cd->end());
1615       std::map<DofComponent, number_t> dofmap;
1616       std::map<DofComponent, number_t>::iterator itmc;
1617       if(ordsut.size()>1)
1618         for(itd=cd->begin(); itd!=cd->end(); ++itd, ++ld) dofmap[*itd]=ld;
1619       itl++;
1620       ld=rcdof.size();
1621 
1622       for(; itl!=itle; itl++)  //travel SuTermMatrix list
1623         {
1624           bool trivial=true;
1625           SuTermMatrix* sut = *itl;
1626           std::vector<DofComponent>* cd=&sut->cdofsu();
1627           if(rc==_row) cd=&sut->cdofsv();
1628           number_t nbcd=cd->size();
1629           std::vector<DofComponent> locd(nbcd);
1630           std::vector<number_t >& num = rcnum[sut];
1631           num.resize(nbcd);
1632           std::vector<number_t >::iterator itc=num.begin();
1633           number_t k=0;
1634           for(itd=cd->begin(); itd!=cd->end(); itd++, itc++)
1635             {
1636               itmc=dofmap.find(*itd);
1637               if(itmc==dofmap.end())
1638                 {
1639                   ld++;            //increase global dof index
1640                   dofmap[*itd]=ld; //update dofmap
1641                   *itc=ld;         //update local->global numbering
1642                   locd[k]=*itd;    //update local cdof
1643                   k++;
1644                 }
1645               else {*itc=itmc->second; trivial=false;}
1646             }
1647           locd.resize(k);
1648           if(trivial) rcnum[sut]= std::vector<number_t >(1,rcdof.size());    //trivial numbering
1649           rcdof.insert(rcdof.end(),locd.begin(),locd.end());
1650         }
1651     }
1652 }
1653 
1654 // -----------------------------------------------------------------------------------------------------------
1655 // Algebraic operations on TermMatrix (+=, -=)
1656 // -----------------------------------------------------------------------------------------------------------
1657 
1658 /*! Algebraic operation += and -=
1659     the result of these operations is a TermMatrix with all unknown blocks of current TermMatrix and added Termatrix
1660         | Avu Avp    |    | Mvu        |         | Avu+Mvu Avp        |
1661         | Aqu        | += | Mqu Mqp    |   ==>   | Aqu+Mqu Mqp        |
1662         |     Atp Ats|    | Mtu     Mts|         | Mtu     Atp Ats+Mts|
1663     in other words, the matrices are merged and summation is a real one on common unknowns blocks
1664 */
operator +=(const TermMatrix & tM)1665 TermMatrix& TermMatrix::operator+=(const TermMatrix& tM)
1666 {
1667   bilinForm_ += tM.bilinForm_;
1668   if(! computed()) return *this;      //no hard copy
1669 
1670   for(it_mustm it = begin(); it != end(); it++)  //travel the blocks of current matrix
1671     {
1672       const Unknown* up = it->first.first, *vp = it->first.second; //unknowns of current block
1673       SuTermMatrix* sut = it->second;                              //current block
1674       const SuTermMatrix* stM = tM.subMatrix_p(up, vp);            //find (up,vp) block in tM
1675       if(stM != 0)(*sut) += *stM;                                   //add block to current block
1676     }
1677   for(cit_mustm itM = tM.begin(); itM != tM.end(); itM++)  //travel the blocks of added matrix
1678     {
1679       const Unknown* up = itM->first.first, *vp = itM->first.second; //unknowns of current block
1680       SuTermMatrix* sutM = itM->second;                              //current block
1681       const SuTermMatrix* sut = subMatrix_p(up, vp);                 //find (up,vp) block in current matrix
1682       if(sut == 0) suTerms_[uvPair(up, vp)] = new SuTermMatrix(*sutM);  //create new block in current matrix
1683     }
1684   return *this;
1685 }
1686 
operator -=(const TermMatrix & tM)1687 TermMatrix& TermMatrix::operator-=(const TermMatrix& tM)
1688 {
1689   bilinForm_ -= tM.bilinForm_;
1690   if(! computed()) return *this;      //no hard copy
1691 
1692   for(it_mustm it = begin(); it != end(); it++)  //travel the blocks of current matrix
1693     {
1694       const Unknown* up = it->first.first, *vp = it->first.second; //unknowns of current block
1695       SuTermMatrix* sut = it->second;                          //current block
1696       const SuTermMatrix* stM = tM.subMatrix_p(up, vp);        //find (up,vp) block in tM
1697       if(stM != 0)(*sut) -= *stM;                               //add block to current block
1698     }
1699   for(cit_mustm itM = tM.begin(); itM != tM.end(); itM++)  //travel the blocks of added matrix
1700     {
1701       const Unknown* up = itM->first.first, *vp = itM->first.second; //unknowns of current block
1702       SuTermMatrix* sutM = itM->second;                           //current block
1703       const SuTermMatrix* sut = subMatrix_p(up, vp);              //find (up,vp) block in current matrix
1704       if(sut == 0)  //create new block in current matrix
1705         {
1706           SuTermMatrix* nsut = new SuTermMatrix(*sutM);
1707           *nsut *= -1.;
1708           suTerms_[uvPair(up, vp)] = nsut;
1709         }
1710     }
1711   return *this;
1712 }
1713 
1714 // -----------------------------------------------------------------------------------------------------------
1715 // get real/imaginary part or move from real/complex to complex/real representation
1716 // -----------------------------------------------------------------------------------------------------------
toReal()1717 TermMatrix& TermMatrix::toReal()
1718 {
1719   if(valueType()==_real) return *this;
1720   for(it_mustm it = begin(); it != end(); it++) it->second->toReal();
1721   return *this;
1722 }
1723 
real(const TermMatrix & tm)1724 TermMatrix real(const TermMatrix& tm)
1725 {
1726   TermMatrix atm=tm;
1727   atm.name()="real("+tm.name()+")";
1728   if(atm.valueType()==_complex) atm.toReal();
1729   return atm;
1730 }
1731 
toComplex()1732 TermMatrix& TermMatrix::toComplex()
1733 {
1734   for(it_mustm it = begin(); it != end(); it++) it->second->toComplex();
1735   return *this;
1736 }
1737 
toComplex(const TermMatrix & tm)1738 TermMatrix toComplex(const TermMatrix& tm)
1739 {
1740   TermMatrix atm=tm;
1741   atm.name()="complex("+tm.name()+")";
1742   atm.toComplex();
1743   return atm;
1744 }
1745 
toImag()1746 TermMatrix& TermMatrix::toImag()
1747 {
1748   for(it_mustm it = begin(); it != end(); it++) it->second->toImag();
1749   return *this;
1750 }
1751 
imag(const TermMatrix & tm)1752 TermMatrix imag(const TermMatrix& tm)
1753 {
1754   TermMatrix atm=tm;
1755   atm.name()="imag("+tm.name()+")";
1756   atm.toImag();
1757   return atm;
1758 }
1759 
toConj()1760 TermMatrix& TermMatrix::toConj()
1761 {
1762   for(it_mustm it = begin(); it != end(); it++) it->second->toConj();
1763   return *this;
1764 }
1765 
conj(const TermMatrix & tm)1766 TermMatrix conj(const TermMatrix& tm)
1767 {
1768   TermMatrix atm=tm;
1769   if(tm.valueType()==_real) warning("free_warning"," taking the conjugate of the REAL TermMatrix "+tm.name()+" is useless");
1770   else
1771   {
1772       atm.name()="conj("+tm.name()+")";
1773       atm.toConj();
1774   }
1775   return atm;
1776 }
1777 
1778 
1779 
roundToZero(real_t aszero)1780 TermMatrix& TermMatrix::roundToZero(real_t aszero)
1781 {
1782   for(it_mustm it = begin(); it != end(); it++) it->second->roundToZero(aszero);
1783   return *this;
1784 }
1785 
roundToZero(const TermMatrix & tm,real_t aszero=10* theEpsilon)1786 TermMatrix roundToZero(const TermMatrix& tm, real_t aszero = 10*theEpsilon )  //! return the 0 rounded TermMatrix)
1787 {
1788    TermMatrix atm=tm;
1789    atm.name()="roundTo0("+tm.name()+")";
1790    atm.roundToZero(aszero);
1791    return atm;
1792 }
1793 
1794 // Frobenius norm : sqrt(sum|a_ij|^2)
norm2() const1795 real_t TermMatrix::norm2() const
1796 {
1797     if(scalar_entries_p!=0) return scalar_entries_p->norm2();
1798     real_t n=0.;
1799     for(cit_mustm it = begin(); it != end(); it++)  //travel the blocks of current matrix
1800     {
1801         real_t nb=it->second->norm2();
1802         n+=nb*nb;
1803     }
1804     return std::sqrt(n);
1805 }
1806 
1807 // infinite norm : sup|a_ij|
norminfty() const1808 real_t TermMatrix::norminfty() const
1809 {
1810     if(scalar_entries_p!=0) return scalar_entries_p->norminfty();
1811     real_t n=0.;
1812     for(cit_mustm it = begin(); it != end(); it++)  //travel the blocks of current matrix
1813         n=std::max(n,it->second->norminfty());
1814     return n;
1815 }
1816 
1817 // -----------------------------------------------------------------------------------------------------------
1818 // direct solver tools
1819 // -----------------------------------------------------------------------------------------------------------
1820 
1821 // member functions
1822 // solve linear system using LU factorization (current matrix is preserved)
luSolve(const TermVector & B,TermVector & X)1823 void TermMatrix::luSolve(const TermVector& B, TermVector& X)
1824 {
1825   TermMatrix Af;
1826   factorize((*this), Af, _lu);
1827   X=factSolve(Af, B);
1828 }
1829 
1830 // solve linear system using LDLt factorization (current matrix is preserved)
ldltSolve(const TermVector & B,TermVector & X)1831 void TermMatrix::ldltSolve(const TermVector& B, TermVector& X)
1832 {
1833   TermMatrix Af;
1834   factorize((*this), Af, _ldlt);
1835   X=factSolve(Af, B);
1836 }
1837 
1838 // solve linear system using LDL* factorization (current matrix is preserved)
ldlstarSolve(const TermVector & B,TermVector & X)1839 void TermMatrix::ldlstarSolve(const TermVector& B, TermVector& X)
1840 {
1841   TermMatrix Af;
1842   factorize((*this), Af, _ldlstar);
1843   X=factSolve(Af, B);
1844 }
1845 
1846 // solve linear system using umfpack(current matrix is preserved)
umfpackSolve(const TermVector & B,TermVector & X)1847 void TermMatrix::umfpackSolve(const TermVector& B, TermVector& X)
1848 {
1849   X = xlifepp::umfpackSolve(*this, B);
1850 }
1851 
1852 //------------------------------------------------------------------------------------------------------------
1853 // particular solver used by SOR and SSOR iterative method
1854 //------------------------------------------------------------------------------------------------------------
sorDiagonalMatrixVector(const TermVector & B,TermVector & X,const real_t w)1855 void TermMatrix::sorDiagonalMatrixVector(const TermVector& B, TermVector& X, const real_t w)
1856 {
1857   sorSolve(B, X, w, _matrixVectorSorS);
1858 }
sorUpperSolve(const TermVector & B,TermVector & X,const real_t w)1859 void TermMatrix::sorUpperSolve(const TermVector& B, TermVector& X, const real_t w)
1860 {
1861   sorSolve(B, X, w, _upperSorS);
1862 }
sorLowerSolve(const TermVector & B,TermVector & X,const real_t w)1863 void TermMatrix::sorLowerSolve(const TermVector& B, TermVector& X, const real_t w)
1864 {
1865   sorSolve(B, X, w, _lowerSorS);
1866 }
sorDiagonalSolve(const TermVector & B,TermVector & X,const real_t w)1867 void TermMatrix::sorDiagonalSolve(const TermVector& B, TermVector& X, const real_t w)
1868 {
1869   sorSolve(B, X, w, _diagSorS);
1870 }
1871 
sorSolve(const TermVector & B,TermVector & X,const real_t w,SorSolverType sType)1872 void TermMatrix::sorSolve(const TermVector& B, TermVector& X, const real_t w, SorSolverType sType)
1873 {
1874   trace_p->push("sorSolver(TermMatrix&, const TermVector&, real_t , SorSolvertype)");
1875   //create TermVector X
1876   ValueType vtX = _real;
1877   if (this->valueType() == _complex || B.valueType() == _complex) vtX = _complex;
1878   this->initTermVector(X, vtX, true);
1879 
1880   //solve linear system
1881   if (this->isSingleUnknown())
1882   {
1883     const Unknown* v = this->begin()->first.second, *u=this->begin()->first.first;
1884     SuTermMatrix* sutm = this->begin()->second;
1885     //check (*this), B unknown consistancy
1886     const SuTermVector* vB = B.subVector_p(u);
1887     if (vB == 0)
1888     {
1889       vB=B.subVector_p(u->dual_p());
1890       if (vB==0) error("term_inconsistent_unknowns");
1891     }
1892     //prepare matrix, right hand side and solution
1893     if (sutm->strucType()==_matrix)  sutm->toScalar(true);
1894     SuTermVector cvB(*vB);    //copy B entries
1895     SuTermVector* vX = X.subVector_p(u);
1896     if (vX == 0) {vX = X.subVector_p(u->dual_p()); }
1897     MatrixEntry* mat=0;
1898     VectorEntry* b=0, *x=0;
1899     if (sutm->scalar_entries()==0)   //scalar system
1900     {
1901       mat=sutm->entries();
1902       b=cvB.entries();
1903       std::vector<number_t> renum = renumber(sutm->space_up(), vB->spacep());
1904       if (renum.size() != 0) b->extendEntries(renum,sutm->space_up()->dimSpace());    //extend vector to matrix column numbering
1905       x=vX->entries();
1906     }
1907     else //vector system in scalar form
1908     {
1909       mat=sutm->scalar_entries();
1910       b=cvB.scalar_entries();
1911       if (b==0) {cvB.toScalar(); b=cvB.scalar_entries();}
1912       std::vector<number_t> renum;
1913       if (cvB.up() == v) renum = renumber(sutm->cdofsv(), cvB.cdofs());
1914       else               renum = renumber(sutm->cdofsv(), dualDofComponents(cvB.cdofs()));
1915       if (renum.size() != 0) b->extendEntries(renum,sutm->cdofsv().size());    //extend vector to matrix column numbering
1916       vX->toScalar();
1917       x=vX->scalar_entries();
1918     }
1919     if ((*this).hasConstraints())  // case of constraints on (*this)
1920     {
1921       mat=sutm->scalar_entries();
1922       if (vX->scalar_entries()==0) x->toScalar();
1923       else x=vX->scalar_entries();
1924       cvB.toScalar();         //force scalar representation
1925       b=cvB.scalar_entries();
1926       Constraints* cons_u = 0, *cons_v = 0;
1927       if (this->constraints_u_p !=0) cons_u = (*(this->constraints_u_p))(u);
1928       if (this->constraints_v_p !=0)
1929       {
1930         cons_v = (*(*this).constraints_v_p)(v);
1931         if(cons_v == 0) cons_v = (*(*this).constraints_v_p)(v->dual_p());          //try with dual unknown
1932       }
1933       appliedRhsCorrectorTo(b, cvB.cdofs(), sutm->rhs_matrix(), cons_u, cons_v, this->computingInfo_.reductionMethod); //correct rhs to take into account constraints
1934     }
1935     //goto solvers
1936     switch(sType)
1937     {
1938       case _diagSorS    :
1939         mat->sorDiagonalSolve(*b, *x, w);
1940         break;
1941       case _upperSorS :
1942         mat->sorUpperSolve(*b, *x, w);
1943         break;
1944       case _lowerSorS     :
1945         mat->sorLowerSolve(*b, *x, w);
1946         break;
1947       case _matrixVectorSorS     :
1948         mat->sorDiagonalMatrixVector(*b, *x, w);
1949         break;
1950       default :
1951         error("undef_option", "SorSolverType");
1952     }
1953     if (vX->up() == sutm->up())  vX->cdofs()=sutm->cdofsu();         //update cdofs
1954     else vX->cdofs()=dualDofComponents(sutm->cdofsu());
1955     if (vX->up()->nbOfComponents() > 1)  vX->toVector(true);  //return to vector representation
1956     vX->computed() = true;
1957     X.computed() = true;
1958   }
1959   else
1960   {
1961     TermVector Bc(B);      //copy of B
1962     if (this->hasConstraints())  // case of constraints on (*this), applied rhs correction
1963     {
1964       Constraints* cons_u = 0, *cons_v = 0;
1965       if (this->constraints_u_p !=0) cons_u = (*(this->constraints_u_p))(0);
1966       if (this->constraints_v_p !=0) cons_v = (*(this->constraints_v_p))(0);
1967       if (cons_u!=0 || cons_v!=0)   //global constraint
1968       {
1969         this->toGlobal(_noStorage, _noAccess, _noSymmetry, false);
1970         Bc.toGlobal(false);                            //go to scalar global representation
1971         Bc.adjustScalarEntries(this->cdofsr());            //adjust vector to matrix column scalar numbering
1972         appliedRhsCorrectorTo(Bc.scalar_entries(), Bc.cdofs(), this->rhs_matrix(),
1973                               cons_u, cons_v, this->computingInfo_.reductionMethod);
1974       }
1975       else //local constraints, correction of subsystems
1976       {
1977         Bc.toScalar();
1978         for (it_mustm it = this->begin(); it != this->end(); it++)
1979         {
1980           const Unknown* u=it->first.first, *v=it->first.second;
1981           SuTermMatrix* sutm= it->second;
1982           SuTermVector* sutv= Bc.subVector_p(u);
1983           if (sutv==0) sutv= Bc.subVector_p(u->dual_p());   //try with dual
1984           if (this->constraints_u_p !=0) cons_u = (*(this->constraints_u_p))(u);
1985           if (this->constraints_v_p !=0)
1986           {
1987             cons_v = (*(this->constraints_v_p))(v);
1988             if (cons_v == 0) cons_v = (*(this->constraints_v_p))(v->dual_p());   //try with dual unknown
1989           }
1990           if (cons_u!=0 && cons_v!=0 && sutv!=0)
1991             appliedRhsCorrectorTo(sutv->scalar_entries(), sutv->cdofs(), sutm->rhs_matrix(),
1992                                   cons_u, cons_v, this->computingInfo_.reductionMethod);
1993         }
1994         Bc.toGlobal();
1995         this->toGlobal(_noStorage, _noAccess, _noSymmetry, false);
1996         Bc.adjustScalarEntries(this->cdofsr());             //adjust vector to matrix column scalar numbering
1997       }
1998     }
1999     else //no constraints to appply
2000     {
2001       this->toGlobal(_noStorage, _noAccess, _noSymmetry, false);
2002       Bc.toGlobal();
2003       Bc.adjustScalarEntries(this->cdofsr());             //adjust vector to matrix column scalar numbering
2004     }
2005 
2006     //goto solvers
2007     X.toGlobal(false);
2008     VectorEntry* x=X.scalar_entries();
2009     VectorEntry* b=Bc.scalar_entries();
2010     MatrixEntry* mat=this->scalar_entries();
2011 
2012     //goto solvers
2013     switch(sType)
2014     {
2015       case _diagSorS    :
2016         mat->sorDiagonalSolve(*b, *x, w);
2017         break;
2018       case _upperSorS :
2019         mat->sorUpperSolve(*b, *x, w);
2020         break;
2021       case _lowerSorS     :
2022         mat->sorLowerSolve(*b, *x, w);
2023         break;
2024       default :
2025         error("undef_option", "SorSolverType");
2026     }
2027     X.computed() = true;
2028     X.toLocal(false);
2029   }
2030   trace_p->pop();
2031 }
2032 
2033 // -----------------------------------------------------------------------------------------------------------
2034 // in/out utilities
2035 // -----------------------------------------------------------------------------------------------------------
2036 
2037 //print storage on stream
viewStorage(std::ostream & out) const2038 void TermMatrix::viewStorage(std::ostream& out) const
2039 {
2040   for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)
2041   {
2042     out << "SuTermMatrix " << it->second->name() << "\n";
2043     it->second->viewStorage(out);
2044   }
2045 }
2046 
2047 //print TermMatrix
print(std::ostream & out) const2048 void TermMatrix::print(std::ostream& out) const
2049 {
2050   if(theVerboseLevel == 0) return;
2051   out << "TermMatrix " << name() << " : ";
2052   if(suTerms_.size() == 0)
2053     {
2054       out << " " << words("void") << " ";
2055       return;
2056     }
2057   cit_mustm it = suTerms_.begin();
2058   if(suTerms_.size() == 1)
2059     {
2060       out << words("unknown") << " \"" << it->first.first->name() << "\" ";
2061       out << words("test function") << " \"" << it->first.second->name() << "\"\n";
2062     }
2063   else
2064     {
2065       out << "("<<words("unknowns")<<", " <<  words("test functions")<<") : ";
2066       for(it = suTerms_.begin(); it != suTerms_.end(); it++)
2067         out << "(" << it->first.first->name() << ", "<< it->first.second->name() << ") ";
2068       out << eol;
2069     }
2070   if(theVerboseLevel < 2) return;
2071 
2072   //print SuTermMatrix's
2073   number_t vb = theVerboseLevel;
2074   if(theVerboseLevel < 5) verboseLevel(2);
2075   bool header = (suTerms_.size() > 1);
2076   for(it = suTerms_.begin(); it != suTerms_.end(); it++) it->second->print(out, header);
2077   verboseLevel(vb);
2078 
2079   //print global entries
2080   if(entries_p != 0)  out << " global entries : "<<*entries_p<<eol;
2081   if(scalar_entries_p != 0)
2082     {
2083       out << " global scalar entries : "<<eol;
2084       out << words("firste") << " " << words("row") << " cdofs : ";
2085       number_t nbd=cdofs_r.size();
2086       number_t m = std::min(number_t(theVerboseLevel),nbd);
2087       std::vector<DofComponent>::const_iterator itd=cdofs_r.begin();
2088       for(number_t i = 0; i < m; i++, itd++)  out  << *itd << "  ";
2089       if(m < nbd) out<<"...";
2090       out<<eol;
2091       out << words("firste") << " " << words("column") << " cdofs : ";
2092       nbd=cdofs_c.size();
2093       m = std::min(number_t(theVerboseLevel),nbd);
2094       itd=cdofs_c.begin();
2095       for(number_t i = 0; i < m; i++, itd++)  out  << *itd << "  ";
2096       if(m < nbd) out<<"...";
2097       out<<eol;
2098       if(scalar_entries_p==entries_p) out<<" same values as global entries"<<eol;
2099       else  out << (*scalar_entries_p)<<eol;
2100     }
2101 
2102   //print SetOfConstraints
2103   if(constraints_u_p!=0)
2104     out << " constraints on unknown (column) : "<<*constraints_u_p;
2105   if(constraints_v_p!=0)
2106     {
2107       out << "  constraints on test fuction (row)  : ";
2108       if(constraints_v_p == constraints_u_p) out<<" same as constraints on column"<<eol;
2109       else out <<*constraints_v_p<<eol;
2110     }
2111   if(constraints_u_p!=0 || constraints_v_p!=0) out<<"  "<<words("reduction method", computingInfo_.reductionMethod.method)<<eol;
2112 }
2113 
2114 //print brief computation report
printSummary(std::ostream & out) const2115 void TermMatrix::printSummary(std::ostream& out) const
2116 {
2117   out << "TermMatrix " << name() << " computed, size "<<numberOfRows()<< " X "<<numberOfCols()<<" : ";
2118   if(!isSingleUnknown()) out<<eol;
2119   for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++) it->second->printSummary(out);
2120   if(scalar_entries_p!=0) out<<eol<<"    has global representation in "<< scalar_entries_p->storagep()->name();
2121   if(rhs_matrix_p!=0) out<<eol<<"    has an essential condition correction matrix "<< rhs_matrix_p->nbOfRows()<<" X "<<rhs_matrix_p->nbOfCols();
2122   out << eol;
2123 }
2124 
2125 // save TermMatrix to file (dense or Matlab format)
saveToFile(const string_t & fn,StorageType st,bool encode) const2126 void TermMatrix::saveToFile(const string_t& fn, StorageType st, bool encode) const
2127 {
2128   if(!computed() || suTerms_.size() == 0)
2129     {
2130       warning("free_warning", "matrix is not computed, no saving");
2131       return;
2132     }
2133 
2134   //save global representation if exists, priority to scalar representation
2135   if(scalar_entries_p!=0)
2136     {
2137       scalar_entries_p->saveToFile(fn,st,encode);
2138       return;
2139     }
2140   if(entries_p!=0)
2141     {
2142       entries_p->saveToFile(fn,st,encode);
2143       return;
2144     }
2145 
2146   //save SuTermmMatrix's
2147   if(suTerms_.size() == 0)
2148     {
2149       warning("free_warning", "matrix seems to be empty, no saving");
2150       return;
2151     }
2152 
2153   cit_mustm it = suTerms_.begin();
2154   if(isSingleUnknown())
2155     {
2156       it->second->saveToFile(fn, st, encode);
2157       return;
2158     }
2159 
2160   std::pair<string_t, string_t> rootext = fileRootExtension(fn);
2161   for(cit_mustm it = suTerms_.begin(); it != suTerms_.end(); it++)
2162     {
2163       string_t fnb = rootext.first + "_" + it->first.first->name() + "_" + it->first.second->name() + "."+rootext.second;
2164       it->second->saveToFile(fnb, st, encode);
2165     }
2166 }
2167 
2168 } // end of namespace xlifepp
2169