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 Constraints.cpp
19   \author E. Lunéville
20   \since 20 jan 2014
21   \date  20 jan 2014
22 
23   \brief Implementation of xlifepp::Constraints class functions
24 */
25 
26 #include "term.h"
27 #include "Constraints.hpp"
28 
29 namespace xlifepp
30 {
31 
32 // ---------------------------------------------------------------------------------------------------------------------------------
33 // constructor of Constraints object
34 // ---------------------------------------------------------------------------------------------------------------------------------
Constraints(MatrixEntry * me,VectorEntry * ve)35 Constraints::Constraints(MatrixEntry* me, VectorEntry* ve)
36   : matrix_p(me), rhs_p(ve), reduced(false), local(true), symmetric(true), isId(false) {}
37 
38 
39 // ---------------------------------------------------------------------------------------------------------------------------------
40 // //create ConstraintData from EssentialCondition, depending on the type of essential conditions
41 // ---------------------------------------------------------------------------------------------------------------------------------
Constraints(const EssentialCondition & ec)42 Constraints::Constraints(const EssentialCondition& ec)
43   : matrix_p(0), rhs_p(0), reduced(false), local(true), symmetric(true), isId(false)
44 {
45   conditions_.push_back(ec);
46   symmetric = false;
47 
48   if(ec.type()== _lfEc)   //essential condition given by a linear form
49     {
50       createLf(ec);      //from TermVector of a linearform
51       return;
52     }
53 
54   // Lagrange u=0/op(g), Hdiv element u.n=0/op(g), Hrot element u^n=0/g^n
55   if(ec.type()==_DirichletEc)
56     {
57       bool done = createDirichlet(ec);
58       if(done) return;
59     }
60 
61   //general method using interpolation on node of domain
62   createNodal(ec);
63 }
64 
65 // ---------------------------------------------------------------------------------------------------------------------------------
66 // copy constructor and assign operator
67 // ---------------------------------------------------------------------------------------------------------------------------------
Constraints(const Constraints & c)68 Constraints::Constraints(const Constraints& c)
69 {
70   matrix_p=0;
71   rhs_p=0;
72   copy(c);
73 }
74 
operator =(const Constraints & c)75 Constraints& Constraints::operator=(const Constraints& c)
76 {
77   if(this==&c) return *this;
78   clear();
79   copy(c);
80   return *this;
81 }
82 
copy(const Constraints & c)83 void Constraints::copy(const Constraints& c)
84 {
85   reduced=c.reduced;
86   local=c.local;
87   symmetric=c.symmetric;
88   conditions_=c.conditions_;
89   cdofsr_=c.cdofsr_;
90   cdofsc_=c.cdofsc_;
91   elcdofs_=c.elcdofs_;
92   recdofs_=c.recdofs_;
93   if(matrix_p!=0) delete matrix_p;
94   if(rhs_p!=0) delete rhs_p;
95   matrix_p=0; rhs_p=0;
96   if(c.matrix_p!=0) matrix_p = new MatrixEntry(*c.matrix_p);
97   if(c.rhs_p!=0) rhs_p = new VectorEntry(*c.rhs_p);
98 }
99 
clear()100 void Constraints::clear()
101 {
102   if(matrix_p!=0) delete matrix_p;
103   if(rhs_p!=0) delete rhs_p;
104   matrix_p=0;
105   rhs_p=0;
106   cdofsr_.clear();
107   cdofsc_.clear();
108   elcdofs_.clear();
109   recdofs_.clear();
110   reduced=false;
111 }
112 
113 // ---------------------------------------------------------------------------------------------------------------------------------
114 // //create ConstraintData from EssentialCondition, depending on the type of essential condition
115 // ---------------------------------------------------------------------------------------------------------------------------------
~Constraints()116 Constraints::~Constraints()
117 {
118   if(matrix_p!=0) delete matrix_p;
119   if(rhs_p!=0) delete rhs_p;
120 }
121 
122 // ---------------------------------------------------------------------------------------------------------
123 /*! build Constraints set from EssentialConditions (list of essential conditions)
124     - create Constraints object for each essential condition
125     - merge constraints involving same unknown
126     - if there exist a constraint coupling different unknowns merge all Constraints object in one Constraints object
127     the output is a map of Constraints pointer indexed by unknown pointer;
128     only one Constraints pointer in case of coupling conditions
129 */
130 // ---------------------------------------------------------------------------------------------------------
buildConstraints(const EssentialConditions & ecs)131 std::map<const Unknown*, Constraints*> buildConstraints(const EssentialConditions& ecs)
132 {
133   trace_p->push("buildConstraints");
134 
135   std::list<EssentialCondition>::const_iterator ite=ecs.begin();
136   if(ite==ecs.end()) //void list
137     error("is_void", "ecs");
138 
139   //create one constraint for each essential condition
140   std::vector<Constraints*> constraints(ecs.size());
141   std::vector<Constraints*>::iterator itc=constraints.begin();
142   for(; ite!=ecs.end(); ite++, itc++) *itc=new Constraints(*ite);
143 
144 //   thePrintStream<<"----------------------- build constraints --------------------------"<<eol;
145 //   for(itc=constraints.begin(); itc!=constraints.end(); itc++) thePrintStream<<**itc<<std::flush;
146 
147   //merge constraints
148   std::map<const Unknown*, Constraints*>::iterator itm;
149   std::map<const Unknown*, Constraints*> mconstraints =  mergeConstraints(constraints);
150 
151 //   thePrintStream<<"----------------------- merge constraints --------------------------"<<eol;
152 //   for(itm=mconstraints.begin(); itm!=mconstraints.end(); itm++) thePrintStream<< *(itm->second)<<std::flush;
153 
154   //reduce constraints
155   for(itm=mconstraints.begin(); itm!=mconstraints.end(); itm++) itm->second->reduceConstraints();
156 
157 //   thePrintStream<<"----------------------- reduce constraints --------------------------"<<eol;
158 //   for(itm=mconstraints.begin(); itm!=mconstraints.end(); itm++) thePrintStream<< *(itm->second);
159 
160   trace_p->pop();
161   return mconstraints;
162 }
163 
164 //=========================================================================================================
165 /*! construct constraints matrix in case of Dirichlet condition
166 
167     Lagrange scalar/vector unknown u :                      a*u = 0/g
168     Raviart-Thomas (3D), Nedelec face (3D) scalar unknown : a*u.n = 0/g
169     Nedelec (2D), Nedelec Edge (3D) scalar unknown :        a*u^n = 0
170 
171     build Id matrix and rhs vector 0/g
172 */
173 //=========================================================================================================
174 
createDirichlet(const EssentialCondition & ec)175 bool Constraints::createDirichlet(const EssentialCondition& ec)
176 {
177   //check if a standard Dirichlet condition
178   const GeomDomain* dom=ec.domain(1);
179   const Unknown* u=ec.unknown(1);
180   Space* sp=u->space();           //rootspace
181   if(!sp->isFE()) return false;
182   FEType type =sp->interpolation()->type;
183   bool direct = (type==_Lagrange      && ec.diffOperator()==_id)
184                 || (type==_RaviartThomas && ec.diffOperator()==_ndot && ec.isHomogeneous())
185                 || (type==_Nedelec_Face  && ec.diffOperator()==_ndot && ec.isHomogeneous())
186                 || (type==_Nedelec_Edge  && ec.diffOperator()==_ncross && ec.isHomogeneous());
187   if(!direct) return false;  //go to general method
188 
189   trace_p->push("Constraints::createDirichlet");
190 
191   //get coefficient a
192   complex_t a=ec.coefficient();    //coefficient of condition
193   ValueType vta=_real;
194   if(a.imag()!=0) vta=_complex;
195   real_t ra=a.real();
196 
197   //create Id matrix
198   Space* subsp=Space::findSubSpace(dom,sp);
199   //if(subsp==0) subsp=new Space(*dom, *sp, sp->name()+"_"+dom->name());
200   std::vector<number_t> dofids;
201   if(subsp!=0) dofids = subsp->dofIds();              //dofs of subspace related to dom
202   else // built dof using dofsOn function
203     {
204       const_cast<GeomDomain*>(dom)->updateParentOfSideElements();
205       dofids = sp->feSpace()->dofsOn(*dom);          //dofs located on dom
206     }
207   if(dofids.size()==0) error("dof_not_found");
208 
209   number_t n = dofids.size() * u->nbOfComponents();   //number of dofs
210   matrix_p = new MatrixEntry(_idMatrix, _cs, _col, n, n, 1.);
211 
212   //create column dofs
213   cdofsc_ = createCdofs(u,dofids);
214 
215   // create virtual constraint space and constraint unknown (row unknown)
216   Function zero;                                                    //create void function to link it to a fake spectral space
217   Space* csp=new Space(*dom, zero, n, 1,"C_"+unknownEcName(ec));    //create virtual constraint space
218   const Unknown* csv= new Unknown(*csp, unknownEcName(ec), 1);      //create virtual constraint unknown
219   cdofsr_=createCdofs(csv,csp->dofIds());                           //create constraint dof
220 
221   // create rhs vector entry
222   const Function* fun=ec.funp();
223   if(fun==0) rhs_p = new VectorEntry(real_t(0),n);
224   else
225     {
226       ValueType vtfun=fun->valueType();
227       rhs_p= new VectorEntry(vtfun,1,n);
228       std::vector<Point> nodes(dofids.size());
229       std::vector<Point>::iterator itp=nodes.begin();
230       std::vector<number_t>::iterator itn=dofids.begin();
231       for(; itn!=dofids.end(); ++itn, ++itp) *itp = sp->feSpace()->dofs[*itn-1].coords();
232       std::vector<Vector<real_t> > ns;
233       if(fun->normalRequired()) ns=computeNormalsAt(*dom,nodes); //compute normals on dom1
234       if(vtfun==_real) buildRhs(fun,nodes,ns,real_t(0));
235       else             buildRhs(fun,nodes,ns,complex_t(0));
236       //divide by a if different from 1
237       if(a != complex_t(1.,0.))
238         {
239           if(vtfun==_real && vta==_complex) {rhs_p->toComplex(); vtfun=_complex;}
240           if(vtfun ==_complex) *rhs_p*=(1./a);
241           else *rhs_p*=(1./ra);
242         }
243 
244     }
245   local=true;
246   isId=true;
247   //end
248   trace_p->pop();
249   return true;
250 }
251 
252 //=========================================================================================================
253 /*! General method to construct "nodal" constraint  a1*op1(u1)|d1 + a2*op2(u2)|d2 + ... = g
254     where ai are complex scalars, opi are operators on unknowns ui and di are geometric domain
255         - only one ui,di     :  u|d = g            Dirichlet condition
256         - ui may be the same :  u|d1 - u|d2 = g    periodic condition
257         - di may be the same :  u1|d - u2|d = g    transmission condition
258         - ui,di are different:  u1|d1 - u2|d2 = g  generalized transmission condition
259   When domains are different it is mandatory to give the maps mi relating d1 to di (see defineMap function),
260   so the condition reads
261                           a1*op1(u1)|d1 + a2*op2(u2)|m2(d1) + ... = g
262   In any case, some nodes of d1 drive the computation :
263                        a1*op1(u1)(Mk) + a2*op2(u2)(m2(Mk)) + ... = g(Mk)   Mk in d1
264   The nodes Mk depends on the status of domain d1 :
265     1) if domain d1 belongs to the mesh supporting u1 and u1 is a Lagrange interpolation
266        then nodes used are all the nodes of the FE interpolation belonging to domain d1
267     2) if domain d1 belongs to the mesh supporting u1 and u1 is a Nedelec or Raviart interpolation
268        then nodes used are all the virtual coordinates of the dofs belonging to domain d1
269     3) else nodes defining geometric domain are used
270 
271   Be cautious : u1|d1 + u2|d2 = g  is not equivalent to u2|d2 + u1|d1 = g
272 
273   The algorithm is the following
274       - construct the list of nodes (Nk) of d1 regarding case
275       - build matrix ai*opi(ui)|mi(di) for i=1,nbterms (see constraintsMatrix function)
276       - concatenate them (see concatenateMatrix function)
277       - construct right hand side
278 
279   \note the constraints matrix has to be a scalar matrix. It means that in case of vector unknown the constraints are split
280 
281                                                      | a  0  ...|
282            Dirichlet and scalar unknown case     C = | 0 ...  0 |   diagonal matrix
283                                                      |... 0   a |
284 
285                                                      | [a 0] [0 0]  ...  ...|     | a 0 0 0 ... ...|
286                                                      | [0 a] [0 0]  ...  ...|     | 0 a 0 0 ... ...|
287            Dirichlet and vector unknown(2D) case C = | [0 0] [a 0] [0 0] ...|  -> | 0 0 a 0 0 0 ...|
288                                                      | [0 0] [0 a] [0 0] ...|     | 0 0 0 a 0 0 ...|
289                                                      | [0 0] [0 0] [a 0] ...|     | 0 0 0 0 a 0 ...|
290                                                      |  ...   ...   ...  ...|     | ... ... ... ...|
291 */
292 //=========================================================================================================
createNodal(const EssentialCondition & ec)293 void Constraints::createNodal(const EssentialCondition& ec)
294 {
295   trace_p->push("Constraints::createNodal");
296   if(ec.nbTerms()==0) error("is_void","term");
297 
298   const GeomDomain* dom1=ec.domain(1);
299   const Unknown* u1=ec.unknown(1);
300   if(dom1==0) error("null_pointer","domain");
301   if(u1==0) error("null_pointer","unknown");
302   Space* sp1=u1->space(), *subsp1=0;
303 
304   //built node list where apply constraints
305   std::vector<number_t>::iterator itd;
306   std::vector<Point>::iterator itp;
307   std::vector<Point> nodes;
308   FEType fet=sp1->feSpace()->interpolation()->type;
309   if(dom1->mesh() == sp1->domain()->mesh() &&  fet ==_Lagrange )   //use nodes of u1 interpolation
310     {
311       subsp1=Space::findSubSpace(dom1,sp1);
312       if(subsp1==0) subsp1=new Space(*dom1, *sp1, sp1->name()+"_"+dom1->name());
313       std::vector<number_t> dofs=subsp1->dofIds();
314       nodes.resize(dofs.size());
315       itp=nodes.begin();
316       for(itd=dofs.begin(); itd!=dofs.end(); ++itd, ++itp)
317         *itp = subsp1->rootSpace()->feSpace()->dofs[*itd-1].coords();
318     }
319   else if(dom1->mesh() == sp1->domain()->mesh() && (fet==_Nedelec_Edge || fet==_Nedelec_Face || fet==_RaviartThomas || fet==_CrouzeixRaviart))
320     {
321       //use internal side dofs "virtual location" given by dofs
322       std::vector<number_t> dofnum=sp1->feSpace()->dofsOn(*dom1); //dofs located on dom1
323       nodes.resize(dofnum.size());
324       std::vector<Point>::iterator itp=nodes.begin();
325       std::vector<number_t>::iterator itn=dofnum.begin();
326       for(; itn!=dofnum.end(); ++itn, ++itp) *itp = sp1->feSpace()->dofs[*itn-1].coords();
327       //thePrintStream<<"dofnum="<<dofnum<<eol<<"nodes="<<nodes<<eol<<std::flush;
328     }
329   else //default : use nodes from domain
330     {
331       std::set<number_t> nn=dom1->meshDomain()->nodeNumbers();
332       const std::vector<Point>& meshnodes=dom1->mesh()->nodes;
333       nodes.resize(nn.size());
334       std::set<number_t>::iterator itn=nn.begin();
335       itp=nodes.begin();
336       for(; itn!=nn.end(); ++itn, ++itp)  *itp = meshnodes[*itn -1];
337     }
338   if(nodes.size()==0) error("is_void","nodes");
339   if(subsp1==0) subsp1=sp1;
340 
341   //create matrix related to u1
342   cit_opuval itc=ec.begin();
343   matrix_p = constraintsMatrix(*itc->first, dom1, subsp1, itc->second, nodes, 0, cdofsc_);
344 
345   itc++;
346   for(number_t i=1; i<ec.nbTerms(); ++i, ++itc)
347     {
348       std::vector<DofComponent> cdofsci;
349       const Function* mi=0;
350       Space* spi=ec.unknown(i+1)->space(), *subspi=spi;
351       FEType feti=spi->feSpace()->interpolation()->type;
352       const GeomDomain* domi=ec.domain(i+1);
353       if(domi->mesh() == spi->domain()->mesh() && (feti==_Lagrange))
354         {
355           subspi=Space::findSubSpace(domi,spi);
356           if(subspi==0) subspi=new Space(*domi, *spi, spi->name()+"_"+domi->name());
357         }
358       if(domi!=dom1)
359         {
360           mi=findMap(*dom1,*domi);
361           if(mi == 0) error("domain_map_undefined",dom1->name(),domi->name());
362         }
363       MatrixEntry* mati = constraintsMatrix(*itc->first, domi, subspi, itc->second, nodes, mi, cdofsci);
364       concatenateMatrix(*matrix_p, cdofsc_, *mati, cdofsci);
365       delete mati;
366     }
367 
368   // create virtual constraint space and constraint unknown (row unknown)
369   Function zero;                                 //create void function to link it to a fake spectral space
370   number_t nbr=matrix_p->nbOfRows();
371   Space* csp=new Space(*dom1, zero, nbr, 1,"C_"+unknownEcName(ec)); //create virtual constraint space
372   const Unknown* csv= new Unknown(*csp, unknownEcName(ec), 1);      //create virtual constraint unknown
373   cdofsr_=createCdofs(csv,csp->dofIds());                           //create constraint dof
374 
375   // create rhs vector entry
376   const Function* fun=ec.funp();
377   if(fun==0) rhs_p = new VectorEntry(real_t(0),nbr);
378   else
379     {
380       std::vector<Vector<real_t> > ns;
381       if(fun->normalRequired()) ns=computeNormalsAt(*dom1,nodes); //compute normals on dom1
382       ValueType vtfun=fun->valueType();
383       //dimPair ds=fun->dims();             //in future, test compatibility of dimension with operator in constraints
384       rhs_p= new VectorEntry(vtfun,1,nbr);
385       if(vtfun==_real) buildRhs(fun,nodes,ns,real_t(0));
386       else             buildRhs(fun,nodes,ns,complex_t(0));
387     }
388 
389   local=(ec.nbTerms()==1 && ec.diffOperator()==_id);  //only u=g condition are considered as local condition
390   trace_p->pop();
391 }
392 
393 // ---------------------------------------------------------------------------------------------------------
394 /*! create constraints matrix from a term  a*op(u)|nodes where nodes is a collection of nodes :
395 
396          [ ... a*op(w_i1)(Mk)... a*op(w_i2)(Mk) .]  for node Mk
397 
398     the matrix is a scalar one and always stored in column sparse (csc)
399     built also the column component dofs vector
400 
401     opu   : operator on unknown
402     dom   : domain where opu is restricted
403     spu   : space or subspace used for interpolation (may be different from space of unknown)
404     coeff : coefficient applied to operator
405     nodes : list of points
406     fmap  : mapping function of nodes, may be 0 meaning id mapping
407 
408     cdofsc :  component dofs vector built by this routine
409 
410 */
411 // ---------------------------------------------------------------------------------------------------------
constraintsMatrix(const OperatorOnUnknown & opu,const GeomDomain * dom,Space * spu,const complex_t & coeff,const std::vector<Point> & nodes,const Function * fmap,std::vector<DofComponent> & cdofsc)412 MatrixEntry* Constraints::constraintsMatrix(const OperatorOnUnknown& opu, const GeomDomain* dom, Space* spu, const complex_t& coeff,
413     const std::vector<Point>& nodes, const Function* fmap,
414     std::vector<DofComponent>& cdofsc)
415 {
416   trace_p->push("Constraints::constraintsMatrix");
417 
418   const Unknown* u=opu.unknown();
419   if(u==0) error("null_pointer","unknown");
420   if(u->space()->typeOfSpace() != _feSpace) error("not_fe_space_type", u->space()->name());
421 
422   //various initialization
423   if(spu==0) spu=u->space();        //largest space if not defined
424   dimen_t nbcu=u->nbOfComponents();
425   dimen_t dimf=u->dimFun();
426   if(nbcu > 1) dimf = nbcu;      // vector extension
427   number_t n=nodes.size();
428   dimen_t d,m;  //block size in operator computation
429   const MeshDomain* mdom=spu->domain()->meshDomain();
430   bool useParent = (!mdom->isSideDomain());
431   dimen_t dimdom=dom->dim();
432 
433   //identify value type
434   ValueType vt=_real;
435   ValueType opuvt=opu.valueType();
436   if(opuvt==_complex) vt=_complex;
437   if(coeff.imag()!=0) vt=_complex;
438   real_t rcoeff=coeff.real();
439 
440   //create the map geomelement number -> element*
441   std::map<number_t, const Element*> gelt2elt;
442   for(number_t k=0; k<spu->nbOfElements(); k++)
443     {
444       const Element* elt=spu->element_p(k);
445       gelt2elt[elt->geomElt_p->number()]=elt;
446     }
447 
448   //loop initialization
449   std::vector<VectorEntry> opuws(n);              //list of values for each node
450   std::vector<std::vector<number_t> > dofs(n);    //list of dofs for each node
451   std::map<number_t, number_t> dofmap;            //map global dof numbering to local dof numbering
452   std::map<number_t, number_t>::iterator itm;
453   std::vector<VectorEntry>::iterator itwu=opuws.begin();
454   std::vector<std::vector<number_t> >::iterator itdu=dofs.begin();
455   std::vector<Point>::const_iterator itp;
456   Vector<real_t>* np=0;   //pointer to normal or other vector involved in operator
457   number_t k=1, i=1;
458 
459   //main construction loop
460   for(itp=nodes.begin(); itp!=nodes.end(); ++itp, ++itwu, ++itdu, ++i)
461     {
462       //geometric stuff
463       Point pt=*itp;
464       if(fmap!=0) pt=(*fmap)(*itp, pt);  //map to
465       Point q=pt;
466       real_t md; //distance to nearest element
467       GeomElement* belt = dom->meshDomain()->nearest(pt,md);
468       if(belt==0) error("point_not_on_boundary");
469       if(dimdom > 0 && md > belt->measure()) error("point_too_far_from_boundary",md);
470       const GeomElement* gelt = belt;
471       if(useParent)
472         {
473           gelt = belt->parentInDomain(mdom);       //first parent in mdom
474           if(gelt==0) gelt = mdom->nearest(q,md);  //try to locate element in mdom
475         }
476       const Element* elt=gelt2elt[gelt->number()];
477       if(opu.normalRequired())
478         {
479           MeshElement* melt = belt->meshElement();
480           if(melt==0) melt=belt->buildSideMeshElement();
481           if(melt->geomMapData_p == 0)  melt->geomMapData_p = new GeomMapData(melt);
482           GeomMapData* mapdata=melt->geomMapData_p;
483           Point q=mapdata->geomMapInverse(pt);
484           mapdata->computeOutwardNormal();
485           np=&mapdata->normalVector;
486         }
487 
488       //numbering stuff
489       std::vector<number_t> dofn=elt->dofNumbers;
490       std::vector<number_t>::iterator itd=dofn.begin(), itdc=itd;
491 
492       //compute shape functions and operator onto
493       ShapeValues shv=elt->computeShapeValues(pt, opu.diffOrder()>0);
494       if(nbcu > 1) shv.extendToVector(nbcu);                            //extend scalar shape functions to nbc vector shape functions
495       if(vt==_real)  //all is real
496         {
497           Vector<real_t> val;
498           if(opu.hasFunction()) opu.eval(pt, shv.w, shv.dw, dimf, val, d, m, np);  //evaluate differential operator with function
499           else                  opu.eval(shv.w, shv.dw, dimf, val, d, m, np);      //evaluate differential operator
500           //clean val
501           Vector<real_t>::iterator itv=val.begin(), itvc=val.begin(), itv2;
502           number_t nt=number_t(d*nbcu);   //number of values linked to a dof
503           number_t nbd=0;
504           for(itd=dofn.begin(); itd!=dofn.end(); ++itd)
505             {
506               real_t s=0.;
507               itv2=itv;
508               for(number_t j=0; j<nt; j++, ++itv) s+=std::abs(*itv);
509               if(s>theTolerance) //keep values
510                 {
511                   for(number_t j=0; j<nt; j++, ++itvc, ++itv2) *itvc=*itv2;
512                   *itdc=*itd;
513                   itdc++;
514                   nbd++;
515                 }
516             }
517           dofn.resize(nbd);
518           val.resize(nbd*nt);
519           *itwu=VectorEntry(val); //store val as a VectorEntry
520         }
521       else //some are complex, store in complex
522         {
523           Vector<complex_t> val;
524           if(opuvt==_real)
525             {
526               Vector<real_t> valr;
527               if(opu.hasFunction()) opu.eval(pt, shv.w, shv.dw, dimf, valr, d, m, np);  //evaluate differential operator with function
528               else                  opu.eval(shv.w, shv.dw, dimf, valr, d, m, np);      //evaluate differential operator
529               val=cmplx(valr);
530             }
531           else
532             {
533               if(opu.hasFunction()) opu.eval(pt, shv.w, shv.dw, dimf, val, d, m, np);  //evaluate differential operator with function
534               else                  opu.eval(shv.w, shv.dw, dimf, val, d, m, np);      //evaluate differential operator
535 
536             }
537           //clean val
538           Vector<complex_t>::iterator itv=val.begin(), itvc=itv, itv2;
539           number_t nt=d*nbcu;   //number of values linked to a dof
540           number_t nbd=0;
541           for(itd=dofn.begin(); itd!=dofn.end(); ++itd)
542             {
543               real_t s=0.;
544               itv2=itv;
545               for(number_t j=0; j<nt; j++, ++itv) s+=std::abs(*itv);
546               if(s>theTolerance) //keep values
547                 {
548                   for(number_t j=0; j<nt; j++, ++itvc, ++itv2) *itvc=*itv2;
549                   *itdc++=*itd;
550                   nbd++;
551                 }
552             }
553           dofn.resize(nbd);
554           val.resize(nbd*nt);
555           *itwu=VectorEntry(val);
556         }
557 
558       //update dof numbering
559       for(itd=dofn.begin(); itd!=dofn.end(); ++itd)
560         if(dofmap.find(*itd)==dofmap.end()) dofmap[*itd] = k++;
561       *itdu=dofn;
562 
563     } //end of loop
564 
565   //create cdofs vector
566   std::vector<number_t> dofv(dofmap.size());
567   std::vector<number_t>::iterator itd=dofv.begin(); k=1;
568   for(itm=dofmap.begin(); itm!=dofmap.end(); ++itm, ++itd,++k)
569     {
570       itm->second=k;
571       *itd=itm->first;
572     }
573   cdofsc = createCdofs(u,dofv);
574   number_t nbcol = cdofsc.size();   //differs from nbdof if vector unknown
575 
576   //create row index (ordering using dofmap) and matrix storage
577   std::vector<std::vector<number_t> > rows(nbcol);
578   k=1;
579   if(nbcu==1 && d==1)  //scalar case
580     {
581       for(itdu=dofs.begin(); itdu!=dofs.end(); ++itdu, ++k)
582         for(itd=itdu->begin(); itd!=itdu->end(); ++itd) rows[dofmap[*itd]-1].push_back(k);
583     }
584   else //vector case
585     {
586       for(itdu=dofs.begin(); itdu!=dofs.end(); ++itdu, k+=d)    //loop on dofs
587         {
588           for(itd=itdu->begin(); itd!=itdu->end(); ++itd)
589             {
590               //number_t c = d*(dofmap[*itd]-1);
591               number_t c = nbcu*(dofmap[*itd]-1);
592               for(number_t i=0; i<d; ++i)
593                 for(number_t j=0; j<nbcu; ++j) rows[c+j].push_back(k+i);
594             }
595         }
596     }
597 
598   //create storage and matrix
599   number_t nbrow = n*d;
600   MatrixStorage* ms= new ColCsStorage(nbrow,nbcol,rows);
601   MatrixEntry* mat= new MatrixEntry(vt,_scalar, ms);
602 
603   //fill matrix (could be optimized)
604   itwu=opuws.begin(); k=1;
605   if(nbcu==1 && d==1)  //scalar case
606     {
607       for(itdu=dofs.begin(); itdu!=dofs.end(); ++itdu, ++itwu, ++k)
608         {
609           number_t i=1;
610           for(itd=itdu->begin(); itd!=itdu->end(); ++itd, ++i)
611             {
612               if(vt==_real)
613                 {
614                   real_t r;
615                   itwu->getEntry(i,r);
616                   mat->setEntry(k,dofmap[*itd],rcoeff*r);
617                 }
618               else
619                 {
620                   complex_t c;
621                   itwu->getEntry(i,c);
622                   mat->setEntry(k,dofmap[*itd],coeff*c);
623                 }
624             }
625         }
626     }
627   else //vector case
628     {
629       for(itdu=dofs.begin(); itdu!=dofs.end(); ++itdu, ++itwu, k+=d)
630         {
631           number_t l=1;
632           for(itd=itdu->begin(); itd!=itdu->end(); ++itd)
633             for(number_t i=0; i<d; ++i)
634               for(number_t j=0; j<nbcu; ++j, ++l)
635                 {
636                   number_t r = k+i;
637                   number_t c = nbcu*(dofmap[*itd]-1)+j +1;
638                   if(vt==_real)
639                     {
640                       real_t vr;
641                       itwu->getEntry(l,vr);
642                       mat->setEntry(r,c,rcoeff*vr);
643                     }
644                   else
645                     {
646                       complex_t vc;
647                       itwu->getEntry(l,vc);
648                       mat->setEntry(r,c,coeff*vc);
649                     }
650                 }
651         }
652     }
653 
654   trace_p->pop();
655   return mat;
656 }
657 
658 // ---------------------------------------------------------------------------------------------------------------------------------
659 /*! create constraint data for a lf condition lf(u)=c (one row constraint), lf represented by a TermVector v
660     the constraints matrix has to be a scalar matrix. It means that in case of vector unknown the constraints are split
661 
662            scalar unknown case     C = | v1 ...  vn |   row matrix
663 
664            vector unknown(2D) case C = | [v11 v12] [v21 v22] ...|  -> | v11 v12 v21 v22 ....|
665 */
666 // ---------------------------------------------------------------------------------------------------------------------------------
createLf(const EssentialCondition & ec)667 void Constraints::createLf(const EssentialCondition& ec)
668 {
669   trace_p->push("Constraints::createLf");
670   if(ec.type()!=_lfEc)
671     error("ec_bad_ectype",words("essential condition",ec.type()), words("essential condition",_lfEc));
672   if(ec.lfp()==0)
673     error("null_pointer","termVector (lf)");
674   TermVector tv(*ec.lfp());
675   tv.toGlobal();  //move to global representation
676   VectorEntry* v=tv.actual_entries();
677   number_t n=v->size();
678   std::vector<number_t> un(1,1);
679   std::vector<std::vector<number_t> > rowindices(n,un);
680   MatrixStorage* ms= new ColCsStorage(1, n, rowindices);
681   ValueType vt=v->valueType_;
682   matrix_p = new MatrixEntry(vt,_scalar,ms);
683   //copy entries
684   if(vt==_real)
685     {
686       Vector<real_t>::const_iterator itv=v->rEntries_p->begin();
687       Vector<real_t>::iterator itm=matrix_p->rEntries_p->values().begin();
688       itm++;//jump first value
689       for(; itv!=v->rEntries_p->end(); itv++, itm++) *itm=*itv;
690     }
691   else
692     {
693       Vector<complex_t>::iterator itv=v->cEntries_p->begin();
694       Vector<complex_t>::iterator itm=matrix_p->cEntries_p->values().begin();
695       itm++; //jump first value
696       for(; itv!=v->cEntries_p->end(); itv++, itm++) *itm=*itv;
697     }
698   complex_t c=ec.clf;
699   if(std::abs(c.imag())==0.)
700     rhs_p = new VectorEntry(c.real(),1);
701   else
702     rhs_p = new VectorEntry(c,1);
703 
704   //create virtual constraint space
705   const GeomDomain* dom=tv.firstSut()->domain(); //take arbitrary domain
706   Function zero;
707   Space* csp=new Space(*dom, zero, 1, 1,"C_"+unknownEcName(ec));
708   const Unknown* csv= new Unknown(*csp, unknownEcName(ec), 1);
709   //update cdofs
710   cdofsc_=tv.cdofs();
711   cdofsr_=createCdofs(csv,csp->dofIds());
712   local=false;
713   trace_p->pop();
714 }
715 
716 
717 // ---------------------------------------------------------------------------------------------------------
718 /*! concatenate 2 constraint matrices mat1 and mat2 with no common column dofs
719     mat1 and mat2 are scalar matrix stored in cs column, mat1 and cdofsc1 are updated
720 */
concatenateMatrix(MatrixEntry & mat1,std::vector<DofComponent> & cdofsc1,const MatrixEntry & mat2,const std::vector<DofComponent> & cdofsc2)721 void Constraints::concatenateMatrix(MatrixEntry& mat1, std::vector<DofComponent>& cdofsc1,
722                                     const MatrixEntry& mat2, const std::vector<DofComponent>& cdofsc2)
723 {
724   trace_p->push("Constraints::concatenateMatrix");
725 
726   if(mat1.storageType()!=_cs) error("storage_unexpected",words("storage type",_cs),words("storage type",mat1.storageType()));
727   if(mat2.storageType()!=_cs) error("storage_unexpected",words("storage type",_cs),words("storage type",mat2.storageType()));
728   if(mat1.accessType()!=_col) error("access_unexpected",words("access type",_col),words("access type",mat1.accessType()));
729   if(mat2.accessType()!=_col) error("access_unexpected",words("access type",_col),words("access type",mat1.accessType()));
730 
731   ValueType vt1=mat1.valueType_, vt2=mat2.valueType_, vt=vt1;
732   if(vt==_real && vt2==_complex) vt=_complex;
733   if(vt==_complex && vt1==_real) mat1.toComplex();
734 
735   //concatenate storage
736   ColCsStorage* sto1 = reinterpret_cast<ColCsStorage*>(mat1.storagep()),
737                 * sto2 = reinterpret_cast<ColCsStorage*>(mat2.storagep());
738   number_t nnz1=sto1->size(), nnz2=sto2->size();
739   number_t nc1=sto1->nbOfColumns(), nc2=sto2->nbOfColumns(), nc=nc1+nc2;
740 
741   std::vector<number_t>& colp1=sto1->colPointer();
742   const std::vector<number_t>& colp2=sto2->colPointer();
743   colp1.resize(nc+1);
744   std::vector<number_t>::iterator it1=colp1.begin()+nc1;
745   std::vector<number_t>::const_iterator it2;
746   for(it2=colp2.begin(); it2!=colp2.end(); ++it2,++it1) *it1 = *it2 + nnz1;
747   std::vector<number_t>& rowi1=sto1->rowIndex();
748   const std::vector<number_t>& rowi2=sto2->rowIndex();
749   rowi1.resize(nnz1+nnz2);
750   it1=rowi1.begin()+nnz1;
751   for(it2=rowi2.begin(); it2!=rowi2.end(); ++it2,++it1) *it1=*it2;
752   sto1->nbOfColumns()=nc;
753 
754   //concatenate values
755   if(vt==_real)  //real case
756     {
757       std::vector<real_t>& val1=mat1.rEntries_p->values();
758       val1.resize(nnz1+nnz2+1);
759       std::vector<real_t>& val2=mat2.rEntries_p->values();
760       std::vector<real_t>::iterator it1=val1.begin()+nnz1+1;
761       std::vector<real_t>::const_iterator it2;
762       for(it2=val2.begin()+1; it2!=val2.end(); ++it2, ++it1) *it1=*it2;
763     }
764   else  //complex case
765     {
766       if(vt2==_real)
767         {
768           std::vector<complex_t>& val1 = mat1.cEntries_p->values();
769           val1.resize(nnz1+nnz2+1);
770           std::vector<real_t>& val2=mat2.rEntries_p->values();
771           std::vector<complex_t>::iterator it1=val1.begin()+nnz1+1;
772           std::vector<real_t>::const_iterator it2;
773           for(it2=val2.begin()+1; it2!=val2.end(); ++it2, ++it1) *it1=*it2;
774         }
775       else
776         {
777           std::vector<complex_t>& val1=mat1.cEntries_p->values();
778           val1.resize(nnz1+nnz2+1);
779           std::vector<complex_t>& val2=mat2.cEntries_p->values();
780           std::vector<complex_t>::iterator it1=val1.begin()+nnz1+1;
781           std::vector<complex_t>::const_iterator it2;
782           for(it2=val2.begin()+1; it2!=val2.end(); ++it2, ++it1) *it1=*it2;
783         }
784     }
785   mat1.setNbOfCols(nc);
786 
787   //concatenate cdofsc
788   cdofsc1.resize(nc1+nc2);
789   std::vector<DofComponent>::iterator itc1=cdofsc1.begin()+nc1;
790   std::vector<DofComponent>::const_iterator itc2=cdofsc2.begin();
791   for(; itc2!=cdofsc2.end(); ++itc2, ++itc1) *itc1=*itc2;
792 
793   trace_p->pop();
794 }
795 
796 // ---------------------------------------------------------------------------------------------------------------------------------
797 /*! merge constraints systems (if more than one conditions)
798    it takes as input a vector of Constraints (each corresponding to an essential condition)
799    and produces a map of Constraints indexed by unknown with two cases :
800 
801    Case of uncoupled unknowns (u1/v1, u2/v2 referred to same unknown u/v), u and v are not coupled by constraints
802                  u1   u2   v1   v2
803                 --------------------                      u1   u2                       v1  v2
804            c1   |cu1  0    0    0  |    | f1             ----------                    ---------
805            c2   | 0  cu2   0    0  |  = | f2  ==>   Cu = |cu1  0  | = fu= | f1    Cv = |cv1 cv2| = fv= | f3
806            c3   |     0   cv1  cv2 |    | f3             | 0  cu2 |       | f2         ---------
807                 --------------------                     ----------
808     The merging process involving u1, u2 referring to same unknown u produces Constraints object where common dofs are merged
809     One Constraints object for each unknown is created and returned
810 
811     Case of coupled unknowns (u1/v1, u2/v2 referred to same unknown u/v), u and v are coupled at least by one constraint
812                 u1    u2   v1   v2
813                 -------------------                       u   v
814            c1   |cu1  0    0   0  |  = | f1             ---------
815            c2   | 0  cu2  cv1 cv2 |    | f2     ==>     |Cu  Cv | = f
816                 -------------------                     ---------
817     A global Constraints matrix is created and returned (indexed by 0)
818 
819     NOTE : when merging some Constraints in a new one the old ones are deleted by this function
820 */
821 // ---------------------------------------------------------------------------------------------------------------------------------
mergeConstraints(std::vector<Constraints * > & constraints)822 std::map<const Unknown*, Constraints*> mergeConstraints(std::vector<Constraints*>& constraints)
823 {
824   number_t nbc=constraints.size();
825   if(nbc==0) error("is_null","constraints");
826   trace_p->push("mergeConstraints");
827 
828   std::map<const Unknown*, Constraints*> mconstraints;
829   std::vector<Constraints*>::iterator itc=constraints.begin();
830   if(nbc==1)  //no merging
831     {
832       mconstraints[(*itc)->unknown()]= *itc;
833       trace_p->pop();
834       return mconstraints;
835     }
836 
837   //collect constraints by unknown
838   std::map<const Unknown*, std::list<Constraints*> > lsu;   //list of constraints involving same unknown
839   std::map<const Unknown*, std::list<Constraints*> >::iterator itlsu;
840   bool global = false;
841   for(; itc!=constraints.end(); itc++)
842     {
843       std::set<const Unknown*> us=(*itc)->unknowns();
844       std::set<const Unknown*>::iterator its=us.begin();
845       for(; its!=us.end(); its++)
846         {
847           itlsu=lsu.find(*its);
848           if(itlsu==lsu.end()) lsu[*its]=std::list<Constraints*>(1,*itc);
849           else itlsu->second.push_back(*itc);
850         }
851       if(!global && (*itc)->coupledUnknowns()) global=true;
852     }
853 
854   if(lsu.size()>1) global=true; // force global when more than one unknown involved
855 
856   std::set<Constraints*> undelete;   //set of constraints to not be deleted
857 
858   //merge constraints by unknown
859   for(itlsu=lsu.begin(); itlsu!=lsu.end(); itlsu++)
860     {
861       const Unknown* u=itlsu->first;
862       std::list<Constraints*>& ls=itlsu->second;
863       std::list<Constraints*>::iterator itls;
864       if(ls.size()==1 && !(*ls.begin())->coupledUnknowns())  //unique constraint on u and uncoupling constraint
865         {
866           mconstraints[u]=*ls.begin();
867           undelete.insert(*ls.begin());   //no copy, do not delete after
868         }
869       else  //more than one constraints : merge them, if one coupling constraint : extract u part
870         {
871           //create new col cs storage and set up cdofs
872           ValueType vtm=_real, vtr=_real;
873           real_t vr; complex_t vc;
874           bool newloc=true;
875           bool newsym=true;
876           EssentialConditions newconditions;
877           std::map<DofComponent, std::set<number_t> > rowindex;
878           std::map<DofComponent, std::set<number_t> >::iterator itmd, itmd2;
879           std::vector<DofComponent>::iterator itd;
880           std::vector<DofComponent> newcdofsc, newcdofsr;
881           number_t nbr=0, nbc=0;
882           for(itls=ls.begin(); itls!=ls.end(); itls++)
883             {
884               number_t c=1;
885               for(itd=(*itls)->cdofsc_.begin(); itd!=(*itls)->cdofsc_.end(); itd++, c++) //loop on col cdofs
886                 if(itd->u_p == u)
887                   {
888                     std::set<number_t> rls=(*itls)->matrixp()->storagep()-> getRows(c);  //row indices of col c
889                     std::set<number_t>::iterator its;
890                     if(nbr!=0) //add nbr to row indices (row translation)
891                       {
892                         std::set<number_t> srls;
893                         for(its=rls.begin(); its!=rls.end(); its++) srls.insert(*its + nbr);
894                         rls=srls;
895                       }
896                     if(rowindex.find(*itd)==rowindex.end()) rowindex[*itd]=rls;
897                     else rowindex[*itd].insert(rls.begin(), rls.end());
898                   }
899               newcdofsr.insert(newcdofsr.end(),(*itls)->cdofsr_.begin(),(*itls)->cdofsr_.end());  //update row cdofs (assuming no overlap in rows)
900               nbr+=(*itls)->cdofsr_.size();
901               //update data of merged constraint
902               if((*itls)->matrixp()->valueType_==_complex) vtm=_complex;  //update matrix value type
903               if((*itls)->rhsp()->valueType_==_complex) vtr=_complex;     //update rhs value type
904               if(!(*itls)->local) newloc=false;                          //update local property
905               if(!(*itls)->symmetric) newsym=false;                      //update symmetry property
906               newconditions.insert(newconditions.end(),(*itls)->conditions_.begin(),(*itls)->conditions_.end());
907             }
908           nbr=newcdofsr.size();
909           nbc=rowindex.size();
910           newcdofsc.resize(nbc);
911           itd= newcdofsc.begin();
912           std::vector<std::vector<number_t> > vrowindex(nbc);
913           std::vector<std::vector<number_t> >::iterator itv=vrowindex.begin();
914           for(itmd=rowindex.begin(); itmd!=rowindex.end(); itmd++, itv++, itd++)
915             {
916               *itd = itmd->first;
917               *itv = std::vector<number_t>(itmd->second.begin(),itmd->second.end());
918             }
919           MatrixStorage* ms=new ColCsStorage(nbr,nbc,vrowindex);
920           //fill new constraint matrix and rhs vector
921           MatrixEntry* newmatrix=new MatrixEntry(vtm, _scalar, ms);
922           VectorEntry* newrhs= new VectorEntry(vtr,_scalar, nbr);
923           nbr=0;
924           for(itls=ls.begin(); itls!=ls.end(); itls++)
925             {
926               number_t c=1;
927               const MatrixEntry* mec=(*itls)->matrixp();
928               for(itd=(*itls)->cdofsc_.begin(); itd!=(*itls)->cdofsc_.end(); itd++, c++) //loop on col cdofs
929                 if(itd->u_p == u)
930                   {
931                     itmd=rowindex.find(*itd);
932                     itmd2=rowindex.begin();
933                     number_t k=1;
934                     while(itmd2!=itmd) {k++; itmd2++;} //range of cdof in map
935                     std::set<number_t> rls=(*itls)->matrixp()->storagep()-> getRows(c);  //row indices of col c
936                     std::set<number_t>::iterator its;
937                     if(mec->valueType_==_real)
938                       for(its=rls.begin(); its!=rls.end(); its++)
939                         {
940                           mec->getEntry(*its, c, vr);
941                           if(vtm==_real) newmatrix->setEntry(*its + nbr, k, vr);
942                           else newmatrix->setEntry(*its + nbr, k, complex_t(vr));
943                         }
944                     else
945                       for(its=rls.begin(); its!=rls.end(); its++)
946                         {
947                           mec->getEntry(*its, c, vc);
948                           newmatrix->setEntry(*its + nbr, k, vc);
949                         }
950                   }
951               //fill new rhs
952               const VectorEntry* vec=(*itls)->rhsp();
953               if(vec->valueType_==_real)
954                 for(number_t k=1; k<=vec->size(); k++)
955                   {
956                     vec->getEntry(k,vr);
957                     if(vtr==_real) newrhs->setEntry(k + nbr, vr);
958                     else newrhs->setEntry(k + nbr, complex_t(vr));
959                   }
960               else
961                 for(number_t k=1; k<=vec->size(); k++)
962                   {
963                     vec->getEntry(k,vc);
964                     newrhs->setEntry(k + nbr, vc);
965                   }
966               nbr+=(*itls)->cdofsr_.size();
967             }
968           //create new constraint
969           Constraints* newc= new Constraints(newmatrix,newrhs);
970           newc->cdofsc_=newcdofsc;
971           newc->cdofsr_=newcdofsr;
972           newc->conditions_=newconditions;
973           newc->local = newloc;
974           newc->symmetric=newsym;
975           mconstraints[u]=newc;
976         }
977     }
978 
979   //global merge if some constraints couple different unknowns
980   //merge all previous constraints in one constraint
981   if(global)
982     {
983       std::map<const Unknown*, Constraints*>::iterator itmc;
984       std::map<DofComponent,number_t> rowdofs;
985       std::map<DofComponent,number_t>::iterator itmn;
986       std::vector<DofComponent> newcdofsc, newcdofsr;
987       std::vector<DofComponent>::iterator itd;
988       ValueType vtm=_real, vtr=_real;
989       number_t k=1;
990       for(itmc=mconstraints.begin(); itmc!=mconstraints.end(); itmc++)
991         {
992           Constraints* cons=itmc->second;
993           for(itd=cons->cdofsr_.begin(); itd!=cons->cdofsr_.end(); itd++)
994             if(rowdofs.find(*itd)==rowdofs.end())
995               {rowdofs.insert(std::make_pair(*itd,k)); k++;}
996           newcdofsc.insert(newcdofsc.end(),cons->cdofsc_.begin(),cons->cdofsc_.end());
997         }
998       newcdofsr.resize(rowdofs.size());
999       itd=newcdofsr.begin();
1000       for(itmn=rowdofs.begin(); itmn!=rowdofs.end(); itmn++, itd++) *itd = itmn->first;
1001       number_t nbc=newcdofsc.size(), nbr= newcdofsr.size();
1002       std::vector<std::vector<number_t> > vrowindex(nbc);
1003       std::vector<std::vector<number_t> >::iterator itv=vrowindex.begin();
1004       std::set<number_t>::iterator its;
1005       std::vector<number_t>::iterator itvr;
1006       for(itmc=mconstraints.begin(); itmc!=mconstraints.end(); itmc++)
1007         {
1008           Constraints* cons=itmc->second;
1009           number_t c=1;
1010           for(itd=cons->cdofsc_.begin(); itd!=cons->cdofsc_.end(); itd++, itv++, c++)
1011             {
1012               std::set<number_t> rls=cons->matrixp()->storagep()-> getRows(c);  //row indices of col c
1013               std::vector<number_t> vrls(rls.size());
1014               itvr=vrls.begin();
1015               for(its=rls.begin(); its!=rls.end(); its++, itvr++) *itvr = rowdofs[cons->cdofsr_[*its-1]];
1016               *itv = vrls;
1017               if(cons->matrixp()->valueType_ == _complex) vtm = _complex;
1018               if(cons->rhsp()->valueType_ == _complex) vtr = _complex;
1019             }
1020         }
1021       MatrixStorage* ms=new ColCsStorage(nbr,nbc,vrowindex);   //new storage
1022       MatrixEntry* newmatrix=new MatrixEntry(vtm, _scalar, ms);
1023       VectorEntry* newrhs= new VectorEntry(vtr,_scalar, nbr);
1024       k=1; real_t vr; complex_t vc;
1025       for(itmc=mconstraints.begin(); itmc!=mconstraints.end(); itmc++)
1026         {
1027           Constraints* cons=itmc->second;
1028           //update matrix
1029           number_t c=1;
1030           for(itd=cons->cdofsc_.begin(); itd!=cons->cdofsc_.end(); itd++, itv++, k++, c++)
1031             {
1032               std::set<number_t> rls=cons->matrixp()->storagep()-> getRows(c);
1033               if(cons->matrixp()->valueType_ ==_real)
1034                 {
1035                   for(its=rls.begin(); its!=rls.end(); its++)
1036                     {
1037                       number_t r = rowdofs[cons->cdofsr_[*its-1]];
1038                       cons->matrixp()->getEntry(*its, c, vr);
1039                       if(vtm==_real) newmatrix->setEntry(r,k,vr);
1040                       else newmatrix->setEntry(r,k,complex_t(vr));
1041                     }
1042                 }
1043               else
1044                 {
1045                   for(its=rls.begin(); its!=rls.end(); its++, itvr++)
1046                     {
1047                       number_t r = rowdofs[cons->cdofsr_[*its-1]];
1048                       cons->matrixp()->getEntry(*its, c, vc);
1049                       newmatrix->setEntry(r,k,vc);
1050                     }
1051                 }
1052             }
1053           //update rhs
1054           const VectorEntry* vec=cons->rhsp();
1055           number_t k=1;
1056           for(itd=cons->cdofsr_.begin(); itd!=cons->cdofsr_.end(); itd++, k++)
1057             {
1058               number_t r = rowdofs[*itd];
1059               if(vec->valueType_==_real)
1060                 {
1061                   vec->getEntry(k,vr);
1062                   if(vtr==_real) newrhs->setEntry(r, vr);
1063                   else newrhs->setEntry(r, complex_t(vr));
1064                 }
1065               else
1066                 {
1067                   vec->getEntry(k,vc);
1068                   newrhs->setEntry(r, vc);
1069                 }
1070             }
1071         }
1072       //delete mconstraints and reallocate
1073       for(itmc=mconstraints.begin(); itmc!=mconstraints.end(); itmc++)
1074         if(undelete.find(itmc->second) == undelete.end())
1075           {
1076             undelete.insert(itmc->second);
1077             delete itmc->second;
1078           }
1079       mconstraints.clear();
1080       Constraints* newc= new Constraints(newmatrix,newrhs);
1081       newc->cdofsc_=newcdofsc;
1082       newc->cdofsr_=newcdofsr;
1083       bool newloc=true;
1084       bool newsym=true;
1085       EssentialConditions newconditions;
1086       for(itc=constraints.begin(); itc!=constraints.end(); itc++)
1087         {
1088           newconditions.insert(newconditions.end(),(*itc)->conditions_.begin(),(*itc)->conditions_.end());
1089           if(!(*itc)->local) newloc=false;
1090           if(!(*itc)->symmetric) newsym=false;
1091         }
1092       newc->conditions_= newconditions;
1093       newc->local = newloc;
1094       newc->symmetric = newsym;
1095       mconstraints[0]=newc;
1096     }
1097 
1098   //delete old constraints
1099   for(itc=constraints.begin(); itc!=constraints.end(); itc++)
1100     if(undelete.find(*itc) == undelete.end()) delete *itc;
1101 
1102   //end of merging
1103   trace_p->pop();
1104   return mconstraints;
1105 }
1106 
1107 
1108 // ---------------------------------------------------------------------------------------------------------------------------------
1109 /*! reduce constraints system to an upper triangular system using stable QR factorization
1110     transform the constraints into a new constraints where matrix is an upper triangular matrix
1111 
1112                            u1           u2         ...      un
1113                      --------------------------------------------
1114                      | ... ... ... | ... ... |           |  ... |          | . |
1115     original     C = | ...  C1 ... | ... ... |    ...    |   Cn |       D= | . |
1116     constraints      | ... ... ... | ... ... |           |  ... |          | . |
1117                      --------------------------------------------
1118 
1119                            rearrangement of u1 , u2, ..., un
1120                      --------------------------------------------
1121                      | 1  x ... | ... ... |           |  ... ...|          | . |
1122     reduce      rC = | 0  1  x  | ... ... |    ...    |  ... ...|      rD= | . |
1123     constraints      | 0  0 ... | ... ... |           |  ... ...|          | . |
1124                      --------------------------------------------
1125 
1126   when algorithm 'fails' it means that some constraints are redundant or conflicting, so we eliminate on the fly some line constraints
1127 
1128   In a second step, the upper triangular system is inverted to produce residual rectangular matrix and modified right hand side
1129 
1130                                     part of  u1 , u2, ..., un
1131                                 --------------------------------
1132                                 |  x   x  |           |  x   x |          | . |
1133     residual constraints   F =  |  x  ... |    ...    |  x  ...|      b = | . |
1134                                 | ... ... |           | ... ...|          | . |
1135                                 --------------------------------
1136     The first p column indices  (of squared upper triangular matrix) corresponds to the eliminated dofs (say U_e)
1137     while the other column indices corresponds to the residual dofs (say U_r). Finally the constraints system reads
1138 
1139                             ----------------------------------------
1140                             | U_e + F*U_r = b  <=>  U_e= b - F*U_r |
1141                             ----------------------------------------
1142 
1143     which is the useful expression to deal with essential conditions in bilinear form computation
1144     \note F may be a null matrix (classic Dirichlet condition for instance, condition reads U_e = b as usual)
1145 
1146   \param aszero  : a positive value near 0 used to round to 0 very small values, say |v|<aszero, default value is 10*theEpsilon
1147 
1148   this process may be permutes column cdofs and produces
1149   elcdofs_ : the map of eliminated cdofs, cdof -> k (rank in cdofsc_)
1150   recdofs_ : the map of reduced cdofs : cdof -> k (rank in cdofsc_)
1151 
1152 */
1153 // ---------------------------------------------------------------------------------------------------------------------------------
1154 
reduceConstraints(real_t aszero)1155 void Constraints::reduceConstraints(real_t aszero)
1156 {
1157   trace_p->push("Constraints::reduceConstraints");
1158 
1159   if(isId)  //special case of Id : trivial reduction
1160     {
1161       //set elcdofs and recdofs
1162       number_t n=matrix_p->nbOfRows();
1163       std::vector<DofComponent>::iterator itc=cdofsc_.begin();
1164       for(number_t k=1; k<=n; k++, itc++) elcdofs_[*itc]=k;
1165       recdofs_.clear();
1166       matrix_p->clear();
1167       if(rhs_p!=0 && norminfty(*rhs_p)< aszero)  {delete rhs_p; rhs_p=0;}  //delete near 0 right hand side
1168       trace_p->pop();
1169       return;
1170     }
1171 
1172   //General case, use QR reduction
1173   MatrixEntry matR, matQ;   //for QR factorisation
1174   bool withPerm = true;     //column permutation allowed in QR factorisation
1175   std::vector<number_t>* numcol=0;
1176   number_t stop=0;
1177   QR(*matrix_p, matR, false, matQ, rhs_p, withPerm, numcol, stop);
1178   number_t nbr=matrix_p->nbOfRows(), nbc=matrix_p->nbOfCols();
1179 
1180   if(stop < nbr)
1181     {
1182       VectorEntry crhs(*rhs_p);
1183       crhs.deleteRows(1,stop);
1184       number_t nbz=crhs.nbzero(aszero), nbnz=nbr-stop-nbz;
1185       std::stringstream ss;
1186       ss<<"Constraints::reduceConstraints() : in essential conditions \n"<<conditions_;
1187       if(nbnz>0) ss<<" conflicting constraint row(s) detected, up to "<<(nbr-stop)<<" rows"<<eol;
1188       else  ss<<nbz<<" redundant constraint row(s) detected and eliminated"<<eol;
1189       warning("free_warning",ss.str());
1190       matR.deleteRows(stop+1, nbr);  //delete redundant rows
1191       rhs_p->deleteRows(stop+1, nbr);
1192       cdofsr_.resize(stop);          //update cdofsr_
1193     }
1194   if(withPerm) //apply permutation to cdofsc_
1195     {
1196       std::vector<DofComponent> newdof(cdofsc_.size());
1197       std::vector<DofComponent>::iterator itc = newdof.begin();
1198       std::vector<number_t>::iterator itn=numcol->begin();
1199       for(; itn!=numcol->end(); itn++, itc++) *itc = cdofsc_[*itn];
1200       cdofsc_=newdof;
1201     }
1202 
1203   //set elcdofs and recdofs
1204   nbr=matR.nbOfRows();
1205   std::vector<DofComponent>::iterator itc=cdofsc_.begin();
1206   number_t k=1;
1207   for(; k<=nbr; k++, itc++) elcdofs_[*itc]=k;
1208   for(; k<=nbc; k++, itc++) recdofs_[*itc]=k;
1209 
1210   // reduced upper triangular system to "diagonal" system
1211   matR.roundToZero(aszero);     //to eliminate spurious rounding effects
1212   MatrixEntry matU(matR,true);  //copy matR, forcing storage copy to prevent shared storage
1213   nbc=matR.nbOfCols();
1214   if(nbc>nbr)
1215     {
1216       matU.deleteCols(nbr+1,nbc);
1217       matR.deleteCols(1, nbr);
1218       if(!matU.isId(theTolerance)) QRSolve(matU,&matR,rhs_p);  // solve upper triangular system
1219     }
1220   else
1221     {
1222       matR.clear();
1223       if(!matU.isId(theTolerance)) QRSolve(matU,0,rhs_p);     // solve upper triangular system
1224     }
1225 
1226   //finalization
1227   *matrix_p=matR;  //ERIC : check the storage management, delete, copy, shared storage ...
1228   if(rhs_p!=0 && norminfty(*rhs_p)< aszero)  //delete near 0 right hand side
1229     {
1230       delete rhs_p;
1231       rhs_p=0;
1232     }
1233   if(numcol!=0) delete numcol;
1234   reduced=true;
1235   trace_p->pop();
1236 }
1237 
1238 // ---------------------------------------------------------------------------------------------------------------------------------
1239 /*! extract eliminated and reduced cdofs from list of cdofs
1240    cdofs : list of cdofs
1241    melcdofs : list of elimited cdofs with their ranks in cdofs list
1242    mrecdofs : list of reduced cdofs with their ranks in cdofs list
1243    useDual  : if true use either unknown or dual unknown to get cdofs
1244 */
1245 // ---------------------------------------------------------------------------------------------------------------------------------
extractCdofs(const std::vector<DofComponent> & cdofs,std::map<DofComponent,number_t> & melcdofs,std::map<DofComponent,number_t> & mrecdofs,bool useDual) const1246 void Constraints::extractCdofs(const std::vector<DofComponent>& cdofs, std::map<DofComponent, number_t>& melcdofs,
1247                                std::map<DofComponent, number_t>& mrecdofs, bool useDual) const
1248 {
1249   melcdofs.clear(); mrecdofs.clear();
1250   std::map<DofComponent, number_t>::const_iterator itmd;
1251   std::vector<DofComponent>::const_iterator itd;
1252   std::vector<DofComponent>::iterator itdd;
1253   std::vector<DofComponent> dual_cdofs;
1254   number_t k=1;
1255   if(useDual)
1256     {
1257       dual_cdofs.resize(cdofs.size());
1258       std::vector<DofComponent>::iterator itdd = dual_cdofs.begin();
1259       for(itd=cdofs.begin(); itd!=cdofs.end(); itd++, itdd++) *itdd = itd->dual();
1260     }
1261   itdd=dual_cdofs.begin();
1262   for(itd=cdofs.begin(); itd!=cdofs.end(); itd++,k++) //travel all row cdof of matrix mat
1263     {
1264       itmd=elcdofs_.find(*itd);
1265       if(itmd!=elcdofs_.end()) melcdofs[*itd]=k;     // eliminated cdof found
1266       itmd=recdofs_.find(*itd);
1267       if(itmd!=recdofs_.end()) mrecdofs[*itd]=k;     // reduced cdof found
1268       if(useDual)
1269         {
1270           itmd=elcdofs_.find(*itdd);
1271           if(itmd!=elcdofs_.end()) melcdofs[*itd]=k;     // eliminated cdof found
1272           itmd=recdofs_.find(*itdd);
1273           if(itmd!=recdofs_.end()) mrecdofs[*itd]=k;     // reduced cdof found
1274           itdd++;
1275         }
1276     }
1277 }
1278 
1279 // ---------------------------------------------------------------------------------------------------------------------------------
1280 // print utilities
1281 // ---------------------------------------------------------------------------------------------------------------------------------
print(std::ostream & os) const1282 void Constraints::print(std::ostream& os) const
1283 {
1284   os<<" Constraints system related to essential condition(s)"<<eol<<conditions_;
1285   if(matrix_p==0)
1286     {
1287       os<<" no matrix representation !"<<eol;
1288       return;
1289     }
1290   if(coupledUnknowns()) os<<" constraints system couples different unknowns, global system ";
1291   //else os<<" constraints system on unknown "<<unknown()->name() << " ";
1292   if(unknown()!=0) os<<" constraints system on unknown "<<unknown()->name() << " ";
1293   else
1294     {
1295       std::set<const Unknown*> us=conditions_.unknowns();
1296       std::set<const Unknown*>::iterator itu = us.begin();
1297       os<<" constraints system on unknowns ("<<(*itu)->name(); ++itu;
1298       for(; itu!=us.end(); ++itu) os<<", "<<(*itu)->name();
1299       os<<") ";
1300     }
1301   if(rhs_p==0) os<<" (homogeneous)";
1302   else os<<" (non homogeneous)";
1303   if(local) os<<" , local constraints";
1304   else os<<" , non local constraints";
1305   if(symmetric) os<<" , keeping symmetry";
1306   else os<<" , not keeping symmetry";
1307   os<<eol;
1308   os<<"  unknown dofs involved ("<<cdofsc_.size()<<") : "<< cdofsc_<<eol;
1309   os<<"  test function dofs involved ("<<cdofsr_.size()<<") : "<< cdofsr_<<eol;
1310   os<<"  constraints matrix : "<<*matrix_p;
1311   if(rhs_p!=0) os<<"  right hand side : "<<*rhs_p<<eol;
1312   if(reduced)
1313     {
1314       os<<"  eliminated dofs ("<<elcdofs_.size()<<") : "<< elcdofs_<<eol;
1315       os<<"  reduced dofs ("<<recdofs_.size()<<") : "<< recdofs_<<eol;
1316     }
1317   return;
1318 }
1319 
operator <<(std::ostream & os,const Constraints & cd)1320 std::ostream& operator<<(std::ostream& os, const Constraints& cd)
1321 {
1322   cd.print(os);
1323   return os;
1324 }
1325 
1326 //utility to create a unique unknown name associated to an essential condition
unknownEcName(const EssentialCondition & ec)1327 string_t unknownEcName(const EssentialCondition& ec)
1328 {
1329   string_t nar=ec.name()+" (c";
1330   number_t k=0;
1331   string_t na=nar+tostring(k)+")";
1332   while(findUnknown(na)!=0) { k++; na=nar+tostring(k)+")";}
1333   return na;
1334 }
1335 
1336 /*!
1337   perform pseudo reduction of reduced essential conditions in a matrix. Essential conditions have the following form  :
1338                           U_E + F*U_R = s   for column unknown U
1339                           V_E + G*V_R = 0   for row test function V (generally related to unknown U)
1340   where E are the eliminated unknown/test function indices and R are the reduced unknown/test function indices
1341   The pseudo reduction of matrix consists in
1342     - modifying column A.j for j in R by adding -Fkj*A.k for k in E and replacing column A.k for k in E by a 0 column
1343     - modifying row Ai. for i in R by adding -Gki*Ak. for k in E and replacing row Ak. for k in E by a 0 row
1344     - if eliminated v unknowns are dual of eliminated u unknowns, the VE rows are replaced by the equation (or a part of)
1345                                       a*U_E + a*F*U_R = a*s   where a is a given scalar
1346   to delay the right hand side modification, the (A.k) columns (k in E) are stored in a new structure
1347 
1348   At the end of the process, the eliminated system looks like
1349                    U_E     U_R    U_S       RHS
1350                  ----------------------   ------
1351                  |      |       |     |   |    |
1352             V_E  | a*Id |  a*F  |  0  |   | a*S|
1353                  |      |       |     |   |    |
1354                  ---------------------    -----
1355                  |      |       |     |   |    |
1356             V_R  |  0   |  ARR  | ARS |   | FR |
1357                  |      |       |     |   |    |
1358                  ----------------------   ------
1359                  |      |       |     |   |    |
1360             V_S  |  0   |  ASR  | ASS |   | FS |
1361                  |      |       |     |   |    |
1362                  ----------------------   ------
1363 
1364   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)
1365   the storage is modified
1366 
1367     mat   : matrix to be eliminated
1368     cdofr : row component dofs of matrix
1369     cdofc : col component dofs of matrix
1370     rhsmat: right hand side matrix pointer
1371 */
pseudoColReduction(MatrixEntry * mat,std::vector<DofComponent> & cdofr,std::vector<DofComponent> & cdofc,MatrixEntry * & rhsmat)1372 void Constraints::pseudoColReduction(MatrixEntry* mat, std::vector<DofComponent>& cdofr,
1373                                      std::vector<DofComponent>& cdofc, MatrixEntry*& rhsmat)
1374 {
1375   trace_p->push("Constraints::pseudoColReduction()");
1376   if(matrix_p==0) {trace_p->pop(); return;}       //no constraints to apply
1377 
1378   //locate eliminated cdofs and reduced cdofs in matrix columns
1379   std::map<DofComponent, number_t> melcdofs, mrecdofs;
1380   extractCdofs(cdofc, melcdofs, mrecdofs, false);
1381   number_t nbe=elcdofs_.size();
1382   std::map<DofComponent, number_t>::iterator itn, itm, itmd;
1383   std::vector<DofComponent>::iterator itd;
1384   complex_t z0(0.,0.), z1(1.,0.);
1385 
1386   if(melcdofs.size()>0) // create correction matrix (rshmat)
1387     {
1388       //construct storage and constraint correction matrix
1389       MatrixStorage* ms=0;
1390       if(mat->storageType()!=_dense)
1391         {
1392           std::vector< std::vector<number_t> > rowindex(melcdofs.size());
1393           std::vector< std::vector<number_t> >::iterator itri=rowindex.begin();
1394           for(itn=melcdofs.begin(); itn!=melcdofs.end(); itn++, itri++)
1395             {
1396               std::set<number_t> snum=mat->storagep()->getRows(itn->second);
1397               *itri = std::vector<number_t>(snum.begin(), snum.end());
1398             }
1399           ms= new ColCsStorage(mat->nbOfRows(),melcdofs.size(),rowindex);
1400         }
1401       else //dense storage
1402         ms= new ColDenseStorage(mat->nbOfRows(),melcdofs.size());
1403 
1404       rhsmat = new MatrixEntry(mat->valueType_, _scalar, ms);
1405       number_t j=1;
1406       for(itn=melcdofs.begin(); itn!=melcdofs.end(); itn++, itd++, j++)
1407         {
1408           number_t c=itn->second;
1409           std::vector<std::pair<number_t, number_t> > adrs = mat->storagep()->getCol(mat->symmetry(),c);
1410           std::vector<number_t> mat_adr(adrs.size());
1411           std::vector<std::pair<number_t, number_t> >::iterator ita=adrs.begin();
1412           std::vector<number_t>::iterator itma=mat_adr.begin();
1413           for(; ita!=adrs.end(); ita++, itma++) *itma = ita->second;   //addresses in mat of col c
1414           adrs=rhsmat->storagep()->getCol(_noSymmetry,j);
1415           std::vector<number_t> rhsmat_adr(adrs.size());
1416           itma=rhsmat_adr.begin();
1417           for(ita=adrs.begin(); ita!=adrs.end(); ita++, itma++) *itma = ita->second;  //addresses in rhsmat of col c
1418           rhsmat->copyVal(*mat, mat_adr, rhsmat_adr);
1419         }
1420     }
1421 
1422   if(mrecdofs.size()>0) // update reduced columns
1423     {
1424       //change mat type if  real matrix and complex constraints matrix
1425       ValueType vtm=mat->valueType_, vtcm=matrix_p->valueType_;
1426       if(vtm==_real && vtcm==_complex)
1427         {
1428           mat->toComplex();
1429           mat->valueType_ = _complex;
1430           vtm=_complex;
1431         }
1432       real_t cr=0.; complex_t cc=z0;
1433       //combine columns
1434       for(itn=melcdofs.begin(); itn!=melcdofs.end(); itn++)
1435         {
1436           std::map<DofComponent, number_t>::const_iterator itmd=elcdofs_.find(itn->first);
1437           number_t i=itmd->second;
1438           for(itm=mrecdofs.begin(); itm!=mrecdofs.end(); itm++)
1439             {
1440               itmd=recdofs_.find(itm->first);
1441               number_t j=itmd->second - nbe;
1442               if(vtcm==_real)
1443                 {
1444                   matrix_p->getEntry(i,j,cr);
1445                   if(cr!=0)
1446                     {
1447                       if(vtm == _real) mat->addColToCol(itn->second,itm->second, -cr);
1448                       else mat->addColToCol(itn->second,itm->second,complex_t(-cr));
1449                     }
1450                 }
1451               else
1452                 {
1453                   matrix_p->getEntry(i,j,cc);
1454                   if(cc!=z0) mat->addColToCol(itn->second,itm->second,-cc);
1455                 }
1456             }
1457         }
1458     }
1459 
1460   if(melcdofs.size()>0) // eliminate columns
1461     {
1462       //pseudo col reduction (set eliminated columns to 0)
1463       for(itn=melcdofs.begin(); itn!=melcdofs.end(); itn++) mat->setColToZero(itn->second,itn->second);
1464     }
1465   trace_p->pop();
1466 }
1467 
1468 
1469 
1470 // pseudo reduction of rows
pseudoRowReduction(MatrixEntry * mat,std::vector<DofComponent> & cdofr,std::vector<DofComponent> & cdofc,const complex_t & alpha)1471 void Constraints::pseudoRowReduction(MatrixEntry* mat, std::vector<DofComponent>& cdofr, std::vector<DofComponent>& cdofc, const complex_t& alpha)
1472 {
1473   trace_p->push("Constraints::pseudoRowReduction()");
1474   if(matrix_p==0) {trace_p->pop(); return;}       //no constraints to apply
1475 
1476   //locate eliminated cdofs and reduced cdofs
1477   std::map<DofComponent, number_t> melcdofs, mrecdofs;
1478   extractCdofs(cdofr, melcdofs, mrecdofs, true);
1479   number_t nbe=elcdofs_.size();
1480   ValueType vtm=mat->valueType_, vtcm=matrix_p->valueType_;
1481   complex_t z0(0.,0.), z1(1.,0.);
1482   real_t cr=0.; complex_t cc=z0;
1483 
1484   std::map<DofComponent, number_t>::iterator itn, itm, itmd;
1485   std::vector<DofComponent>::iterator itd;
1486   if(mrecdofs.size()>0) // update reduced rows
1487     {
1488       //change mat type if required (real matrix and complex constraints matrix)
1489       if(vtm==_real && vtcm==_complex)
1490         {
1491           mat->toComplex();
1492           mat->valueType_ = _complex;
1493           vtm=_complex;
1494         }
1495       //combine rows
1496       for(itn=melcdofs.begin(); itn!=melcdofs.end(); itn++)
1497         {
1498           std::map<DofComponent, number_t>::const_iterator itmd=elcdofs_.find(itn->first);
1499           if(itmd==elcdofs_.end()) itmd=elcdofs_.find(itn->first.dual());  //try with dual
1500           number_t i=itmd->second;
1501           for(itm=mrecdofs.begin(); itm!=mrecdofs.end(); itm++)
1502             {
1503               itmd=recdofs_.find(itm->first);
1504               if(itmd==recdofs_.end()) itmd=recdofs_.find(itm->first.dual());  //try with dual
1505               number_t j=itmd->second - nbe;
1506               if(vtcm==_real)
1507                 {
1508                   matrix_p->getEntry(i,j,cr);
1509                   if(cr!=0)
1510                     {
1511                       if(vtm == _real) mat->addRowToRow(itn->second,itm->second, -cr);
1512                       else mat->addRowToRow(itn->second,itm->second,complex_t(-cr));
1513                     }
1514                 }
1515               else
1516                 {
1517                   matrix_p->getEntry(i,j,cc);
1518                   if(cc!=z0) mat->addRowToRow(itn->second,itm->second,conj(-cc));  //warning : conjugate constraints coefficient
1519                 }
1520             }
1521         }
1522     }
1523 
1524   if(melcdofs.size()>0) // "eliminate" rows
1525     {
1526       for(itn=melcdofs.begin(); itn!=melcdofs.end(); itn++) mat->setRowToZero(itn->second,itn->second);
1527       //set diagonal coefficient of mat to 1 if row cdofs and col cdofs are dual or same
1528       number_t k=1, kt;
1529       std::map<DofComponent, number_t> mapcdofc;  //map of column dofs
1530       for(itd=cdofc.begin(); itd!=cdofc.end(); itd++, k++) mapcdofc[*itd]=k;
1531       ValueType vtm=mat->valueType_;
1532       for(itn=melcdofs.begin(); itn!=melcdofs.end(); itn++)
1533         {
1534           k=itn->second;
1535           itm=mapcdofc.find(itn->first);
1536           if(itm==mapcdofc.end()) itm=mapcdofc.find(itn->first.dual());
1537           if(itm!=mapcdofc.end())
1538             {
1539               kt = itm->second;
1540               if(vtm==_real) mat->setEntry(k,kt, alpha.real());
1541               else  mat->setEntry(k,kt,alpha);
1542 //            if(vtm==_real) mat->setEntry(k,kt, 1.);
1543 //            else  mat->setEntry(k,kt,z1);
1544 
1545             }
1546         }
1547     }
1548 
1549   if(mrecdofs.size()>0) // replace "eliminate" row assuming a v_constraints is same as u_constraints
1550     {
1551       //replace block eliminated x reduced by constraints matrix
1552       for(itn=melcdofs.begin(); itn!=melcdofs.end(); itn++)
1553         {
1554           std::map<DofComponent, number_t>::const_iterator itmd=elcdofs_.find(itn->first);
1555           if(itmd==elcdofs_.end()) itmd=elcdofs_.find(itn->first.dual());  //try with dual
1556           number_t i=itmd->second;
1557           for(itm=mrecdofs.begin(); itm!=mrecdofs.end(); itm++)
1558             {
1559               itmd=recdofs_.find(itm->first);
1560               if(itmd==recdofs_.end()) itmd=recdofs_.find(itm->first.dual());  //try with dual
1561 
1562               number_t j=itmd->second - nbe; //block eliminated x reduced
1563               if(vtcm==_real)
1564                 {
1565                   matrix_p->getEntry(i,j,cr);
1566                   if(cr!=0.)  //all row has been already reset to 0 (except diagonal to 1)
1567                     {
1568                       if(vtm==_real) mat->setEntry(itn->second, itm->second,alpha.real()*cr,false);
1569                       else mat->setEntry(itn->second, itm->second,alpha*complex_t(cr),false);
1570                     }
1571                 }
1572               else
1573                 {
1574                   matrix_p->getEntry(i,j,cc);
1575                   if(cc!=z0)
1576                     {
1577                       mat->setEntry(itn->second, itm->second,alpha*cc,false);
1578                     }
1579                 }
1580             }
1581         }
1582     }
1583   trace_p->pop();
1584 }
1585 
1586 // extend storage of matrix when constraints are not local and have column/row combination
1587 // assuming scalar matrix entries !
extendStorage(MatrixEntry * mat,std::vector<DofComponent> & cdofsr,std::vector<DofComponent> & cdofsc,const Constraints * cu,const Constraints * cv)1588 void extendStorage(MatrixEntry* mat, std::vector<DofComponent>& cdofsr, std::vector<DofComponent>& cdofsc,
1589                    const Constraints* cu, const Constraints* cv)
1590 {
1591   trace_p->push("extendStorage(...)");
1592   if(mat==0) { trace_p->pop(); return; } //nothing to do !!!
1593   bool local=true;
1594   std::map<DofComponent, number_t> melcdofs_u, mrecdofs_u, melcdofs_v, mrecdofs_v;
1595   if(cu!=0 && !cu->local)
1596     {
1597       cu->extractCdofs(cdofsc, melcdofs_u, mrecdofs_u, false);
1598       local = (mrecdofs_u.size()==0);
1599     }
1600   if(cv!=0 && !cv->local)
1601     {
1602       cv->extractCdofs(cdofsr, melcdofs_v, mrecdofs_v, true);
1603       if(local) local = (mrecdofs_v.size()==0);
1604     }
1605 
1606   if(local) {trace_p->pop(); return;}  //storage extension not required
1607 
1608   //build extended col index
1609   number_t nbc=mat->nbOfCols(), nbr=mat->nbOfRows();
1610   std::vector<std::set<number_t> > colindex(nbr);
1611   std::vector<std::set<number_t> >::iterator itc=colindex.begin();
1612   for(number_t r=1; r<=nbr; r++, itc++) *itc = mat->storagep()->getCols(r); //copy col indices
1613   real_t cr=0.; complex_t cc=0.;
1614   std::map<DofComponent, number_t>::iterator itm, itn;
1615 
1616   const MatrixEntry* cmat=cu->matrixp();
1617   if(mrecdofs_u.size()>0)  //column combination
1618     {
1619       cmat=cu->matrixp();
1620       number_t nbe=cu->elcdofs_.size();
1621       for(itn=melcdofs_u.begin(); itn!=melcdofs_u.end(); itn++)
1622         {
1623           std::set<number_t> indrow = mat->storagep()->getRows(itn->second);  //row indices of col
1624           std::map<DofComponent, number_t>::const_iterator itmd=cu->elcdofs_.find(itn->first);
1625           number_t i=itmd->second;
1626           for(itm=mrecdofs_u.begin(); itm!=mrecdofs_u.end(); itm++)
1627             {
1628               itmd=cu->recdofs_.find(itm->first);
1629               number_t j=itmd->second - nbe;
1630               if(cmat->valueType_ == _real) {cmat->getEntry(i,j,cr); cc=cr;}
1631               else cmat->getEntry(i,j,cc);
1632               if(cc!=complex_t(0.)) //add row index in current col
1633                 {
1634                   std::set<number_t>::iterator its;
1635                   for(its=indrow.begin(); its!=indrow.end(); its++) colindex[*its-1].insert(itm->second);
1636                 }
1637             }
1638         }
1639     }
1640 
1641   //row combination
1642   cmat=cv->matrixp();
1643   number_t nbe=cv->elcdofs_.size();
1644   for(itm=mrecdofs_v.begin(); itm!=mrecdofs_v.end(); itm++)
1645     {
1646       std::map<DofComponent, number_t>::const_iterator itmd=cv->recdofs_.find(itm->first);
1647       if(itmd==cv->recdofs_.end()) itmd=cv->recdofs_.find(itm->first.dual());  //try with dual
1648       number_t j=itmd->second - nbe;
1649       for(itn=melcdofs_v.begin(); itn!=melcdofs_v.end(); itn++)
1650         {
1651           itmd=cu->elcdofs_.find(itn->first);
1652           if(itmd==cu->elcdofs_.end()) itmd=cu->elcdofs_.find(itn->first.dual());  //try with dual
1653           number_t i=itmd->second;
1654           if(cmat->valueType_ == _real) {cmat->getEntry(i,j,cr); cc=cr;}
1655           else cmat->getEntry(i,j,cc);
1656           if(cc!=complex_t(0.)) //add col indices in current col index
1657             {
1658               std::set<number_t>& indcol=colindex[itn->second -1];
1659               colindex[itm->second -1].insert(indcol.begin(),indcol.end());
1660             }
1661         }
1662     }
1663 
1664   // insert eliminated x reduced block assuming v_constraints is same as u_constraints
1665   if(mrecdofs_u.size()>0)
1666     {
1667       number_t nbe=melcdofs_u.size();
1668       for(itn=melcdofs_u.begin(); itn!=melcdofs_u.end(); itn++)
1669         {
1670           if(itn->second > colindex.size()) //constraint involve unknowns not present in matrix
1671             error("ec_unknown_not_found");
1672           std::map<DofComponent, number_t>::const_iterator itmd=cu->elcdofs_.find(itn->first);
1673           number_t i=itmd->second;
1674           for(itm=mrecdofs_u.begin(); itm!=mrecdofs_u.end(); itm++)
1675             {
1676               itmd=cu->recdofs_.find(itm->first);
1677               number_t j=itmd->second - nbe;
1678               if(cmat->valueType_ == _real)
1679                 {
1680                   cmat->getEntry(i,j,cr);
1681                   if(cr!=0.) colindex[itn->second -1].insert(itm->second);
1682                 }
1683               else
1684                 {
1685                   cmat->getEntry(i,j,cc);
1686                   if(cc!=0.) colindex[itn->second -1].insert(itm->second);
1687                 }
1688             }
1689         }
1690     }
1691 
1692   //create new storage
1693   std::vector<std::vector<number_t> > vcolindex(nbr);
1694   std::vector<std::vector<number_t> >::iterator itv=vcolindex.begin();
1695   itc=colindex.begin();
1696   for(; itv!=vcolindex.end(); itv++,itc++)
1697     if(!itc->empty()) *itv = std::vector<number_t>(itc->begin(),itc->end());
1698   colindex.clear();
1699   AccessType at = mat->accessType();
1700   StorageType st= mat->storageType();
1701 //  SymType sy= mat->symmetry();
1702   if(at==_sym && (mrecdofs_u.size()>0 || mrecdofs_v.size()>0)) at=_dual;
1703   if(at==_sym && cu != cv) at=_dual;  //symmetry is lost
1704   MatrixStorage* newsto = createMatrixStorage(st,at,nbr,nbc,vcolindex,mat->storagep()->name()+"_extended");
1705   mat->toStorage(newsto);
1706   if(at==_dual) mat->symmetry() =_noSymmetry;
1707   trace_p->pop();
1708 }
1709 
1710 /*! correct a right hand side b to take into account constraints
1711     recall that constraints on unknown are of the form  Ue1 + CUr1 = f  (C matrix e1 x r1)
1712     and constraints on test functions are of the form   Ve2 + DVr2 = 0  (D matrix e2 x r2)
1713     where ei stands for eliminated indices and ri for reduced indices (e1=e2 and r1=r2 in most cases)
1714     in the matrix reduction process, a corrector matrix has been computed, say E matrix m x r1
1715     the correction process consists in
1716          first step  : b -= E * f_r1       (column combination)
1717          second step : b_r2 -= Dt * b_e2   (row combination)
1718          third step  : b_e2 = f_e1         (deletion in case of real reduction)
1719     in simple cases (Dirichlet for instance), C=D=0 so the second step is not required
1720 
1721     b      : vector to be corrected
1722     cdofsb : component dof of vector b
1723     rhsmap : pointer to correction matrix (C)
1724     cu, cv : pointer to u/v constraints system
1725 
1726 */
appliedRhsCorrectorTo(VectorEntry * b,const std::vector<DofComponent> & cdofsb,MatrixEntry * rhsmat,const Constraints * cu,const Constraints * cv,const ReductionMethod & rm)1727 void appliedRhsCorrectorTo(VectorEntry* b, const std::vector<DofComponent>& cdofsb,
1728                            MatrixEntry* rhsmat, const Constraints* cu, const Constraints* cv,
1729                            const ReductionMethod& rm)
1730 {
1731   trace_p->push("appliedRhsCorrectorTo()");
1732 
1733   ReductionMethodType meth=rm.method;
1734   complex_t alpha = rm.alpha;
1735 
1736   if(cu!=0 && cu->rhsp()!=0 && rhsmat!=0) // first step (column combination)
1737     {
1738       std::map<DofComponent, number_t>::const_iterator itmd;
1739       VectorEntry* nrhs;
1740       const VectorEntry* rhsp=cu->rhsp();
1741       if(rhsp->valueType_==_real)
1742         {
1743           nrhs = new VectorEntry(_real, _scalar,cu->elcdofs_.size());
1744           number_t k=1; real_t v;
1745           for(itmd=cu->elcdofs_.begin(); itmd!=cu->elcdofs_.end(); ++itmd, k++)
1746             {
1747               rhsp->getEntry(itmd->second,v);
1748               nrhs->setEntry(k,v);
1749             }
1750         }
1751       else
1752         {
1753           nrhs = new VectorEntry(_complex, _scalar,cu->elcdofs_.size());
1754           number_t k=1; complex_t c;
1755           for(itmd=cu->elcdofs_.begin(); itmd!=cu->elcdofs_.end(); ++itmd, k++)
1756             {
1757               rhsp->getEntry(itmd->second,c);
1758               nrhs->setEntry(k,c);
1759             }
1760         }
1761       *b -= *rhsmat** nrhs;
1762       delete nrhs;
1763     }
1764 
1765   if(cv==0) {trace_p->pop(); return;} //no row reduction
1766 
1767   //create dual cdofsb
1768   std::vector<DofComponent> dual_cdofsb(cdofsb.size());
1769   std::vector<DofComponent>::const_iterator itd;
1770   std::vector<DofComponent>::iterator itdd=dual_cdofsb.begin();
1771   for(itd=cdofsb.begin(); itd!=cdofsb.end(); itd++, itdd++) *itdd = itd->dual();
1772 
1773   //locate eliminated and reduced dofs in b
1774   std::map<DofComponent, number_t> belcdofs, brecdofs;
1775   itdd=dual_cdofsb.begin(); number_t k=1;
1776   std::map<DofComponent, number_t>::const_iterator itmd;
1777   for(itd=cdofsb.begin(); itd!=cdofsb.end(); itd++, itdd++, k++)  //goto original row numbering
1778     {
1779       itmd=cv->elcdofs_.find(*itd);
1780       if(itmd!=cv->elcdofs_.end()) belcdofs[itmd->first] = k;
1781       itmd=cv->elcdofs_.find(*itdd);
1782       if(itmd!=cv->elcdofs_.end()) belcdofs[itmd->first] = k;
1783       itmd=cv->recdofs_.find(*itd);
1784       if(itmd!=cv->recdofs_.end()) brecdofs[itmd->first] = k;
1785       itmd=cv->recdofs_.find(*itdd);
1786       if(itmd!=cv->recdofs_.end()) brecdofs[itmd->first] = k;
1787     }
1788 
1789   if(cv->matrixp()!=0  && cv->matrixp()->nbOfCols()>0)         // second step (row combination)
1790     {
1791       number_t nbe=cv->elcdofs_.size();
1792       VectorEntry rb(b->valueType_,b->strucType_,nbe);
1793 
1794       std::map<DofComponent, number_t>::const_iterator itme;
1795       for(itmd = belcdofs.begin(); itmd!=belcdofs.end(); itmd++)
1796         {
1797           itme=cv->elcdofs_.find(itmd->first);
1798           if(b->valueType_==_real)
1799             {
1800               real_t v;
1801               b->getEntry(itmd->second,v);
1802               rb.setEntry(itme->second,v);
1803             }
1804           else
1805             {
1806               complex_t v;
1807               b->getEntry(itmd->second, v);
1808               rb.setEntry(itme->second,v);
1809             }
1810         }
1811 
1812       VectorEntry rbe;
1813       if(cv->matrixp()->valueType_==_complex) rbe = rb * conj(*cv->matrixp());  //warning : constraint matrix is conjugated
1814       else rbe =  rb** cv->matrixp();
1815 
1816       for(itmd=brecdofs.begin(); itmd!=brecdofs.end(); itmd++)
1817         {
1818           itme=cv->recdofs_.find(itmd->first);
1819           if(b->valueType_==_real)
1820             {
1821               real_t v1,v2;
1822               rbe.getEntry(itme->second-nbe,v1);
1823               b->getEntry(itmd->second,v2);
1824               v2-=v1;
1825               b->setEntry(itmd->second,v2);
1826             }
1827           else
1828             {
1829               complex_t v1,v2;
1830               rbe.getEntry(itme->second-nbe,v1);
1831               b->getEntry(itmd->second,v2);
1832               v2-=v1;
1833               b->setEntry(itmd->second,v2);
1834             }
1835         }
1836     }
1837   if(meth ==_pseudoReduction && cu==cv) // third step : set b eldofs to 0 or u constraints rhs only if cu==cv
1838     {
1839       std::map<DofComponent, number_t>::const_iterator itmd2=cv->elcdofs_.begin();
1840       for(itmd=belcdofs.begin(); itmd!=belcdofs.end(); itmd++, itmd2++)
1841         if(b->valueType_==_real)
1842           {
1843             real_t v=0;
1844             if(cu->rhsp()!=0) cu->rhsp()->getEntry(itmd2->second,v);
1845             b->setEntry(itmd->second,alpha.real()*v);
1846           }
1847         else
1848           {
1849             complex_t v=0;
1850             if(cu->rhsp()!=0)
1851               {
1852                 if(cu->rhsp()->valueType_ ==_real)
1853                   {
1854                     real_t r=0;
1855                     cu->rhsp()->getEntry(itmd2->second,r);
1856                     v=r;
1857                   }
1858                 else cu->rhsp()->getEntry(itmd2->second,v);
1859               }
1860             b->setEntry(itmd->second,alpha*v);
1861           }
1862     }
1863   else
1864     {
1865       if(meth !=_pseudoReduction)
1866         error("reduction_unexpected", words("reduction method",_pseudoReduction), words("reduction method",meth));
1867     }
1868   trace_p->pop();
1869 }
1870 
1871 // ---------------------------------------------------------------------------------------------------------------------------------
1872 // SetOfConstraints stuff
1873 // ---------------------------------------------------------------------------------------------------------------------------------
1874 
1875 // copy, clear, copy constructor, destructor
SetOfConstraints(const SetOfConstraints & soc)1876 SetOfConstraints::SetOfConstraints(const SetOfConstraints& soc)
1877 {
1878   copy(soc);
1879 }
1880 
operator =(const SetOfConstraints & soc)1881 SetOfConstraints& SetOfConstraints::operator = (const SetOfConstraints& soc)
1882 {
1883   if(this==&soc) return *this;
1884   clear();
1885   copy(soc);
1886   return *this;
1887 }
1888 
~SetOfConstraints()1889 SetOfConstraints::~SetOfConstraints()
1890 {
1891   clear();
1892 }
1893 
1894 // full copy, has to be cleared before
copy(const SetOfConstraints & soc)1895 void SetOfConstraints::copy(const SetOfConstraints& soc)
1896 {
1897   std::map<const Unknown*, Constraints*>::const_iterator itm=soc.begin();
1898   for(; itm!=soc.end(); itm++)
1899     if(itm->second !=0)
1900       {
1901         Constraints* c= new Constraints(*itm->second);
1902         insert(std::make_pair(itm->first,c));
1903       }
1904 }
1905 
1906 //deallocate constraints pointers and reset map to void
clear()1907 void SetOfConstraints::clear()
1908 {
1909   std::map<const Unknown*, Constraints*>::iterator itm=begin();
1910   for(; itm!=end(); itm++)
1911     if(itm->second!=0) delete itm->second;
1912   std::map<const Unknown*, Constraints*>::clear();
1913 }
1914 // some utilities
1915 
operator ()(const Unknown * u) const1916 Constraints* SetOfConstraints::operator()(const Unknown* u) const
1917 {
1918   std::map<const Unknown*, Constraints*>::const_iterator itm=find(u);
1919   if(itm == end()) return 0;
1920   return itm->second;
1921 }
1922 
isGlobal() const1923 bool SetOfConstraints::isGlobal() const    //return true if SetOfConstraints has a unique global constraints
1924 {
1925   if(size()==0) return false;
1926   if(begin()->first == 0) return true;
1927   return false;
1928 }
1929 
isReduced() const1930 bool SetOfConstraints::isReduced() const   // return true if all constraints in SetOfConstraints have been reduced
1931 {
1932   std::map<const Unknown*, Constraints*>::const_iterator itm=begin();
1933   for(; itm!=end(); itm++)
1934     {
1935       if(itm->second ==0) return false;
1936       if(!itm->second->reduced) return false;
1937     }
1938   return true;
1939 }
1940 
1941 // print utilities
print(std::ostream & os) const1942 void SetOfConstraints::print(std::ostream& os) const
1943 {
1944   std::map<const Unknown*, Constraints*>::const_iterator itm=begin();
1945   for(; itm!=end(); itm++)
1946     {
1947       if(itm->first==0) os<<"global constraints : ";
1948       else os<<"constraints on unknown "<<itm->first->name()<<" : ";
1949       if(itm->second!=0)
1950         {
1951           os<<eol;
1952           itm->second->print(os);
1953         }
1954       else os<<" void !"<<eol;
1955     }
1956 }
1957 
operator <<(std::ostream & os,const SetOfConstraints & soc)1958 std::ostream& operator<<(std::ostream& os, const SetOfConstraints& soc)
1959 {
1960   soc.print(os);
1961   return os;
1962 }
1963 
1964 } // end of namespace xlifepp
1965