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