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 SuTermVector.cpp
19   \authors D. Martin, E. Lunéville
20   \since 03 apr 2012
21   \date  13 jan 2014
22 
23   \brief Implementation of xlifepp::SuTermVector class members and related utilities
24  */
25 
26 #include "SuTermVector.hpp"
27 #include "BilinearFormAsLinearForm.hpp"
28 #include "TermMatrix.hpp"
29 #include "geometry.h"
30 #include "utils.h"
31 #include <numeric>
32 
33 
34 namespace xlifepp
35 {
36 //===============================================================================
37 //member functions of SuTermVector class
38 //===============================================================================
39 //constructors, destructor, assignment
SuTermVector(SuLinearForm * sulf,const string_t & na,bool noass)40 SuTermVector::SuTermVector(SuLinearForm* sulf, const string_t& na, bool noass)
41 {
42   termType_ = _sutermVector;
43   sulf_p = sulf;
44   name_ = na;
45   if(sulf_p != 0)  u_p = sulf_p->unknown();
46   else u_p = 0;
47   space_p = 0;
48   computingInfo_.noAssembly = noass;
49   entries_p = 0;
50   scalar_entries_p = 0;
51   if(sulf_p != 0) buildSubspaces();   //construct the required subspaces
52 }
53 
SuTermVector(const string_t & na,const Unknown * u,Space * sp,ValueType vt,number_t n,dimen_t nv,bool noass)54 SuTermVector::SuTermVector(const string_t& na, const Unknown* u, Space* sp,
55                            ValueType vt, number_t n, dimen_t nv, bool noass)
56 {
57   termType_ = _sutermVector;
58   name_ = na;
59   sulf_p = 0;
60   u_p = u;
61   space_p = sp;
62   computingInfo_.noAssembly = noass;
63   entries_p = 0;
64   scalar_entries_p = 0;
65   if(n > 0) entries_p = new VectorEntry(vt, nv, n);
66 }
67 
68 //copy constructor (full copy of entries)
SuTermVector(const SuTermVector & suV)69 SuTermVector::SuTermVector(const SuTermVector& suV)
70 {
71   copy(suV);
72 }
73 
74 //full copy of entries assuming SutermVector is clean
copy(const SuTermVector & suV)75 void SuTermVector::copy(const SuTermVector& suV)
76 {
77   termType_ = _sutermVector;
78   sulf_p = suV.sulf_p;
79   name_ = suV.name_;
80   u_p = suV.u_p;
81   space_p = suV.space_p;
82   subspaces = suV.subspaces;
83   computingInfo_ = suV.computingInfo_;
84   entries_p = 0;
85   scalar_entries_p = 0;
86   if(suV.entries_p != 0) entries_p = new VectorEntry(*suV.entries_p);
87   if(suV.scalar_entries_p != suV.entries_p && suV.scalar_entries_p != 0)
88     {
89       scalar_entries_p = new VectorEntry(*suV.scalar_entries_p);
90     }
91   cdofs_ = suV.cdofs_;
92 }
93 
94 //SuTermVector constructor from Unknown and function (no linear form). Specialization of Function or OperatorOnFunction
95 //compute f(Mi) for all Mi,Lagrange Dof of space
96 template <>
SuTermVector(const Unknown & u,const GeomDomain & dom,const OperatorOnFunction & opf,const string_t & na,bool noass)97 SuTermVector::SuTermVector(const Unknown& u, const GeomDomain& dom, const OperatorOnFunction& opf, const string_t& na, bool noass)
98 {
99   initFromFunction(u, dom, opf, na, noass);
100 }
101 
102 template <>
SuTermVector(const Unknown & u,const GeomDomain & dom,const Function & f,const string_t & na,bool noass)103 SuTermVector::SuTermVector(const Unknown& u, const GeomDomain& dom, const Function& f, const string_t& na, bool noass)
104 {
105   initFromFunction(u, dom, OperatorOnFunction(f), na, noass);
106 }
107 
SuTermVector(const Unknown & u,const GeomDomain & dom,funSR_t & f,const string_t & na,bool noass)108 SuTermVector::SuTermVector(const Unknown& u, const GeomDomain& dom, funSR_t& f, const string_t& na, bool noass)
109 {
110   Function F(f);
111   OperatorOnFunction opf(F);
112   initFromFunction(u, dom, opf, na, noass);
113 }
114 
SuTermVector(const Unknown & u,const GeomDomain & dom,funSC_t & f,const string_t & na,bool noass)115 SuTermVector::SuTermVector(const Unknown& u, const GeomDomain& dom, funSC_t& f, const string_t& na, bool noass)
116 {
117   Function F(f);
118   OperatorOnFunction opf(F);
119   initFromFunction(u, dom, opf, na, noass);
120 }
121 
SuTermVector(const Unknown & u,const GeomDomain & dom,funVR_t & f,const string_t & na,bool noass)122 SuTermVector::SuTermVector(const Unknown& u, const GeomDomain& dom, funVR_t& f, const string_t& na, bool noass)
123 {
124   Function F(f);
125   OperatorOnFunction opf(F);
126   initFromFunction(u, dom, opf, na, noass);
127 }
128 
SuTermVector(const Unknown & u,const GeomDomain & dom,funVC_t & f,const string_t & na,bool noass)129 SuTermVector::SuTermVector(const Unknown& u, const GeomDomain& dom, funVC_t& f, const string_t& na, bool noass)
130 {
131   Function F(f);
132   OperatorOnFunction opf(F);
133   initFromFunction(u, dom, opf, na, noass);
134 }
135 
136 //specialization of SuTermVector constructor from Unknown and SymbolicFunction
137 template <>
SuTermVector(const Unknown & u,const GeomDomain & dom,const SymbolicFunction & fs,const string_t & na,bool noass)138 SuTermVector::SuTermVector(const Unknown& u, const GeomDomain& dom, const SymbolicFunction& fs, const string_t& na, bool noass)
139 {
140   if(u.nbOfComponents() > 1)
141     {
142       where("SuTermVector::SuTermVector(Unknown, DOmain, SymbolicFunction, String, bool)");
143       error("unknown_not_vector");
144     }
145   termType_ = _sutermVector;
146   computingInfo_.noAssembly = noass;
147   name_ = na;
148   sulf_p = 0;
149   u_p = &u;
150   //find subspace or create it
151   Space* spu = u.space();
152   space_p = spu->findSubSpace(&dom, spu);
153   if(space_p == 0) space_p = new Space(dom, *spu, spu->name() + "_" + dom.name());
154   //allocate entries
155   number_t n = space_p->nbDofs();
156   entries_p = 0;
157   scalar_entries_p = 0;
158   if(n == 0) return;   // no entries
159   //fill entries with fs values
160   ValueType vt = fs.valueType();
161   entries_p = new VectorEntry(vt, _scalar, n, 1);
162   if(vt == _real)
163     {
164       Vector<real_t>::iterator ite = entries_p->rEntries_p->begin();
165       for(number_t i = 1; i <= n; i++, ite++) *ite = fs(space_p->dof(i).coords());
166     }
167   else
168     {
169       Vector<complex_t>::iterator ite = entries_p->cEntries_p->begin();
170       for(number_t i = 1; i <= n; i++, ite++) *ite = fs(space_p->dof(i).coords());
171     }
172   computingInfo_.isComputed = true;
173 }
174 
175 //specialization of SuTermVector constructor from Unknown and VariableName
176 template <>
SuTermVector(const Unknown & u,const GeomDomain & dom,const VariableName & vn,const string_t & na,bool noass)177 SuTermVector::SuTermVector(const Unknown& u, const GeomDomain& dom, const VariableName& vn, const string_t& na, bool noass)
178 {
179   if(u.nbOfComponents() > 1)
180     {
181       where("SuTermVector::SuTermVector(Unknown, Domain, VariableName, String, bool)");
182       error("unknown_not_vector");
183     }
184   termType_ = _sutermVector;
185   computingInfo_.noAssembly = noass;
186   name_ = na;
187   sulf_p = 0;
188   u_p = &u;
189   //find subspace or create it
190   Space* spu = u.space();
191   space_p = spu->findSubSpace(&dom, spu);
192   if(space_p == 0) space_p = new Space(dom, *spu, spu->name() + "_" + dom.name());
193   //allocate entries
194   number_t n = space_p->nbDofs();
195   entries_p = 0;
196   scalar_entries_p = 0;
197   if(n == 0) return;   // no entries
198   //create symbolic function
199   SymbolicFunction fs(vn);
200   //fill entries with fs values
201   ValueType vt = fs.valueType();
202   entries_p = new VectorEntry(vt, _scalar, n, 1);
203   if(vt == _real)
204     {
205       Vector<real_t>::iterator ite = entries_p->rEntries_p->begin();
206       for(number_t i = 1; i <= n; i++, ite++) *ite = fs(space_p->dof(i).coords());
207     }
208   else
209     {
210       Vector<complex_t>::iterator ite = entries_p->cEntries_p->begin();
211       for(number_t i = 1; i <= n; i++, ite++) *ite = fs(space_p->dof(i).coords());
212     }
213   computingInfo_.isComputed = true;
214 }
215 
216 /*! apply function to SutermVector
217     build new SutermVector Y from SuTermVector X with Y(i)=f(X(i))
218     function f has to be consistent with SuTermVector coefficients
219         use a scalar function for scalar SuTermVector and vector function for vector SuTermVector
220 */
SuTermVector(const SuTermVector & X,funSR1_t & f,const string_t & na)221 SuTermVector::SuTermVector(const SuTermVector& X, funSR1_t& f, const string_t& na)
222 {
223   if(X.strucType() != _scalar || X.valueType() != _real)
224     {
225       where("SuTermVector::SuTermVector(SuTermVector, funSR1_t, String)");
226       error("value_wrongtype", words("structure", X.strucType()), words("value", X.valueType()),
227             words("structure", _scalar), words("value", _real));
228     }
229   copy(X);
230   name_ = na;
231   if(entries_p == 0 || entries_p->rEntries_p == 0)
232     {
233       where("SuTermVector::SuTermVector(SuTermVector, funSR1_t, String)");
234       error("term_no_entries");
235     }
236   Vector<real_t>::iterator itv = entries_p->rEntries_p->begin();
237   for(; itv != entries_p->rEntries_p->end(); ++itv) *itv = f(*itv);
238   if(scalar_entries_p != 0)
239     {
240       delete scalar_entries_p;
241       scalar_entries_p = 0;
242     }
243 }
244 
SuTermVector(const SuTermVector & X,funSC1_t & f,const string_t & na)245 SuTermVector::SuTermVector(const SuTermVector& X, funSC1_t& f, const string_t& na)
246 {
247   if(X.strucType() != _scalar || X.valueType() != _complex)
248     {
249       where("SuTermVector::SuTermVector(SuTermVector, funSC1_t, String)");
250       error("value_wrongtype", words("structure", X.strucType()), words("value", X.valueType()),
251             words("structure", _scalar), words("value", _complex));
252     }
253   copy(X);
254   name_ = na;
255   if(entries_p == 0 || entries_p->cEntries_p == 0)
256     {
257       where("SuTermVector::SuTermVector(SuTermVector, funSC1_t, String)");
258       error("term_no_Entries");
259     }
260   Vector<complex_t>::iterator itv = entries_p->cEntries_p->begin();
261   for(; itv != entries_p->cEntries_p->end(); ++itv) *itv = f(*itv);
262   if(scalar_entries_p != 0)
263     {
264       delete scalar_entries_p;
265       scalar_entries_p = 0;
266     }
267 }
268 
269 /*! apply function to two SutermVector's
270     build new SutermVector Z from SuTermVectors X and Y with Z(i)=f(X(i),Y(i))
271 */
SuTermVector(const SuTermVector & X,const SuTermVector & Y,funSR2_t & f,const string_t & na)272 SuTermVector::SuTermVector(const SuTermVector& X, const SuTermVector& Y, funSR2_t& f, const string_t& na)
273 {
274   if(X.space_p != Y.space_p)
275     {
276       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, funSR2_t, String);");
277       error("term_mismatch_spaces", X.space_p->name(), Y.space_p->name());
278     }
279   if(X.strucType() != _scalar || X.valueType() != _real)
280     {
281       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, funSR2_t, String);");
282       error("value_wrongtype", words("structure", X.strucType()), words("value", X.valueType()),
283             words("structure", _scalar), words("value", _real));
284     }
285   if(X.entries_p == 0 || Y.entries_p == 0 || X.entries_p->rEntries_p == 0 || Y.entries_p->rEntries_p == 0)
286     {
287       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, funSR2_t, String);");
288       error("term_no_entries");
289     }
290   if(X.entries_p->rEntries_p->size() != Y.entries_p->rEntries_p->size())
291     {
292       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, funSR2_t, String);");
293       error("entry_mismatch_dims", X.entries_p->rEntries_p->size(), Y.entries_p->rEntries_p->size());
294     }
295   copy(X);
296   name_ = na;
297   Vector<real_t>::iterator itv = entries_p->rEntries_p->begin(), itX = X.entries_p->rEntries_p->begin(), itY = Y.entries_p->rEntries_p->begin();
298   for(; itv != entries_p->rEntries_p->end(); ++itv, ++itX, ++itY) *itv = f(*itX, *itY);
299   if(scalar_entries_p != 0)
300     {
301       delete scalar_entries_p;
302       scalar_entries_p = 0;
303     }
304 }
305 
SuTermVector(const SuTermVector & X,const SuTermVector & Y,funSC2_t & f,const string_t & na)306 SuTermVector::SuTermVector(const SuTermVector& X, const SuTermVector& Y, funSC2_t& f, const string_t& na)
307 {
308   if(X.space_p != Y.space_p)
309     {
310       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, funSC2_t, String);");
311       error("term_mismatch_spaces", X.space_p->name(), Y.space_p->name());
312     }
313   if(X.strucType() != _scalar || X.valueType() != _complex)
314     {
315       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, funSC2_t, String)");
316       error("value_wrongtype", words("structure", X.strucType()), words("value", X.valueType()),
317             words("structure", _scalar), words("value", _complex));
318     }
319   if(X.entries_p == 0 || Y.entries_p == 0 || X.entries_p->cEntries_p == 0 || Y.entries_p->cEntries_p == 0)
320     {
321       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, funSC2_t, String);");
322       error("term_no_entries");
323     }
324   if(X.entries_p->cEntries_p->size() != Y.entries_p->cEntries_p->size())
325     {
326       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, funSC2_t, String);");
327       error("entry_mismatch_dims", X.entries_p->cEntries_p->size(), Y.entries_p->cEntries_p->size());
328     }
329   copy(X);
330   name_ = na;
331   Vector<complex_t>::iterator itv = entries_p->cEntries_p->begin(), itX = X.entries_p->cEntries_p->begin(), itY = Y.entries_p->cEntries_p->begin();
332   for(; itv != entries_p->cEntries_p->end(); ++itv, ++itX, ++itY) *itv = f(*itX, *itY);
333   if(scalar_entries_p != 0)
334     {
335       delete scalar_entries_p;
336       scalar_entries_p = 0;
337     }
338 }
339 
340 //constructor from symbolic function of TermVector's
341 /*!
342    build the SuTermVector R = fs(X) where fs is a symbolic function of x
343    when X is a scalar SuTermVector, performs
344          R(i)=fs(X(i))  i=1,n   result is a scalar SuTermVector with X unknown
345    when X is a vector SuTermVector (dim=d), performs component by component
346          R_k(i)=fs(X_k(i))  i=1,n, k=1,d, result is a vector SuTermVector with X unknown
347 */
SuTermVector(const SuTermVector & X,const SymbolicFunction & fs,const string_t & na)348 SuTermVector::SuTermVector(const SuTermVector& X, const SymbolicFunction& fs, const string_t& na)
349 {
350   copy(X);
351   name_ = na;
352   bool isComplex = (fs.valueType()==_complex || X.valueType()==_complex);
353   if(isComplex && X.valueType()==_real) toComplex();
354   if(entries_p->rEntries_p != 0) //real scalar case
355     {
356       Vector<real_t>::iterator itx = X.entries_p->rEntries_p->begin();
357       if(!isComplex)
358         {
359           Vector<real_t>::iterator itr = entries_p->rEntries_p->begin();
360           for(; itr != entries_p->rEntries_p->end(); ++itx, ++itr) *itr = fs(*itx);
361         }
362       else
363         {
364           Vector<complex_t>::iterator itr = entries_p->cEntries_p->begin();
365           for(; itr != entries_p->cEntries_p->end(); ++itx, ++itr) *itr = fs(complex_t(*itx));
366         }
367     }
368   else if(entries_p->cEntries_p != 0) //complex scalar case
369     {
370       Vector<complex_t>::iterator itx = X.entries_p->cEntries_p->begin();
371       Vector<complex_t>::iterator itr = entries_p->cEntries_p->begin();
372       for(; itr != entries_p->cEntries_p->end(); ++itx,++itr) *itr = fs(*itx);
373     }
374 
375   else  // real/complex vector case
376     {
377       Unknown* us = const_cast<Unknown*>(X.up());
378       dimen_t nbc=us->nbOfComponents();
379       for(dimen_t k=0; k<nbc; ++k)
380         {
381           SuTermVector sut = SuTermVector(X(*(*us)[k+1].asComponent()),fs); //compute kth component
382           if(!isComplex)
383             {
384               Vector<Vector<real_t> >::iterator itr = entries_p->rvEntries_p->begin();
385               Vector<real_t>::iterator itxk = sut.entries_p->rEntries_p->begin();
386               for(; itr!=entries_p->rvEntries_p->end(); ++itr,++itxk)(*itr)[k]=*itxk;
387             }
388           else
389             {
390               Vector<Vector<complex_t> >::iterator itr = entries_p->cvEntries_p->begin();
391               Vector<complex_t>::iterator itxk = sut.entries_p->cEntries_p->begin();
392               for(; itr!=entries_p->cvEntries_p->end(); ++itr,++itxk)(*itr)[k]=*itxk;
393             }
394         }
395     }
396   if(scalar_entries_p != 0)
397     {
398       delete scalar_entries_p;
399       scalar_entries_p = 0;
400     }
401 }
402 
403 /*!
404    build the SuTermVector R = fs(X1,X2) where fs is a symbolic function of x1_ x2_
405    when X1 and X2 are scalar SuTermVector, performs
406          R(i)=fs(X1(i),X2(i))  i=1,n   result is a scalar SuTermVector with X1 unknown
407    when X1 is a vector SuTermVector (dim=d) and X2 a scalar SuTermvector, performs component by component
408          R_k(i)=fs(X1_k(i),X2(i))  i=1,n, k=1,d, result is a vector SuTermVector with X1 unknown
409    when X1 is a scalar SuTermVector and X2 a vector SuTermvector (dim=d), performs component by component
410          R_k(i)=fs(X1(i),X2_k(i))  i=1,n, k=1,d, result is a vector SuTermVector with X2 unknown
411    when X1 and X2 are both vector SuTermvector, computation is not available
412 
413    NB : unknown can be change later using changeUnknown function
414 */
SuTermVector(const SuTermVector & X1,const SuTermVector & X2,const SymbolicFunction & fs,const string_t & na)415 SuTermVector::SuTermVector(const SuTermVector& X1, const SuTermVector& X2, const SymbolicFunction& fs, const string_t& na)
416 {
417   if(X1.space_p != X2.space_p)
418     {
419       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, SymbolicFunction, String);");
420       error("term_mismatch_spaces", X1.space_p->name(), X2.space_p->name());
421     }
422   if(X1.entries_p == 0 || X2.entries_p == 0)
423     {
424       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, SymbolicFunction, String)");
425       error("term_no_entries");
426     }
427 
428   bool fsIsComplex = (fs.valueType()==_complex);
429   name_ = na;
430   if(X1.strucType() == _scalar && X2.strucType() ==_scalar) //scalar case
431     {
432 
433       if(X1.entries_p->rEntries_p != 0)  //X1 is real
434         {
435           Vector<real_t>::const_iterator itv1 = X1.entries_p->rEntries_p->begin();
436           copy(X1);
437           if(X2.entries_p->rEntries_p != 0)    //X2 is real
438             {
439               if(!fsIsComplex) //real result
440                 {
441                   Vector<real_t>::iterator itv2 = X2.entries_p->rEntries_p->begin();
442                   Vector<real_t>::iterator itvr = entries_p->rEntries_p->begin();
443                   for(; itvr != entries_p->rEntries_p->end(); ++itv1, ++itv2, ++itvr) *itvr = fs(*itv1, *itv2);
444                 }
445               else //complex result
446                 {
447                   toComplex(); //move to complex
448                   Vector<real_t>::iterator itv2 = entries_p->rEntries_p->begin();
449                   Vector<complex_t>::iterator itvr = entries_p->cEntries_p->begin();
450                   for(; itvr != entries_p->cEntries_p->end(); ++itv1, ++itv2, ++itvr) *itvr = fs(complex_t(*itv1), complex_t(*itv2));
451                 }
452             }
453           else if(X2.entries_p->cEntries_p != 0) //X2 is complex
454             {
455               toComplex(); //move to complex
456               Vector<complex_t>::iterator itv2 = X2.entries_p->cEntries_p->begin();
457               Vector<complex_t>::iterator itvr = entries_p->cEntries_p->begin();
458               for(; itvr != entries_p->cEntries_p->end(); ++itv1, ++itv2, ++itvr) *itvr = fs(complex_t(*itv1), *itv2);
459             }
460         }
461       else // X1 is complex, result is complex
462         {
463           copy(X1);
464           Vector<complex_t>::iterator itv1 = entries_p->cEntries_p->begin();
465           if(X2.entries_p->rEntries_p != 0)  // X2 is real
466             {
467               Vector<real_t>::const_iterator itv2 = X2.entries_p->rEntries_p->begin();
468               Vector<complex_t>::iterator itvr = entries_p->cEntries_p->begin();
469               for(; itvr != entries_p->cEntries_p->end(); ++itv1, ++itv2, ++itvr) *itv1 = fs(*itv1, complex_t(*itv2));
470             }
471           else
472             {
473               Vector<complex_t>::const_iterator itv2 = X2.entries_p->cEntries_p->begin();
474               for(; itv1 != entries_p->cEntries_p->end(); ++itv1, ++itv2) *itv1 = fs(*itv1, *itv2);
475             }
476         }
477       //remove scalar representation
478       if(scalar_entries_p != 0)
479         {
480           delete scalar_entries_p;
481           scalar_entries_p = 0;
482         }
483       return;  //end of scalar case
484     }
485 
486   //vector case
487   if(X1.strucType() != _scalar && X2.strucType() !=_scalar)  //two vector SuTermVector not available
488     {
489       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, SymbolicFunction, String)");
490       error("term_unhandled_structures", words("structure", X1.strucType()), words("structure", X2.strucType()),fs.asString());
491     }
492   Unknown* us =0;
493   dimen_t nbc=0;
494   bool isComplex = false;
495   bool X1isVector=true;
496   if(X1.strucType() != _scalar) // X1 vector, X2 scalar
497     {
498       us = const_cast<Unknown*>(X1.up());
499       nbc=us->nbOfComponents();
500       copy(X1);
501       isComplex = (fs.valueType()==_complex || X2.valueType()==_complex || X1.valueType()==_complex);
502       if(isComplex && X1.valueType()==_real) toComplex();
503     }
504   else // X2 vector, X1 scalar
505     {
506       X1isVector=false;
507       us = const_cast<Unknown*>(X2.up());
508       nbc=us->nbOfComponents();
509       copy(X2);
510       isComplex = (fs.valueType()==_complex || X2.valueType()==_complex || X1.valueType()==_complex);
511       if(isComplex && X2.valueType()==_real) toComplex();
512     }
513   for(dimen_t k=0; k<nbc; ++k)
514     {
515       SuTermVector sut;
516       if(X1isVector) sut = SuTermVector(X1(*(*us)[k+1].asComponent()),X2,fs); //compute kth component
517       else sut = SuTermVector(X1,X2(*(*us)[k+1].asComponent()),fs);           //compute kth component
518       if(!isComplex)
519         {
520           Vector<Vector<real_t> >::iterator itvr = entries_p->rvEntries_p->begin();
521           Vector<real_t>::iterator itvk = sut.entries_p->rEntries_p->begin();
522           for(; itvr!=entries_p->rvEntries_p->end(); ++itvr,++itvk)(*itvr)[k]=*itvk;
523         }
524       else
525         {
526           Vector<Vector<complex_t> >::iterator itvr = entries_p->cvEntries_p->begin();
527           Vector<complex_t>::iterator itvk = sut.entries_p->cEntries_p->begin();
528           for(; itvr!=entries_p->cvEntries_p->end(); ++itvr,++itvk)(*itvr)[k]=*itvk;
529         }
530     }
531   //remove scalar representation
532   if(scalar_entries_p != 0)
533     {
534       delete scalar_entries_p;
535       scalar_entries_p = 0;
536     }
537 }
538 
539 /*!
540    build the SuTermVector R = fs(X1,X2,X3) where fs is a symbolic function of x_1 x_2 x_3 :
541      R(i)=fs(X1(i),X2(i),X3(i))  i=1,n
542    X1, X2, X3 have to be three scalar SutermVectors defined on the same space
543    the unknown of the SuTermVector result is the unknown of X1
544    it can be change later using changeUnknown function
545 */
SuTermVector(const SuTermVector & X1,const SuTermVector & X2,const SuTermVector & X3,const SymbolicFunction & fs,const string_t & na)546 SuTermVector::SuTermVector(const SuTermVector& X1, const SuTermVector& X2, const SuTermVector& X3,
547                            const SymbolicFunction& fs, const string_t& na)
548 {
549   if(X1.space_p != X2.space_p)
550     {
551       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, SuTermVector, SymbolicFunction, String);");
552       error("term_mismatch_spaces", X1.space_p->name(), X2.space_p->name());
553     }
554   if(X1.space_p != X3.space_p)
555     {
556       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, SuTermVector, SymbolicFunction, String);");
557       error("term_mismatch_spaces", X1.space_p->name(), X2.space_p->name());
558     }
559   if(X1.strucType() != _scalar)
560     {
561       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, SuTermVector, SymbolicFunction, String)");
562       error("term_mismatch_structures", words("structure", X1.strucType()), words("structure", _scalar));
563     }
564   if(X2.strucType() != _scalar)
565     {
566       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, SuTermVector, SymbolicFunction, String)");
567       error("term_mismatch_structures", words("structure", X2.strucType()), words("structure", _scalar));
568     }
569   if(X3.strucType() != _scalar)
570     {
571       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, SuTermVector, SymbolicFunction, String)");
572       error("term_mismatch_structures", words("structure", X3.strucType()), words("structure", _scalar));
573     }
574   if(X1.entries_p == 0 || X2.entries_p == 0 || X3.entries_p == 0)
575     {
576       where("SuTermVector::SuTermVector(SuTermVector, SuTermVector, SuTermVector, SymbolicFunction, String)");
577       error("term_no_entries");
578     }
579 
580   name_ = na;
581   bool fsIsComplex = (fs.valueType()==_complex);
582   ValueType vt1 = X1.valueType(), vt2 = X2.valueType(), vt3 = X3.valueType();
583   copy(X1);
584   if((vt2==_complex || vt3==_complex || fsIsComplex) && vt1==_real) toComplex();
585 
586   if(vt1 == _real)
587     {
588       Vector<real_t>::const_iterator itv1 = X1.entries_p->rEntries_p->begin();
589       if(vt2 == _real)
590         {
591           Vector<real_t>::const_iterator itv2 = X2.entries_p->rEntries_p->begin();
592           if(vt3 == _real)
593             {
594               Vector<real_t>::const_iterator itv3 = X3.entries_p->rEntries_p->begin();
595               if(!fsIsComplex)
596                 {
597                   Vector<real_t>::iterator itvr = entries_p->rEntries_p->begin();
598                   for(; itvr != entries_p->rEntries_p->end(); ++itvr, ++itv1, ++itv2, ++itv3) *itvr = fs(*itv1, *itv2, *itv3);
599                 }
600               else
601                 {
602                   Vector<complex_t>::iterator itvr = entries_p->cEntries_p->begin();
603                   for(; itvr != entries_p->cEntries_p->end(); ++itvr, ++itv1, ++itv2, ++itv3) *itvr = fs(complex_t(*itv1), complex_t(*itv2), complex_t(*itv3));
604                 }
605             }
606           else // X3 is complex
607             {
608               Vector<complex_t>::const_iterator itv3 = entries_p->cEntries_p->begin();
609               Vector<complex_t>::iterator itvr = entries_p->cEntries_p->begin();
610               for(; itvr != entries_p->cEntries_p->end(); ++itvr, ++itv1, ++itv2, ++itv3) *itvr = fs(complex_t(*itv1), complex_t(*itv2), *itv3);
611             }
612         }
613       else // X2 is complex
614         {
615           Vector<complex_t>::const_iterator itv2 = entries_p->cEntries_p->begin();
616           if(vt3 == _real)   //X3 is real
617             {
618               Vector<real_t>::const_iterator itv3 = X3.entries_p->rEntries_p->begin();
619               Vector<complex_t>::iterator itvr = entries_p->cEntries_p->begin();
620               for(; itvr != entries_p->cEntries_p->end(); ++itvr, ++itv1, ++itv2, ++itv3) *itvr = fs(complex_t(*itv1), *itv2, complex_t(*itv3));
621             }
622           else //X3 is complex
623             {
624               Vector<complex_t>::const_iterator itv3 = X3.entries_p->cEntries_p->begin();
625               Vector<complex_t>::iterator itvr = entries_p->cEntries_p->begin();
626               for(; itvr != entries_p->cEntries_p->end(); ++itvr, ++itv1, ++itv2, ++itv3) *itvr = fs(complex_t(*itv1), *itv2, *itv3);
627             }
628         }
629     }
630   else //X1 is complex
631     {
632       Vector<complex_t>::iterator itv1 = entries_p->cEntries_p->begin();
633       if(vt2 == _real)  //X2 is real
634         {
635           Vector<real_t>::const_iterator itv2 = X2.entries_p->rEntries_p->begin();
636           if(vt3 == _real)  //X3 is real
637             {
638               Vector<real_t>::const_iterator itv3 = X3.entries_p->rEntries_p->begin();
639               Vector<complex_t>::iterator itvr = entries_p->cEntries_p->begin();
640               for(; itvr != entries_p->cEntries_p->end(); ++itvr, ++itv1, ++itv2, ++itv3) *itvr = fs(*itv1, complex_t(*itv2), complex_t(*itv3));
641             }
642           else //X3 is complex
643             {
644               Vector<complex_t>::const_iterator itv3 = X3.entries_p->cEntries_p->begin();
645               Vector<complex_t>::iterator itvr = entries_p->cEntries_p->begin();
646               for(; itvr != entries_p->cEntries_p->end(); ++itvr, ++itv1, ++itv2, ++itv3) *itvr = fs(*itv1, complex_t(*itv2), *itv3);
647             }
648         }
649       else //X2 is complex
650         {
651           Vector<complex_t>::const_iterator itv2 = X2.entries_p->cEntries_p->begin();
652           if(vt3 == _real)  //X3 is real
653             {
654               Vector<real_t>::const_iterator itv3 = X3.entries_p->rEntries_p->begin();
655               Vector<complex_t>::iterator itvr = entries_p->cEntries_p->begin();
656               for(; itvr != entries_p->cEntries_p->end(); ++itvr, ++itv1, ++itv2, ++itv3) *itvr = fs(*itv1, *itv2, complex_t(*itv3));
657             }
658           else //X3 is complex
659             {
660               Vector<complex_t>::const_iterator itv3 = X3.entries_p->cEntries_p->begin();
661               Vector<complex_t>::iterator itvr = entries_p->cEntries_p->begin();
662               for(; itvr != entries_p->cEntries_p->end(); ++itvr, ++itv1, ++itv2, ++itv3) *itvr = fs(*itv1, *itv2, *itv3);
663             }
664         }
665     }
666   if(scalar_entries_p != 0)
667     {
668       delete scalar_entries_p;
669       scalar_entries_p = 0;
670     }
671 }
672 
673 /*! construct vector SutermVector from 2 scalar SuTermVector's
674     scalar SuTermVector's have to be defined on the same space
675     vu has to be a vector unknown at least d=2 */
SuTermVector(const Unknown & vu,const SuTermVector & X1,const SuTermVector & X2,const string_t & na)676 SuTermVector::SuTermVector(const Unknown& vu, const SuTermVector& X1, const SuTermVector& X2, const string_t& na)
677 {
678   if(X1.strucType()!=_scalar || X2.strucType()!=_scalar)
679     {
680       where("SuTermVector::SuTermVector(Unknown, SuTermVector,SuTermVector)");
681       error("term_nonscalar");
682     }
683   number_t nbc=vu.nbOfComponents();
684   if(nbc<2)
685     {
686       where("SuTermVector::SuTermVector(Unknown, SuTermVector,SuTermVector)");
687       error("unknown_vector",2);
688     }
689   if(X1.space_p!=X2.space_p)
690     {
691       where("SuTermVector::SuTermVector(Unknown, SuTermVector,SuTermVector)");
692       error("term_mismatch_spaces", X1.space_p->name(), X2.space_p->name());
693     }
694   name_ = na;
695   ValueType vt=X1.valueType();
696   if(X2.valueType()==_complex) vt = _complex;
697   space_p=X1.space_p;
698   sulf_p=0;
699   u_p=&vu;
700   scalar_entries_p = 0;
701   entries_p=new VectorEntry(vt, _vector, X1.nbDofs(), nbc);
702   if(vt==_real)
703     {
704       Vector<real_t>::const_iterator it1 = X1.entries_p->rEntries_p->begin(),
705                                      it2 = X2.entries_p->rEntries_p->begin();
706       Vector<Vector<real_t> >::iterator itv = entries_p->rvEntries_p->begin();
707       for(; itv!=entries_p->rvEntries_p->end(); ++itv,++it1,++it2)
708         {(*itv)[0]=*it1; (*itv)[1]=*it2;}
709     }
710   else
711     {
712       Vector<Vector<complex_t> >::iterator itv = entries_p->cvEntries_p->begin();
713       if(X1.valueType()==_real) // X2 is complex
714         {
715           Vector<real_t>::const_iterator it1 = X1.entries_p->rEntries_p->begin();
716           Vector<complex_t>::const_iterator it2 = X2.entries_p->cEntries_p->begin();
717           for(; itv!=entries_p->cvEntries_p->end(); ++itv,++it1,++it2)
718             {(*itv)[0]=*it1; (*itv)[1]=*it2;}
719         }
720       else //X1 is complex
721         {
722           if(X2.valueType()==_real) // X2 is real
723             {
724               Vector<complex_t>::const_iterator it1 = X1.entries_p->cEntries_p->begin();
725               Vector<real_t>::const_iterator it2 = X2.entries_p->rEntries_p->begin();
726               for(; itv!=entries_p->cvEntries_p->end(); ++itv,++it1,++it2)
727                 {(*itv)[0]=*it1; (*itv)[1]=*it2;}
728             }
729           else //X3 complex
730             {
731               Vector<complex_t>::const_iterator it1 = X1.entries_p->cEntries_p->begin();
732               Vector<complex_t>::const_iterator it2 = X2.entries_p->cEntries_p->begin();
733               for(; itv!=entries_p->cvEntries_p->end(); ++itv,++it1,++it2)
734                 {(*itv)[0]=*it1; (*itv)[1]=*it2;}
735             }
736         }
737     }
738   computingInfo_.isComputed = true;
739 }
740 
741 /*! construct vector SutermVector from n scalar SuTermVector's
742     scalar SuTermVector's have to be defined on the same space
743     vu has to be a vector unknown at least n */
SuTermVector(const Unknown & vu,const std::list<const SuTermVector * > & Xs,const string_t & na)744 SuTermVector::SuTermVector(const Unknown& vu, const std::list<const SuTermVector*>& Xs, const string_t& na)
745 {
746   number_t nbX=Xs.size();
747   if(nbX<2)
748     {
749       where("SuTermVector::SuTermVector(Unknown,list<const SuTermVector*>)");
750       error("term_not_enough",2);
751     }
752   number_t nbc=vu.nbOfComponents();
753   if(nbc<nbX)
754     {
755       where("SuTermVector::SuTermVector(Unknown,list<const SuTermVector*>)");
756       error("unknown_vector",nbX);
757     }
758   Space* sp=0;
759   ValueType vt=_real;
760   std::list<const SuTermVector*>::const_iterator itX=Xs.begin();
761   sp=(*itX)->space_p;
762   number_t n=(*itX)->nbDofs();
763   for(; itX!=Xs.end(); ++itX)
764     {
765       const SuTermVector& X=**itX;
766       if(X.space_p!=sp)
767         {
768           where("SuTermVector::SuTermVector(Unknown,list<const SuTermVector*>)");
769           error("term_mismatch_spaces", X.space_p->name(), sp->name());
770         }
771       if(X.valueType()==_complex) vt=_complex;
772     }
773   name_ = na;
774   space_p=sp;
775   sulf_p=0;
776   u_p=&vu;
777   scalar_entries_p = 0;
778   entries_p=new VectorEntry(vt, _vector, n, nbc);
779   if(vt==_real)  //all SuTermVector are real
780     {
781       std::list<Vector<real_t>::const_iterator> itlist;
782       for(itX=Xs.begin(); itX!=Xs.end(); ++itX) itlist.push_back((*itX)->entries_p->rEntries_p->begin());
783       std::list<Vector<real_t>::const_iterator>::iterator itl;
784       Vector<Vector<real_t> >::iterator itv = entries_p->rvEntries_p->begin();
785       for(; itv!=entries_p->rvEntries_p->end(); ++itv)
786         {
787           Vector<real_t>::iterator it=itv->begin();
788           for(itl=itlist.begin(); itl!=itlist.end(); ++it,++itl) {*it=**itl; (*itl)++;}
789         }
790     }
791   else // complex result
792     {
793       Vector<Vector<complex_t> >::iterator itv;
794       number_t k=0;
795       for(itX=Xs.begin(); itX!=Xs.end(); ++itX, k++)
796         {
797           const SuTermVector& X=**itX;
798           if(X.valueType()==_real)
799             {
800               Vector<real_t>::const_iterator it=X.entries_p->rEntries_p->begin();
801               for(itv = entries_p->cvEntries_p->begin(); itv!=entries_p->cvEntries_p->end(); ++itv,++it)(*itv)[k]=*it;
802             }
803 
804           else
805             {
806               Vector<complex_t>::const_iterator it=X.entries_p->cEntries_p->begin();
807               for(itv = entries_p->cvEntries_p->begin(); itv!=entries_p->cvEntries_p->end(); ++itv,++it)(*itv)[k]=*it;
808             }
809         }
810     }
811   computingInfo_.isComputed = true;
812 }
813 
initFromFunction(const Unknown & u,const GeomDomain & dom,const OperatorOnFunction & opf,const string_t & na,bool noass)814 void SuTermVector::initFromFunction(const Unknown& u, const GeomDomain& dom, const OperatorOnFunction& opf,
815                                     const string_t& na, bool noass)
816 {
817   termType_ = _sutermVector;
818   computingInfo_.noAssembly = noass;
819   name_ = na;
820   sulf_p = 0;
821   u_p = &u;
822 
823   //find subspace or create it
824   Space* spu = u.space();
825   space_p = spu->findSubSpace(&dom, spu);
826   if(space_p == 0) space_p = new Space(dom, *spu, spu->name() + "_" + dom.name());
827 
828   //allocate entries
829   number_t n = space_p->nbDofs(), nv = number_t(u.nbOfComponents());
830   entries_p = 0;
831   scalar_entries_p = 0;
832   if(n == 0) return;   // no entries
833 
834   //check structure of function
835   if(opf.strucType()==_matrix)
836     {
837       where("SuTermVector::initFromFunction(Unknown, Domain, OperatorOnFunction, String, bool)");
838       error("scalar_or_vector");
839     }
840   if(nv != opf.dims().first)
841     {
842       where("SuTermVector::initFromFunction(Unknown, Domain, OperatorOnFunction, String, bool)");
843       error("operator_fct_mismatch_dims", nv, opf.dims().first);
844     }
845 
846   //compute normal vectors if function required them (function parameters contains "_n" parameter)
847   bool nor = opf.normalRequired(), norf = opf.funp()->requireNx;
848   const MeshDomain* mdom = dom.meshDomain();
849   if(mdom == 0)
850     {
851       where("SuTermVector::initFromFunction(Unknown, Domain, OperatorOnFunction, String, bool)");
852       error("domain_notmesh", dom.name(), words("domain type", dom.domType()));
853     }
854 
855   if(nor && !(mdom->isSideDomain() || mdom->spaceDim() > mdom->dim()))    //when function has "_n" as parameter but computation does not occur on a side domain
856     {
857       where("SuTermVector::initFromFunction(Unknown, Domain, OperatorOnFunction, String, bool)");
858       warning("normal_ignored",mdom->name());
859       nor = false;
860     }
861   std::vector<Vector<real_t> > ns;
862   if(nor)
863     {
864       if(dom.meshDomain() == 0)
865         {
866           where("SuTermVector::initFromFunction(const Unknown&, const GeomDomain&, const OperatorOnFunction&, const String&, bool)");
867           error("domain_notmesh", dom.name(), words("domain type", dom.domType()));
868         }
869       if(!dom.meshDomain()->orientationComputed) dom.meshDomain()->setNormalOrientation();
870       interpolatedNormals(*space_p, ns);
871     }
872 
873   //flag to transmit dof pointer tp function parameters
874   bool assDof = opf.funp()->requireDof;
875 
876   //fill entries with f values
877   Vector<real_t>* np = 0;
878   ValueType vt = opf.valueType();
879   StrucType st = opf.strucType();
880   entries_p = new VectorEntry(vt, st, n, nv);
881   if(vt == _real)
882     {
883       if(st == _scalar)
884         {
885           Vector<real_t>::iterator ite = entries_p->rEntries_p->begin();
886 #ifdef XLIFEPP_WITH_OMP
887           #pragma omp parallel for firstprivate(np)
888 #endif // XLIFEPP_WITH_OMP
889           for(number_t i = 0; i < n; i++)
890             {
891               if(nor)
892                 {
893                   np = &ns[i];
894                   if(norf) setNx(np);
895                 }
896               if(assDof) setDof(const_cast<Dof*>(&space_p->dof(i + 1)));
897               opf.eval(space_p->dof(i + 1).coords(), *(ite+i), np);
898             }
899         }
900       if(st == _vector)
901         {
902           Vector<Vector<real_t> >::iterator ite = entries_p->rvEntries_p->begin();
903 #ifdef XLIFEPP_WITH_OMP
904           #pragma omp parallel for firstprivate(np)
905 #endif // XLIFEPP_WITH_OMP
906           for(number_t i = 0; i < n; i++)
907             {
908               if(nor)
909                 {
910                   np = &ns[i];
911                   if(norf) setNx(np);
912                 }
913               if(assDof) setDof(const_cast<Dof*>(&space_p->dof(i + 1)));
914               opf.eval(space_p->dof(i + 1).coords(), *(ite+i), np);
915             }
916         }
917     }
918   if(vt == _complex)
919     {
920       if(st == _scalar)
921         {
922           Vector<complex_t>::iterator ite = entries_p->cEntries_p->begin();
923 #ifdef XLIFEPP_WITH_OMP
924           #pragma omp parallel for firstprivate(np)
925 #endif // XLIFEPP_WITH_OMP
926           for(number_t i = 0; i < n; i++)
927             {
928               if(nor)
929                 {
930                   np = &ns[i];
931                   if(norf) setNx(np);
932                 }
933               if(assDof) setDof(const_cast<Dof*>(&space_p->dof(i + 1)));
934               opf.eval(space_p->dof(i + 1).coords(), *(ite+i), np);
935             }
936         }
937       if(st == _vector)
938         {
939           Vector<Vector<complex_t> >::iterator ite = entries_p->cvEntries_p->begin();
940 #ifdef XLIFEPP_WITH_OMP
941           #pragma omp parallel for firstprivate(np)
942 #endif // XLIFEPP_WITH_OMP
943           for(number_t i = 0; i < n; i++)
944             {
945               if(nor)
946                 {
947                   np = &ns[i];
948                   if(norf) setNx(np);
949                 }
950               if(assDof) setDof(const_cast<Dof*>(&space_p->dof(i + 1)));
951               opf.eval(space_p->dof(i + 1).coords(), *(ite+i), np);
952             }
953         }
954     }
955   computingInfo_.isComputed = true;
956 }
957 
958 /*! SuTermVector from the restriction of a SuTermVector to a given domain dom
959     raise an error if dom does not intersect the SutermVector domain
960     SutermVector sutv has to be computed and its entries_p has to be non zero
961     In case of entries_p==0 and scalar_entries_p!=0 goto vector representation before calling this
962 */
SuTermVector(const SuTermVector & sutv,const GeomDomain & dom,const string_t & na)963 SuTermVector::SuTermVector(const SuTermVector& sutv, const GeomDomain& dom, const string_t& na)
964 {
965   termType_ = _sutermVector;
966   sulf_p = 0;
967   u_p = 0;
968   space_p = 0;
969   entries_p = 0;
970   scalar_entries_p = 0;
971   if(!sutv.computed())
972     {
973       where("SuTermVector::SuTermVector");
974       error("not_computed_term", sutv.name());
975     }
976   if(domain() == &dom)  //same domain
977     {
978       copy(sutv);
979       where("SuTermVector::SuTermVector");
980       warning("free_warning", "SuTermVector(SuTermVector,GeomDomain): no restriction to do, full copy");
981     }
982 
983   Space* spu = sutv.u_p->space();
984   space_p = spu->findSubSpace(&dom, spu);
985   if(space_p == 0) space_p = new Space(dom, *spu, spu->name() + "_" + dom.name());
986   u_p = sutv.u_p;
987   number_t n = space_p->nbDofs(), nv = number_t(sutv.u_p->nbOfComponents());
988   if(n == 0)
989     {
990       where("SuTermVector::SuTermVector");
991       error("space_no_dof", space_p->name());
992     }
993   VectorEntry* ove = sutv.entries_p;
994   VectorEntry* sove = sutv.scalar_entries_p;
995   if(ove == 0)  //no standard entries
996     {
997       if(sove == 0)
998         {
999           where("SuTermVector::SuTermVector");
1000           error("term_no_entries");
1001         }
1002       else
1003         {
1004           where("SuTermVector::SuTermVector");
1005           error("entry_inconsistent_structure");
1006         }
1007     }
1008 
1009   std::vector<number_t> r = renumber(spu, space_p);
1010   number_t p = number_t(r.size());
1011   if(n == 0)  //no renumbering, copy all entries
1012     {
1013       entries_p = new VectorEntry(*sutv.entries_p);
1014     }
1015   else
1016     {
1017       entries_p = new VectorEntry(sutv.entries_p->valueType_, sutv.entries_p->strucType_, p, nv);
1018       std::vector<number_t>::iterator itr = r.begin();
1019       number_t k = 1;
1020       for(; itr != r.end(); itr++, k++)
1021         {
1022           number_t i = *itr;
1023           if(i != 0) entries_p->setValue(k, ove->getValue(i));
1024         }
1025     }
1026   computingInfo_.isComputed = true;
1027 }
1028 
1029 // SuTermVector from a linear combination of SuTermVector's
SuTermVector(const LcTerm<SuTermVector> & lc)1030 SuTermVector::SuTermVector(const LcTerm<SuTermVector>& lc)
1031 {
1032   termType_ = _sutermVector;
1033   sulf_p = 0;
1034   u_p = 0;
1035   space_p = 0;
1036   entries_p = 0;
1037   scalar_entries_p = 0;
1038   compute(lc);
1039 }
1040 
1041 // assign operator (full copy)
operator =(const SuTermVector & suV)1042 SuTermVector& SuTermVector::operator=(const SuTermVector& suV)
1043 {
1044   clear();
1045   copy(suV);
1046   return *this;
1047 }
1048 
1049 /*! construct SuTermVector from a SuTermVector with geometrical mapping, the unknowns may differ
1050     this process involves mesh interpolation and is restricted to Lagrange interpolation spaces
1051     it is assumed that the two unknowns have same structure
1052     - if fmap =0, identity is assumed
1053     - if errorOnOutDom = true the program stop on error, else the interpolated value is set to 0
1054 */
SuTermVector(const Unknown & u,const GeomDomain & dom,const SuTermVector & sut,const Function * fmap,bool errorOnOutDom,const string_t & na)1055 SuTermVector::SuTermVector(const Unknown& u, const GeomDomain& dom, const SuTermVector& sut,
1056                            const Function* fmap, bool errorOnOutDom, const string_t& na)
1057 {
1058   termType_ = _sutermVector;
1059   name_ = na;
1060   sulf_p = 0;
1061   u_p = &u;
1062   Space* spu = u.space();
1063   space_p = spu->findSubSpace(&dom, spu);
1064   if(space_p == 0) space_p = new Space(dom, *spu, spu->name() + "_" + dom.name());
1065   number_t n = space_p->nbDofs(), nv = number_t(u.nbOfComponents());
1066   entries_p = 0;
1067   scalar_entries_p = 0;
1068   if(!sut.computed())
1069     {
1070       where("SuTermVector::SuTermVector");
1071       error("not_computed_term", "SuTermVector");
1072     }
1073   //if (nv!=sut.nbOfComponents())
1074   if(nv != sut.entries()->nbOfComponents)
1075     {
1076       where("SuTermVector::SuTermVector");
1077       error("term_mismatch_nb_components", nv, sut.entries()->nbOfComponents);
1078     }
1079   if(!spu->isFE())
1080     {
1081       where("SuTermVector::SuTermVector");
1082       error("not_fe_space_type", spu->name());
1083     }
1084   if(spu->feSpace()->interpolation()->type != _Lagrange)
1085     {
1086       where("SuTermVector::SuTermVector");
1087       error("lagrange_fe_space_only", spu->name());
1088     }
1089   ValueType vt = sut.valueType();
1090   StrucType st = sut.strucType();
1091   entries_p = new VectorEntry(vt, st, n, nv);
1092   //prepare interpolation
1093   Space* spdom = sut.space_p;
1094   const MeshDomain* mdom = spdom->domain()->meshDomain();
1095   mdom->buildKdTree();            //if not exist, create kdtree for fast location of points
1096   std::map<GeomElement*, const Element*> gelt2elt;
1097 
1098   for(number_t k = 0; k < spdom->nbOfElements(); k++)
1099     {
1100       const Element* elt = spdom->element_p(k);
1101       gelt2elt[elt->geomElt_p] = elt;
1102     }
1103   std::vector<real_t> v;
1104   //do interpolation
1105   if(vt == _real)
1106     {
1107       if(st == _scalar)
1108         {
1109           Vector<real_t>::iterator ite = entries_p->rEntries_p->begin();
1110           for(number_t i = 0; i < n; i++, ite++)
1111             {
1112               Point pt = space_p->dof(i + 1).coords();
1113               if(fmap != 0) pt = (*fmap)(space_p->dof(i + 1).coords(), v);  //map to dom
1114               GeomElement* gelt = mdom->locate(pt);
1115               if(gelt == 0)
1116                 {
1117                   if(errorOnOutDom) locateError("in SutermVector constructor with mapping", *mdom, pt);
1118                   *ite = 0.;
1119                 }
1120               else
1121                 {
1122                   const Element* elt = gelt2elt[gelt];
1123                   elt->interpolate(*sut.entries_p, pt, elt->dofNumbers, *ite);
1124                 }
1125             }
1126         }
1127       if(st == _vector)
1128         {
1129           Vector<Vector<real_t> >::iterator ite = entries_p->rvEntries_p->begin();
1130           Vector<real_t> zero(nv, 0.);
1131           for(number_t i = 0; i < n; i++, ite++)
1132             {
1133               Point pt = space_p->dof(i + 1).coords();
1134               if(fmap != 0) pt = (*fmap)(space_p->dof(i + 1).coords(), v);  //map to dom
1135               GeomElement* gelt = mdom->locate(pt);
1136               if(gelt == 0)
1137                 {
1138                   if(errorOnOutDom) locateError("in SutermVector constructor with mapping", *mdom, pt);
1139                   *ite = zero;
1140                 }
1141               else
1142                 {
1143                   const Element* elt = gelt2elt[gelt];
1144                   elt->interpolate(*sut.entries_p, pt, elt->dofNumbers, *ite);
1145                 }
1146             }
1147         }
1148     }
1149   if(vt == _complex)
1150     {
1151       if(st == _scalar)
1152         {
1153           Vector<complex_t>::iterator ite = entries_p->cEntries_p->begin();
1154           for(number_t i = 0; i < n; i++, ite++)
1155             {
1156               Point pt = space_p->dof(i + 1).coords();
1157               if(fmap != 0) pt = (*fmap)(space_p->dof(i + 1).coords(), v);  //map to dom
1158               GeomElement* gelt = mdom->locate(pt);
1159               if(gelt == 0)
1160                 {
1161                   if(errorOnOutDom) locateError("in SutermVector constructor with mapping", *mdom, pt);
1162                   *ite = 0.;
1163                 }
1164               else
1165                 {
1166                   const Element* elt = gelt2elt[gelt];
1167                   elt->interpolate(*sut.entries_p, pt, elt->dofNumbers, *ite);
1168                 }
1169             }
1170         }
1171       if(st == _vector)
1172         {
1173           Vector<Vector<complex_t> >::iterator ite = entries_p->cvEntries_p->begin();
1174           Vector<complex_t> zero(nv, 0.);
1175           for(number_t i = 0; i < n; i++, ite++)
1176             {
1177               Point pt = space_p->dof(i + 1).coords();
1178               if(fmap != 0) pt = (*fmap)(space_p->dof(i + 1).coords(), v);  //map to dom
1179               GeomElement* gelt = mdom->locate(pt);
1180               if(gelt == 0)
1181                 {
1182                   if(errorOnOutDom) locateError("in SutermVector constructor with mapping", *mdom, pt);
1183                   *ite = zero;
1184                 }
1185               else
1186                 {
1187                   const Element* elt = gelt2elt[gelt];
1188                   elt->interpolate(*sut.entries_p, pt, elt->dofNumbers, *ite);
1189                 }
1190             }
1191         }
1192     }
1193   computingInfo_.isComputed = true;
1194 }
1195 
1196 /*! produce the mapped SuTermVector from current GeomDomains to GeomDomain dom
1197     current SuTermVector has to be already computed
1198 */
mapTo(const GeomDomain & dom,const Unknown & u,bool errOnOut) const1199 SuTermVector* SuTermVector::mapTo(const GeomDomain& dom, const Unknown& u, bool errOnOut) const
1200 {
1201   trace_p->push("SuTermVector::mapTo");
1202   if(!computed()) error("not_computed_term", "SuTermVector");
1203   SuTermVector* sut = 0;
1204   const GeomDomain* curdom = domain();
1205   if(curdom == 0) error("null_pointer", "domain");
1206   const Function* fmap = findMap(dom, *curdom);          // find map between domains
1207   //if (fmap==0) error("domain_map_undefined",dom.name(),curdom->name());
1208   //const GeomDomain* udom = u.space()->domain();
1209   //if (udom!= &dom && !udom->include(dom)) error("domain_not_subdomain",dom.name(),udom->name());
1210   //create new SuTermVector
1211   sut = new SuTermVector(u, dom, *this, fmap, errOnOut, name_ + "mapto_" + dom.name());
1212   trace_p->pop();
1213   return sut;
1214 }
1215 
1216 /*! extract unknown component term vector as a SuTermVector, create a  SuTermVector
1217     this function must be called from TermVector class in order to encapsulate SuTermVector in a TermVector
1218 */
operator ()(const ComponentOfUnknown & cu) const1219 SuTermVector SuTermVector::operator()(const ComponentOfUnknown& cu) const
1220 {
1221   if(cu.parent() != u_p)
1222     {
1223       where("SuTermVector::operator()");
1224       error("term_wrong_unknown", name_, u_p->name(), cu.parent()->name());
1225     }
1226   if(cu.componentIndex() > nbOfComponents())
1227     {
1228       where("SuTermVector::operator()");
1229       error("term_wrong_unknown_component", name_, cu.componentIndex(), nbOfComponents());
1230     }
1231   if(nbOfComponents() == 1)
1232     {
1233       where("SuTermVector::operator()");
1234       error("unknown_not_scalar");
1235     }
1236   string_t na = name() + "_" + tostring(cu.componentIndex());
1237   SuTermVector su(na, &cu, space_p, valueType(), size(), 1, false); //create a scalar SuTermVector
1238   su.entries_p->extractComponent(*entries_p, cu.componentIndex());
1239   su.computed() = true;
1240   return su;
1241 }
1242 
1243 /*! move SuTermVector unknown to an other one
1244     consist in changing the unknown u of SuTermVector by the unknown v (u and v must be defined on the same Space!)
1245     with an optionnal management of components of unknown, examples
1246       u a scalar unknown and v a scalar unknown :  SuTermVector if not modified
1247       u a scalar unknown and v a 3 vector unknown, ci ={2} the SuTermVector is changed to a 3 column vector :
1248              new sutv=[ [0...0] [sutv] [0...0] ]
1249       u a 3-vector unknown and v a 3-vector unknown, ci ={2 3 1} the SuTermVector is changed columns are permuted :
1250              new sutv=[ [sutv2] [sutv3] [sutv1] ]   v may be equal to u in that case
1251       u a 4-vector unknown and v a 2-vector unknown, ci ={2 4} the SuTermVector is changed  :
1252              new sutv=[ [sutv2] [sutv4] ]
1253       u a 4-vector unknown and v a 3-vector unknown, ci ={2 0 4} the SuTermVector is changed :
1254              new sutv=[ [sutv2] [0...0] [sutv4] ]
1255     u is replaced by v,
1256     v may be equal to u but be cautious if the result is not of the dimension of v because many operations are not supported
1257     in doubt, create a new unknown of the consistent dimension
1258 */
1259 
changeUnknown(const Unknown & v,const Vector<number_t> & ci)1260 void SuTermVector::changeUnknown(const Unknown& v, const Vector<number_t>& ci)
1261 {
1262   dimen_t du = u_p->nbOfComponents(), dv = v.nbOfComponents();
1263   if(ci.size() == 0 || (du == 1 && dv == 1))
1264     {
1265       if(u_p != &v) u_p = &v;
1266       return;
1267     }
1268   if(entries_p == 0)
1269     {
1270       where("SuTermVector::changeUnknown");
1271       error("null_pointer", "entries_p");
1272     }
1273   entries_p->moveColumns(ci);
1274 }
1275 
1276 //destructor
~SuTermVector()1277 SuTermVector::~SuTermVector()
1278 {
1279   if(entries_p != 0) delete entries_p;       //delete entries
1280   if(scalar_entries_p != entries_p && scalar_entries_p != 0) delete scalar_entries_p;     //delete scalar entries
1281 }
1282 
1283 // size of SuTermvector counted in scalar
size() const1284 number_t SuTermVector::size() const
1285 {
1286   if(entries_p != 0) return entries_p->size() * (u_p->nbOfComponents());
1287   if(scalar_entries_p != 0) return scalar_entries_p->size();
1288   return 0;
1289 }
1290 
1291 
1292 // size of Termvector counted in dofs
nbDofs() const1293 number_t SuTermVector::nbDofs() const
1294 {
1295   return space_p->nbDofs();
1296 }
1297 
1298 //return n-th dof of unknown (n>=1)
dof(number_t n) const1299 const Dof& SuTermVector::dof(number_t n) const
1300 {
1301   return space_p->dof(n);
1302 }
1303 
1304 // return geometric domain pointer attached to SuTermVector (may be 0)
domain() const1305 const GeomDomain* SuTermVector::domain() const
1306 {
1307   if(space_p == 0) return 0;  //no space -> no domain
1308   return space_p->domain();
1309 }
1310 
1311 // restriction of SuTermVector to a domain, return a pointer. May be null if dom does not intersect SuTermVector domain
onDomain(const GeomDomain & dom) const1312 SuTermVector* SuTermVector::onDomain(const GeomDomain& dom) const
1313 {
1314   SuTermVector* sutv = new SuTermVector(*this, dom);
1315   if(sutv->size() == 0)
1316     {
1317       delete sutv;
1318       return 0;
1319     }
1320   else return sutv;
1321 }
1322 
1323 //deallocate memory used by a SuTermVector
clear()1324 void SuTermVector::clear()
1325 {
1326   if(entries_p != 0) delete entries_p;
1327   if(scalar_entries_p != entries_p && scalar_entries_p != 0) delete scalar_entries_p;
1328   cdofs_.clear();
1329   entries_p = 0;
1330   scalar_entries_p = 0;
1331   computed() = false;
1332 }
1333 
1334 //! set of unknown spaces involved
unknownSpaces() const1335 std::set<const Space*> SuTermVector::unknownSpaces() const
1336 {
1337   std::set<const Space*>sps;
1338   if(u_p != 0) sps.insert(u_p->space());
1339   return sps;
1340 }
1341 
1342 // return the actual pointer to entries (priority to scalar entry), return 0 is no allocated pointer
actual_entries() const1343 VectorEntry* SuTermVector::actual_entries() const
1344 {
1345   VectorEntry* ve = scalar_entries_p;
1346   if(ve != 0) return ve;
1347   return entries_p;
1348 }
1349 
1350 //direct value managment (n>=1)
getValue(number_t n) const1351 Value SuTermVector::getValue(number_t n) const
1352 {
1353   if(entries_p == 0)
1354     {
1355       where("SuTermVector::getValue");
1356       error("null_pointer", "entries_p");
1357     }
1358   return entries_p->getValue(n);
1359 }
1360 
setValue(number_t n,const Value & val)1361 void SuTermVector::setValue(number_t n, const Value& val)
1362 {
1363   if(entries_p == 0)
1364     {
1365       where("SuTermVector::setValue");
1366       error("null_pointer", "entries_p");
1367     }
1368   entries_p->setValue(n, val);
1369 }
1370 
1371 /*! set dof values of SutermVector on a GeomDomainfrom from Value : u_i = v for all dof i on dom
1372     does not change other values
1373     dom has to be a subdomain of the domain of the currrent SuTermVector
1374     be cautious when Space is not a FE Lagrange space because does not imply that u=v on dom in the meaning of function*/
setValue(const Value & v,const GeomDomain & dom)1375 void SuTermVector::setValue(const Value& v, const GeomDomain& dom)
1376 {
1377   //check space type
1378   Space* sp = u_p->space();
1379 
1380   //check value type
1381   StrucType st=strucType();
1382   ValueType vt=valueType();
1383   if(st!=v.strucType() || (vt==_real && v.valueType()!=_real))
1384     {
1385       where("SuTermVector::setValue(Value, Domain)");
1386       error("value_wrongtype", words("structure", st), "(" + words("value", vt) + ", " + words("value", v.valueType()) + ")",
1387             words("structure", v.strucType()), "(" + words("value", _real) + ", " + words("value", _real) + ")");
1388     }
1389 
1390   std::vector<number_t> rks;
1391   bool samedom= (domain() == &dom);
1392   if(!samedom)   //not same domain, get numberings
1393     {
1394       //get dof numbers of current SuTermVector, dof numbers of domain dom
1395       std::vector<number_t> curdofids = space_p->dofIds();
1396       std::vector<number_t> domdofids;
1397       Space* subsp=Space::findSubSpace(&dom,sp);
1398       if(subsp!=0) domdofids = subsp->dofIds();           //dofs of subspace related to dom
1399       else // built dof using dofsOn function
1400         {
1401           const_cast<GeomDomain&>(dom).updateParentOfSideElements();
1402           domdofids = sp->feSpace()->dofsOn(dom);        //dofs located on dom
1403         }
1404       number_t nd=domdofids.size();
1405       if(nd==0)
1406         {
1407           where("SuTermVector::setValue(Value, Domain)");
1408           error("dof_not_found");
1409         }
1410       rks.resize(nd,0);
1411       ranks(curdofids,domdofids,rks);   // costly find, to improve
1412     }
1413 
1414   //fill value
1415   VectorEntry* ve=entries_p;
1416   if(ve==0) ve=scalar_entries_p;
1417   if(ve==0)
1418     {
1419       where("SuTermVector::setValue(Value, Domain)");
1420       error("term_no_entries");
1421     }
1422   std::vector<number_t>::iterator itn=rks.begin();
1423   switch(st)
1424     {
1425       case _scalar:
1426         if(vt==_real)
1427           {
1428             real_t r = v.asReal();
1429             Vector<real_t>::iterator it= ve->rEntries_p->begin();
1430             if(samedom)
1431               for(; it!=ve->rEntries_p->end(); ++it) *it = r;
1432             else
1433               for(; itn!=rks.end(); ++itn)
1434                 if(*itn!=0) *(it + *itn-1) = r;
1435           }
1436         else
1437           {
1438             complex_t c = 0.;
1439             if(v.valueType()==_real) c=v.asReal();
1440             else c=v.asComplex();
1441             Vector<complex_t>::iterator it= ve->cEntries_p->begin();
1442             if(samedom)
1443               for(; it!=ve->cEntries_p->end(); ++it) *it = c;
1444             else
1445               for(; itn!=rks.end(); ++itn)
1446                 if(*itn!=0) *(it + *itn-1) = c;
1447           }
1448         break;
1449       case _vector:
1450         if(vt==_real)
1451           {
1452             Vector<real_t> rs=v.asRealVector();
1453             Vector<Vector<real_t> >::iterator it= ve->rvEntries_p->begin();
1454             if(samedom)
1455               for(; it!=ve->rvEntries_p->end(); ++it) *it = rs;
1456             else
1457               for(; itn!=rks.end(); ++itn)
1458                 if(*itn!=0) *(it + *itn-1) = rs;
1459           }
1460         else
1461           {
1462             Vector<complex_t> cs;
1463             if(v.valueType()==_real) cs=v.asRealVector();
1464             else cs=v.asComplexVector();
1465             Vector<Vector<complex_t> >::iterator it= ve->cvEntries_p->begin();
1466             if(samedom)
1467               for(; it!=ve->cvEntries_p->end(); ++it) *it=cs;
1468             else
1469               for(; itn!=rks.end(); ++itn)
1470                 if(*itn!=0) *(it + *itn-1) = cs;
1471           }
1472         break;
1473       default:
1474         where("SuTermVector::setValue(Value, Domain)");
1475         error("scalar_or_vector");
1476     }
1477 }
1478 
1479 /*! set dof values of GeomDomain from Function : u_i = f(M_i) for all dof i on dom, M_i point support of dof i
1480     does not change other values
1481     restricted to FE space
1482     dom has to be a subdomain of the domain of the currrent SuTermVector
1483     be cautious when Space is not a FE Lagrange space, because does not imply that u=f on dom in the meaning of function */
setValue(const Function & f,const GeomDomain & dom)1484 void SuTermVector::setValue(const Function& f, const GeomDomain& dom)
1485 {
1486   //check space type
1487   Space* sp = u_p->space();
1488   if(sp->typeOfSpace() != _feSpace)
1489     {
1490       where("SuTermVector::setValue(Function, Domain)");
1491       error("not_fe_space_type", sp->name());
1492     }
1493   //check value type
1494   StrucType st=strucType();
1495   ValueType vt=valueType();
1496   if(st!=f.strucType() || (vt==_real && f.valueType()!=_real))
1497     {
1498       where("SuTermVector::setValue(Function, Domain)");
1499       error("value_wrongtype", words("structure", st), "(" + words("value", vt) + ", " + words("value", f.valueType()) + ")",
1500             words("structure", f.strucType()), "(" + words("value", _real) + ", " + words("value", _real) + ")");
1501     }
1502 
1503   std::vector<number_t> rks;
1504   bool samedom= (domain() == &dom);
1505   if(!samedom)   //not same domain, get numberings
1506     {
1507       //get dof numbers of current SuTermVector, dof numbers of domain dom
1508       std::vector<number_t> curdofids = space_p->dofIds();
1509       std::vector<number_t> domdofids;
1510       Space* subsp=Space::findSubSpace(&dom,sp);
1511       if(subsp!=0) domdofids = subsp->dofIds();           //dofs of subspace related to dom
1512       else // built dof using dofsOn function
1513         {
1514           const_cast<GeomDomain&>(dom).updateParentOfSideElements();
1515           domdofids = sp->feSpace()->dofsOn(dom);        //dofs located on dom
1516         }
1517       number_t nd=domdofids.size();
1518       if(nd==0)
1519         {
1520           where("SuTermVector::setValue(Function, Domain)");
1521           error("dof_not_found");
1522         }
1523       rks.resize(nd,0);
1524       ranks(curdofids,domdofids,rks);   // costly find, to improve
1525     }
1526   else rks=trivialNumbering<number_t>(1,space_p->nbDofs());
1527 
1528   //fill value
1529   VectorEntry* ve=entries_p;
1530   if(ve==0) ve=scalar_entries_p;
1531   if(ve==0)
1532     {
1533       where("SuTermVector::setValue(Function, Domain)");
1534       error("term_no_entries");
1535     }
1536   std::vector<number_t>::iterator itn=rks.begin();
1537   switch(st)
1538     {
1539       case _scalar:
1540         if(vt==_real)
1541           {
1542             Vector<real_t>::iterator it= ve->rEntries_p->begin();
1543             real_t r;
1544             for(; itn!=rks.end(); ++itn)
1545               if(*itn!=0) *(it + *itn-1) = f(sp->dof(*itn).coords(),r);
1546           }
1547         else
1548           {
1549             real_t r;
1550             complex_t c = 0.;
1551             Vector<complex_t>::iterator it= ve->cEntries_p->begin();
1552             for(; itn!=rks.end(); ++itn)
1553               if(*itn!=0)
1554                 {
1555                   if(f.valueType()==_real) *(it + *itn-1) = f(sp->dof(*itn).coords(),r);
1556                   else *(it + *itn-1) = f(sp->dof(*itn).coords(),c);
1557                 }
1558           }
1559         break;
1560       case _vector:
1561         if(vt==_real)
1562           {
1563             Vector<real_t> rs;
1564             Vector<Vector<real_t> >::iterator it= ve->rvEntries_p->begin();
1565             for(; itn!=rks.end(); ++itn)
1566               if(*itn!=0) *(it + *itn-1) = f(sp->dof(*itn).coords(),rs);
1567           }
1568         else
1569           {
1570             Vector<complex_t> cs;
1571             Vector<real_t> rs;
1572             Vector<Vector<complex_t> >::iterator it= ve->cvEntries_p->begin();
1573             for(; itn!=rks.end(); ++itn)
1574               if(*itn!=0)
1575                 {
1576                   if(f.valueType()==_real) *(it + *itn-1) = f(sp->dof(*itn).coords(),rs);
1577                   else *(it + *itn-1) = f(sp->dof(*itn).coords(),cs);
1578                 }
1579           }
1580         break;
1581       default:
1582         where("SuTermVector::setValue(Function, Domain)");
1583         error("scalar_or_vector");
1584     }
1585 }
1586 
1587 /*! set dof values of GeomDomain from SuTermVector : u_i = v_i for all dof i on dom
1588     does not change other values
1589     dom has to be a subdomain of the domain of the currrent SuTermVector
1590     be cautious when Space is not a FE Lagrange space, because does not imply that u=v on dom in the meaning of function*/
setValue(const SuTermVector & sut,const GeomDomain & dom)1591 void SuTermVector::setValue(const SuTermVector& sut, const GeomDomain& dom)
1592 {
1593   //check value type
1594   StrucType st=strucType();
1595   ValueType vt=valueType();
1596   if(st!=sut.strucType() || (vt==_real && sut.valueType()!=_real))
1597     {
1598       where("SuTermVector::setValue(SuTermVector, Domain)");
1599       error("value_wrongtype", words("structure", st), "(" + words("value", vt) + ", " + words("value", sut.valueType()) + ")",
1600             words("structure", sut.strucType()), "(" + words("value", _real) + ", " + words("value", _real) + ")");
1601     }
1602 
1603   //check space
1604   Space* sp = u_p->space();
1605   if(sut.u_p->space()!=sp)
1606     {
1607       where("SuTermVector::setValue(SuTermVector, Domain)");
1608       error("term_mismatch_spaces", sut.u_p->space()->name(), sp->name());
1609     }
1610 
1611   //build numberings
1612   std::vector<number_t> curdofids = space_p->dofIds();     //dof ids of current SuTermVector
1613   std::vector<number_t> sutdofids = sut.space_p->dofIds(); //dof ids of given SuTermVector
1614   std::vector<number_t> domdofids;                         //dof ids on domain
1615   Space* subsp=Space::findSubSpace(&dom,sp);
1616   if(subsp!=0) domdofids = subsp->dofIds();           //dofs of subspace related to dom
1617   else // built dof using dofsOn function
1618     {
1619       const_cast<GeomDomain&>(dom).updateParentOfSideElements();
1620       domdofids = sp->feSpace()->dofsOn(dom);        //dofs located on dom
1621     }
1622   std::vector<number_t> rks, rkc;
1623   ranks(sutdofids,domdofids,rks);   // ranks of domain dofs in sut dofs
1624   if(sut.domain()==&dom) rkc=trivialNumbering(number_t(1),sut.nbDofs());
1625   else ranks(curdofids,domdofids,rkc);   // ranks of domain dofs in current dofs
1626 
1627   //fill value
1628   VectorEntry* vec=entries_p;
1629   const VectorEntry* ves=sut.entries();
1630   if(vec==0) vec=scalar_entries_p;
1631   if(vec==0)
1632     {
1633       where("SuTermVector::setValue(SuTermVector, Domain)");
1634       error("term_no_entries");
1635     }
1636   if(ves==0) ves=scalar_entries_p;
1637   if(ves==0)
1638     {
1639       where("SuTermVector::setValue(SuTermVector, Domain)");
1640       error("term_no_entries");
1641     }
1642   std::vector<number_t>::iterator itns=rks.begin(), itnc=rkc.begin();
1643   switch(st)
1644     {
1645       case _scalar:
1646         if(vt==_real)
1647           {
1648             Vector<real_t>::iterator itc= vec->rEntries_p->begin();
1649             Vector<real_t>::const_iterator its= ves->rEntries_p->begin();
1650             for(; itns!=rks.end(); ++itns, ++itnc)
1651               if(*itns!=0 && *itnc!=0) *(itc + *itnc-1) = *(its+*itns-1);
1652           }
1653         else
1654           {
1655             Vector<complex_t>::iterator itc= vec->cEntries_p->begin();
1656             if(sut.valueType()==_real)
1657               {
1658                 Vector<real_t>::const_iterator its= ves->rEntries_p->begin();
1659                 for(; itns!=rks.end(); ++itns, ++itnc)
1660                   if(*itns!=0 && *itnc!=0) *(itc + *itnc-1) = *(its+*itns-1);
1661               }
1662             else
1663               {
1664                 Vector<complex_t>::const_iterator its= ves->cEntries_p->begin();
1665                 for(; itns!=rks.end(); ++itns, ++itnc)
1666                   if(*itns!=0 && *itnc!=0) *(itc + *itnc-1) = *(its+*itns-1);
1667               }
1668           }
1669         break;
1670       case _vector:
1671         if(vt==_real)
1672           {
1673             Vector<Vector<real_t> >::iterator itc= vec->rvEntries_p->begin();
1674             Vector<Vector<real_t> >::const_iterator its= ves->rvEntries_p->begin();
1675             for(; itns!=rks.end(); ++itns, ++itnc)
1676               if(*itns!=0 && *itnc!=0) *(itc + *itnc-1) = *(its+*itns-1);
1677           }
1678         else
1679           {
1680             Vector<Vector<complex_t> >::iterator itc= vec->cvEntries_p->begin();
1681             if(sut.valueType()==_real)
1682               {
1683                 Vector<Vector<real_t> >::const_iterator its= ves->rvEntries_p->begin();
1684                 for(; itns!=rks.end(); ++itns, ++itnc)
1685                   if(*itns!=0 && *itnc!=0) *(itc + *itnc-1) = *(its+*itns-1);
1686               }
1687             else
1688               {
1689                 Vector<Vector<complex_t> >::const_iterator its= ves->cvEntries_p->begin();
1690                 for(; itns!=rks.end(); ++itns, ++itnc)
1691                   if(*itns!=0 && *itnc!=0) *(itc + *itnc-1) = *(its+*itns-1);
1692               }
1693           }
1694         break;
1695       default:
1696         where("SuTermVector::setValue(SuTermVector, Domain)");
1697         error("scalar_or_vector");
1698     }
1699 }
1700 
1701 /*! set dof values of SutermVector from a given SuTermVector : u_i = v_i for all dof i of the given SutermVector
1702     does not change other values */
setValue(const SuTermVector & sut)1703 void SuTermVector::setValue(const SuTermVector& sut)
1704 {
1705   //check value type
1706   StrucType st=strucType();
1707   ValueType vt=valueType();
1708   if(st!=sut.strucType() || (vt==_real && sut.valueType()!=_real))
1709     {
1710       where("SuTermVector::setValue(SuTermVector)");
1711       error("value_wrongtype", words("structure", st), "(" + words("value", vt) + ", " + words("value", sut.valueType()) + ")",
1712             words("structure", sut.strucType()), "(" + words("value", _real) + ", " + words("value", _real) + ")");
1713     }
1714 
1715   //check space
1716   Space* sp = u_p->space();
1717   if(sut.u_p->space()!=sp)
1718     {
1719       where("SuTermVector::setValue(SuTermVector)");
1720       error("term_mismatch_spaces", sut.u_p->space()->name(), sp->name());
1721     }
1722 
1723   //build numberings
1724   std::vector<number_t> rks;
1725   if(sp==space_p) rks = sut.space_p->dofIds();  //dof ids of given SuTermVector
1726   else
1727     {
1728       std::vector<number_t> curdofids = space_p->dofIds();     //dof ids of current SuTermVector
1729       std::vector<number_t> sutdofids = sut.space_p->dofIds(); //dof ids of given SuTermVector
1730       ranks(curdofids,sutdofids,rks);   // ranks of sut dofs in current dofs
1731     }
1732 
1733   //fill value
1734   VectorEntry* vec=entries_p;
1735   const VectorEntry* ves=sut.entries();
1736   if(vec==0) vec=scalar_entries_p;
1737   if(vec==0)
1738     {
1739       where("SuTermVector::setValue(SuTermVector)");
1740       error("term_no_entries");
1741     }
1742   if(ves==0) ves=scalar_entries_p;
1743   if(ves==0)
1744     {
1745       where("SuTermVector::setValue(SuTermVector)");
1746       error("term_no_entries");
1747     }
1748   std::vector<number_t>::iterator itn=rks.begin();
1749   switch(st)
1750     {
1751       case _scalar:
1752         if(vt==_real)
1753           {
1754             Vector<real_t>::iterator itc= vec->rEntries_p->begin();
1755             Vector<real_t>::const_iterator its= ves->rEntries_p->begin();
1756             for(; itn!=rks.end(); ++itn, ++its)
1757               if(*itn!=0) *(itc + *itn-1) = *its;
1758           }
1759         else
1760           {
1761             Vector<complex_t>::iterator itc= vec->cEntries_p->begin();
1762             if(sut.valueType()==_real)
1763               {
1764                 Vector<real_t>::const_iterator its= ves->rEntries_p->begin();
1765                 for(; itn!=rks.end(); ++itn, ++its)
1766                   if(*itn!=0) *(itc + *itn-1) = *its;
1767               }
1768             else
1769               {
1770                 Vector<complex_t>::const_iterator its= ves->cEntries_p->begin();
1771                 for(; itn!=rks.end(); ++itn, ++its)
1772                   if(*itn!=0) *(itc + *itn-1) = *its;
1773               }
1774           }
1775         break;
1776       case _vector:
1777         if(vt==_real)
1778           {
1779             Vector<Vector<real_t> >::iterator itc= vec->rvEntries_p->begin();
1780             Vector<Vector<real_t> >::const_iterator its= ves->rvEntries_p->begin();
1781             for(; itn!=rks.end(); ++itn, ++its)
1782               if(*itn!=0) *(itc + *itn-1) = *its;
1783           }
1784         else
1785           {
1786             Vector<Vector<complex_t> >::iterator itc= vec->cvEntries_p->begin();
1787             if(sut.valueType()==_real)
1788               {
1789                 Vector<Vector<real_t> >::const_iterator its= ves->rvEntries_p->begin();
1790                 for(; itn!=rks.end(); ++itn, ++its)
1791                   if(*itn!=0) *(itc + *itn-1) = *its;
1792               }
1793             else
1794               {
1795                 Vector<Vector<complex_t> >::const_iterator its= ves->cvEntries_p->begin();
1796                 for(; itn!=rks.end(); ++itn, ++its)
1797                   if(*itn!=0) *(itc + *itn-1) = *its;
1798               }
1799           }
1800         break;
1801       default:
1802         where("SuTermVector::setValue(SuTermVector)");
1803         error("scalar_or_vector");
1804     }
1805 }
1806 
1807 
1808 // evaluate interpolated value at a point, use expansive interpolation method
evaluate(const Point & p) const1809 Value SuTermVector::evaluate(const Point& p) const
1810 {
1811   if(entries_p == 0)
1812     {
1813       where("SuTermVector::evaluate");
1814       error("null_pointer", "entries_p");
1815     }
1816   const FeSpace* fsp = space_p->feSpace();
1817   const FeSubSpace* ssp = space_p->feSubSpace();
1818   if(fsp == 0 && ssp == 0)
1819     {
1820       where("SuTermVector::evaluate");
1821       error("not_fe_space_type", space_p->name());
1822     }
1823   dimen_t dimf, dimu;
1824   if(fsp != 0) dimf = fsp->dimFun();
1825   else dimf = ssp->dimFun();
1826   if(dimf >1) dimf += space_p->dimPoint()-space_p->dimDomain();  //modify dimension because of mapping mD->nD
1827   dimu = u_p->nbOfComponents();
1828   dimen_t d = dimf * dimu;
1829 
1830   if(entries_p->rEntries_p != 0)  //real scalar input
1831     {
1832       if(d == 1)  //real scalar output
1833         {
1834           real_t r;
1835           if(fsp != 0) fsp->interpolate(*entries_p->rEntries_p, p, r, _id);
1836           else ssp->interpolate(*entries_p->rEntries_p, p, r, _id);
1837           return Value(r);
1838         }
1839       else  //real vector output
1840         {
1841           Vector<real_t> r(d);
1842           if(fsp != 0) fsp->interpolate(*entries_p->rEntries_p, p, r, _id);
1843           else ssp->interpolate(*entries_p->rEntries_p, p, r, _id);
1844           return Value(r);
1845         }
1846     }
1847 
1848   if(entries_p->cEntries_p != 0)  //complex scalar input
1849     {
1850       if(d == 1)  //complex scalar output
1851         {
1852           complex_t r;
1853           if(fsp != 0) fsp->interpolate(*entries_p->cEntries_p, p, r, _id);
1854           else ssp->interpolate(*entries_p->cEntries_p, p, r, _id);
1855           return Value(r);
1856         }
1857       else //complex vector output
1858         {
1859           Vector<complex_t> r(d);
1860           if(fsp != 0) fsp->interpolate(*entries_p->cEntries_p, p, r, _id);
1861           else ssp->interpolate(*entries_p->cEntries_p, p, r, _id);
1862           return Value(r);
1863         }
1864     }
1865 
1866   if(entries_p->rvEntries_p != 0)  //real vector input
1867     {
1868       if(d == 1)  //real scalar output
1869         {
1870           Vector<real_t> r(1);
1871           if(fsp != 0) fsp->interpolate(*entries_p->rvEntries_p, p, r, _id);
1872           else ssp->interpolate(*entries_p->rvEntries_p, p, r, _id);
1873           return Value(r[0]);
1874         }
1875       else //real vector output
1876         {
1877           Vector<real_t> r(d);
1878           if(fsp != 0) fsp->interpolate(*entries_p->rvEntries_p, p, r, _id);
1879           else ssp->interpolate(*entries_p->rvEntries_p, p, r, _id);
1880           return Value(Vector<real_t>(r));
1881         }
1882     }
1883 
1884   if(entries_p->cvEntries_p != 0)  //complex vector input
1885     {
1886       if(d == 1)  //complex scalar output
1887         {
1888           Vector<complex_t> r(1);
1889           if(fsp != 0) fsp->interpolate(*entries_p->cvEntries_p, p, r, _id);
1890           else ssp->interpolate(*entries_p->cvEntries_p, p, r, _id);
1891           return Value(r[0]);
1892         }
1893       else //complex vector output
1894         {
1895           Vector<complex_t> r(d);
1896           if(fsp != 0) fsp->interpolate(*entries_p->cvEntries_p, p, r, _id);
1897           else ssp->interpolate(*entries_p->cvEntries_p, p, r, _id);
1898           return Value(Vector<complex_t>(r));
1899         }
1900     }
1901 
1902   where("SuTermVector::evaluate");
1903   error("term_no_entries");
1904   return Value(0.);
1905 }
1906 
1907 
1908 /*!build the required subspaces and the largest subspace (possibly the whole space)
1909   this function :
1910    - travel along basic linear forms of the linear combination
1911    - identify the largest geometric domain
1912    - build the largest subspace (for SuTermVector dofs numbering)
1913    - create subspace related to each basic linear form if it does not exist
1914    - create dofs numbering between domain subspaces ands largest subspace
1915 
1916  dofs numbering :
1917     whole space     largest subspace    domain subspace
1918             1               5                2
1919             2               3                1
1920             3               1
1921             4
1922             5
1923 */
buildSubspaces()1924 void SuTermVector::buildSubspaces()
1925 {
1926   //for safety
1927   if(sulf_p == 0) return ;               //no linear form, nothing to do
1928   trace_p->push("SuTermVector::buildSubspaces");
1929 
1930   //case of not a FeSpace
1931   Space* spu = sulf_p->unknown()->space(); //space of the unknown
1932   number_t nblf = sulf_p->size();            //number of basic linear forms in linear form
1933   std::vector<const GeomDomain*> doms(nblf, 0);
1934   space_p = spu;
1935   if(spu->typeOfSpace() != _feSpace)
1936     {
1937       spu->buildSubspaces(doms, subspaces); //build subspaces
1938       trace_p->pop();
1939       return;
1940     }
1941 
1942   //only for FeSpace, make list of domains of each basic linear form
1943   number_t n = 0;
1944   for(it_vlfp it = sulf_p->begin(); it != sulf_p->end(); it++, n++)  //travel the linear combination of forms
1945     {
1946       BasicLinearForm* blc = it->first;
1947       switch(blc->type())
1948         {
1949           case _intg :
1950             {
1951               if(blc->asIntgForm()->computationType()==_FEextComputation && blc->asIntgForm()->opu()->extensionRequired())
1952                 doms[n] = &blc->asIntgForm()->domain()->meshDomain()->extendDomain();  //find or create extension of domain dom
1953               else doms[n] = blc->asIntgForm()->domain();
1954               break;
1955             }
1956           //case _bilinearAsLinear :
1957           //doms[n] = blc->asBilinearAsLinearForm()->domain(); //get the domain of linear form
1958           // break;
1959           case _doubleIntg :                                   //to do later
1960           default          :
1961             error("lform_not_handled", words("form type", blc->type()));      //unknown basic linear form
1962         }
1963     }
1964 
1965   space_p = spu->buildSubspaces(doms, subspaces); //build subspaces
1966 
1967   trace_p->pop();
1968 }
1969 
1970 /*! if vector unknown, create vector representation from scalar representation (have to exist)
1971     if scalar unknown, set entries_p = scalar_entries_p
1972     keepScalar : if false (default value), scalar entries are deleted
1973 */
toVector(bool keepScalar)1974 void SuTermVector::toVector(bool keepScalar)
1975 {
1976   if(scalar_entries_p == 0) return;  // no scalar representation, nothing done
1977   trace_p->push("SuTermVector::toVector()");
1978   if(entries_p != 0 && scalar_entries_p != entries_p) delete entries_p;  // delete old entries
1979   dimen_t nbc = u_p->nbOfComponents();
1980   if(nbc <= 1)  //not a vector unknown
1981     {
1982       entries_p = scalar_entries_p;
1983       trace_p->pop();
1984       return;
1985     }
1986   //reallocate entries
1987   ValueType vt = scalar_entries_p->valueType_;
1988   std::vector<number_t> dofs = space_p->dofIds();
1989   entries_p = new VectorEntry(vt, nbc, dofs.size());
1990   std::map<number_t, number_t> dofindex;
1991   std::vector<number_t>::iterator itd = dofs.begin();
1992   number_t n = 1;
1993   for(; itd != dofs.end(); itd++, n++) dofindex[*itd] = n;
1994   std::vector<DofComponent>::iterator itcd = cdofs_.begin();
1995   std::map<number_t, number_t>::iterator itm;
1996   if(vt == _real)  //real case
1997     {
1998       Vector<real_t>& sval = *scalar_entries_p->rEntries_p;
1999       Vector<Vector<real_t> >& val = *entries_p->rvEntries_p;
2000       Vector<real_t>::iterator itv = sval.begin();
2001       for(; itcd != cdofs_.end(); itcd++, itv++)
2002         {
2003           itm = dofindex.find(itcd->dofnum);
2004           if(itm == dofindex.end())
2005             error("dof_not_found");
2006           val(itm->second)(itcd->numc) = *itv;
2007         }
2008     }
2009   else //complex case
2010     {
2011       Vector<complex_t>& sval = *scalar_entries_p->cEntries_p;
2012       Vector<Vector<complex_t> >& val = *entries_p->cvEntries_p;
2013       Vector<complex_t>::iterator itv = sval.begin();
2014       for(; itcd != cdofs_.end(); itcd++, itv++)
2015         {
2016           itm = dofindex.find(itcd->dofnum);
2017           if(itm == dofindex.end())
2018             error("dof_not_found");
2019           val(itm->second)(itcd->numc) = *itv;
2020         }
2021     }
2022   if(!keepScalar)
2023     {
2024       delete scalar_entries_p;
2025       scalar_entries_p = 0;
2026     }
2027   trace_p->pop();
2028 }
2029 
2030 /*! create scalar representation scalar_entries_p and cdofs_ numbering vectors
2031     - if unknown is a vector unknown a new VectorEntry is created using  VectorEntry::toScalar() function
2032       and linked to the  VectorEntry pointer scalar_entries_p. In that case, if keepVector is false the vector representation is destroyed
2033     - if unknowns is a scalar unknown, no new VectorEntry : scalar_entries_p = entries_p
2034     This function builds in any case, the cdofs_ numbering vector (vector of ComponentDof's)
2035 */
toScalar(bool keepVector)2036 void SuTermVector::toScalar(bool keepVector)
2037 {
2038   if(scalar_entries_p != 0) return;  //already in scalar form
2039 
2040   trace_p->push("SuTermVector::toScalar");
2041   //create or update scalar_entries_p
2042   dimen_t nbc = u_p->nbOfComponents();
2043   if(nbc == 1)  scalar_entries_p = entries_p;                       //no creation, pointer copy
2044   else if(entries_p != 0) scalar_entries_p = entries_p->toScalar();  //create new scalar entries from vector entries
2045 
2046   //create cdofs_u
2047   std::vector<number_t> dofs = space_p->dofIds();
2048   cdofs_.resize(dofs.size()*nbc);
2049   std::vector<number_t>::iterator itd = dofs.begin();
2050   std::vector<DofComponent>::iterator itdc = cdofs_.begin();
2051   for(; itd != dofs.end(); itd++)
2052     for(dimen_t d = 0; d < nbc; d++, itdc++) *itdc = DofComponent(u_p, *itd, d + 1);
2053 
2054   if(!keepVector && entries_p != scalar_entries_p)
2055     {
2056       delete entries_p;
2057       entries_p = 0;
2058     }
2059   trace_p->pop();
2060 }
2061 
2062 /*! when current SutermVector has a component unknown, return vector unknown representation
2063     if is not a component unknown SuTermVector, a copy of current SuTermVector is returned
2064 */
toVectorUnknown() const2065 SuTermVector SuTermVector::toVectorUnknown() const
2066 {
2067   trace_p->push("SuTermVector::toVectorUnknown");
2068   SuTermVector res(*this);
2069   if(!u_p->isComponent() || entries_p == 0)
2070     {
2071       trace_p->pop();
2072       return res;
2073     }
2074   res.entries_p->toVector(u_p->parent()->nbOfComponents(), u_p->componentIndex());
2075   res.u_p = u_p->parent();
2076   trace_p->pop();
2077   return res;
2078 }
2079 
2080 // save SuTermVector to file
saveToFile(const string_t & fn,bool encode) const2081 void SuTermVector::saveToFile(const string_t& fn, bool encode) const
2082 {
2083   if(entries_p != 0) entries_p->saveToFile(fn, encode);
2084   if(scalar_entries_p != 0) scalar_entries_p->saveToFile(fn, encode);
2085 }
2086 
2087 //return value type (_real,_complex)
valueType() const2088 ValueType SuTermVector::valueType() const
2089 {
2090   if(entries_p != 0) return entries_p->valueType_;
2091   if(scalar_entries_p != 0) return scalar_entries_p->valueType_;
2092   if(sulf_p != 0) return sulf_p->valueType();
2093   return _none;
2094 }
2095 //return structure type (_scalar,_vector)
strucType() const2096 StrucType SuTermVector::strucType() const
2097 {
2098   if(entries_p != 0) return entries_p->strucType_;
2099   if(scalar_entries_p != 0) return scalar_entries_p->strucType_;
2100   if(sulf_p != 0) return sulf_p->strucType();
2101   return _scalar;
2102 }
2103 
2104 /* ----------------------------------------------------------------------------------------
2105   compute abs, real and imaginary part of SuTermVector
2106   note : current SuTermVector is modified
2107   ----------------------------------------------------------------------------------------*/
toAbs()2108 SuTermVector& SuTermVector::toAbs()
2109 {
2110   if(entries_p != 0) entries_p->toAbs();
2111   if(scalar_entries_p != 0) scalar_entries_p->toAbs();
2112   return *this;
2113 }
2114 
toReal()2115 SuTermVector& SuTermVector::toReal()
2116 {
2117   if(entries_p != 0) entries_p->toReal();
2118   if(scalar_entries_p != 0) scalar_entries_p->toReal();
2119   return *this;
2120 }
2121 
toImag()2122 SuTermVector& SuTermVector::toImag()
2123 {
2124   if(entries_p != 0) entries_p->toImag();
2125   if(scalar_entries_p != 0) scalar_entries_p->toImag();
2126   return *this;
2127 }
2128 
toComplex()2129 SuTermVector& SuTermVector::toComplex()
2130 {
2131   if(entries_p != 0) entries_p->toComplex();
2132   if(scalar_entries_p != 0) scalar_entries_p->toComplex();
2133   return *this;
2134 }
2135 
2136 // take the conjugate of entries, if no entries nothing is done
2137 // when conjugate is taken, the linear form is not updated to take it into account !
toConj()2138 SuTermVector& SuTermVector::toConj()
2139 {
2140   if(valueType()==_real) return *this;  //nothing to do
2141   if(entries_p != 0) entries_p->toConj();
2142   if(scalar_entries_p != 0) scalar_entries_p->toConj();
2143   return *this;
2144 
2145 }
2146 // round to zero all coefficients close to 0 (|.| < aszero)
roundToZero(real_t aszero)2147 SuTermVector& SuTermVector::roundToZero(real_t aszero)
2148 {
2149   if(entries_p != 0) entries_p->roundToZero(aszero);
2150   if(scalar_entries_p != 0) scalar_entries_p->roundToZero(aszero);
2151   return *this;
2152 
2153 }
2154 
2155 /* ----------------------------------------------------------------------------------------
2156   compute SuTermVector
2157   remember that it deal with a single unknown
2158   this routine first analyse the linear form to be computed,
2159   it collects computations by domain and type of computation
2160 
2161   !!! For the moment, only FE computation is handled (not the BEM and spectral methods)
2162   ----------------------------------------------------------------------------------------*/
compute()2163 void SuTermVector::compute()
2164 {
2165   if(sulf_p == 0) return;     //no linear form to compute
2166   if(sulf_p->size() == 0) return;    //void SuTermVector !!!
2167   trace_p->push("SuTermVector::compute");
2168   //retry unknown
2169   const Unknown* up = sulf_p->unknown();
2170 
2171   //analyse the combination of linear forms to be computed and split them by domain (and by type of computation)
2172   std::map<const GeomDomain*, std::vector<lfPair> > intgByDomain;  //list of linear form by domain
2173   std::map<const GeomDomain*, std::vector<lfPair> >::iterator itm;
2174   std::list<lfPair>  bilinearAslinear;  //list of bilinear_as_linear forms
2175   std::list<lfPair>::iterator itl;
2176   ValueType vt = _real;
2177   StrucType st = sulf_p->begin()->first->strucType();
2178   dimPair dims = dimPair(0,0);
2179   for(it_vlfp it = sulf_p->begin(); it != sulf_p->end(); it++)
2180     {
2181       switch(it->first->type())
2182         {
2183           case _intg :  //integral type
2184             {
2185               IntgLinearForm* ifl = it->first->asIntgForm(); //downcast
2186               const GeomDomain* dom = ifl->domain();
2187               itm = intgByDomain.find(dom);
2188               if(itm == intgByDomain.end())
2189                 intgByDomain[dom] = std::vector<lfPair>(1, lfPair(*it));
2190               else
2191                 intgByDomain[dom].push_back(lfPair(*it));
2192               //value and structure types
2193               if(it->first->valueType() == _complex || it->second.imag() != 0) vt = _complex;
2194               if(dims.first==0) dims=ifl->opu()->dimsRes();
2195               else if(dims!=ifl->opu()->dimsRes())
2196                 error("operator_mismatch_size", dims.first, ifl->opu()->dimsRes().first);
2197               if(it->first->strucType() != st)
2198                 error("term_mismatch_structures", words("structure", it->first->strucType()), words("structure", st));
2199               break;
2200             }
2201           case _bilinearAsLinear :
2202             {
2203               bilinearAslinear.push_back(lfPair(*it));
2204               if(it->first->valueType() == _complex) vt = _complex;
2205               if(it->first->strucType() != st)
2206                 error("term_mismatch_structures", words("structure", it->first->strucType()), words("structure", st));
2207               break;
2208             }
2209           default :
2210             error("lform_not_handled", words("form type", it->first->type()));
2211 
2212         }
2213     }
2214   std::vector<SuLinearForm> sulfs;   //list of SuLinearForm, each of them is defined on a unique domain
2215   for(itm = intgByDomain.begin(); itm != intgByDomain.end(); itm++)
2216     {
2217       sulfs.push_back(SuLinearForm(itm->second));
2218     }
2219   intgByDomain.clear();
2220 
2221   //create entries
2222   if(dims.second>1) error("scalar_or_vector");
2223   if(up->nbOfComponents()>1 && dims.first>1)
2224     error("term_inconsistent_nb_components");
2225   dimen_t du = std::max(up->nbOfComponents(),dims.first);
2226   if(du == 1)
2227     {
2228       st=_scalar;
2229       entries_p = new VectorEntry(sulf_p->valueType(), _scalar, space_p->dimSpace());
2230     }
2231   else
2232     {
2233       st=_vector;
2234       entries_p = new VectorEntry(sulf_p->valueType(), _vector, space_p->nbDofs(), du);
2235     }
2236 
2237   //computation of SuLinearForms from intg
2238   std::vector<SuLinearForm>::iterator itsulf;
2239   UnknownType ut = up->type();
2240   //st = up->strucType();
2241   real_t r = 0;
2242   complex_t c = 0.;
2243   for(itsulf = sulfs.begin(); itsulf != sulfs.end(); itsulf++)
2244     {
2245       switch(ut)
2246         {
2247           case _feUnknown :
2248             switch(st)
2249               {
2250                 case _scalar :
2251                   if(vt == _real) computeFE(*itsulf, *(entries_p->rEntries_p), r);
2252                   else computeFE(*itsulf, *(entries_p->cEntries_p), c);
2253                   break;
2254                 case _vector :
2255                   if(vt == _real) computeFE(*itsulf, *(entries_p->rvEntries_p), r);
2256                   else computeFE(*itsulf, *(entries_p->cvEntries_p), c);
2257                   break;
2258                 default :
2259                   error("scalar_or_vector");
2260               }
2261             break;
2262           case _spUnknown :
2263           default :
2264             error("unknown_not_handled", words("unknown", ut));
2265         }
2266     }
2267 
2268   // //computation of SuLinearForms from bilinear_as_linear form
2269   // for (itl=bilinearAslinear.begin(); itl!=bilinearAslinear.end(); ++itl)
2270   //   switch(st)
2271   //     {
2272   //       case _scalar :
2273   //         if (vt == _real) computeBilAsLin(*itl, *(entries_p->rEntries_p), r);
2274   //         else computeBilAsLin(*itl, *(entries_p->cEntries_p), c);
2275   //         break;
2276   //       case _vector :
2277   //         if (vt == _real) computeBilAsLin(*itl, *(entries_p->rvEntries_p), r);
2278   //         else computeBilAsLin(*itl, *(entries_p->cvEntries_p), c);
2279   //         break;
2280   //       default :
2281   //         error("scalar_or_vector");
2282   //     }
2283 
2284   computed() = true;
2285   trace_p->pop();
2286 }
2287 
2288 /*! extend current vector to numbering of vector v (useful for algebraic computation on SuTermVector)
2289     update entries and not scalar entries if allocated
2290 */
extendTo(const SuTermVector & v)2291 void SuTermVector::extendTo(const SuTermVector& v)
2292 {
2293   if(&v == this) return;             //same vector nothing to extend
2294   if(space_p == v.space_p) return;   //same space nothing to extend
2295   if(u_p != v.u_p && u_p != v.u_p->dual_p())
2296     {
2297       where("SuTermVector::extendTo");
2298       error("term_inconsistent_unknowns");
2299     }
2300   if(entries_p == 0) return;  //entries not allocated, do nothing
2301 
2302   //extension may be required
2303   std::vector<number_t> dofrenumber = renumber(v.space_p, space_p);
2304   if(dofrenumber.size() == 0) return;  //a trivial renumbering
2305   entries_p->extendEntries(dofrenumber, v.space_p->dimSpace());
2306   space_p = v.space_p;   //update SuTermVector space
2307 }
2308 
2309 /*! extend current vector to numbering of space sp
2310    update entries and not scalar entries
2311 */
extendTo(const Space & sp)2312 void SuTermVector::extendTo(const Space& sp)
2313 {
2314   if(space_p == &sp) return;   //same space nothing to extend
2315   if(space_p->rootSpace() != sp.rootSpace())
2316     error("term_mismatch_spaces", space_p->rootSpace()->name(), sp.rootSpace()->name());
2317   if(entries_p == 0) return;  //entries not allocated, do nothing
2318 
2319   std::vector<number_t> dofrenumber = renumber(&sp, space_p);
2320   if(dofrenumber.size() == 0) return;  //trivial renumbering
2321   entries_p->extendEntries(dofrenumber, sp.dimSpace());
2322   space_p = const_cast<Space*>(&sp);    //update SuTermVector space
2323 }
2324 
2325 /*! extend current vector to numbering given by DofComponent vector ndofs
2326     if useDual is true, use dual components dof (default = false)
2327     update scalar entries and not vector entries
2328     if scalar_entries = 0  move to scalar representation
2329     Note : differs from previous extendTo functions by the fact it works with component dof numbering instead of dof numbering
2330 */
extendScalarTo(const std::vector<DofComponent> & ndofs,bool useDual)2331 void SuTermVector::extendScalarTo(const std::vector<DofComponent>& ndofs, bool useDual)
2332 {
2333   VectorEntry* b = scalar_entries();
2334   if(b == 0)
2335     {
2336       toScalar();
2337       b = scalar_entries();
2338     }
2339   std::vector<number_t> renum;
2340   if(!useDual) renum = renumber(ndofs, cdofs());
2341   else         renum = renumber(ndofs, dualDofComponents(cdofs()));
2342   if(renum.size() != 0)
2343     {
2344       b->extendEntries(renum, ndofs.size());      //extend vector to matrix column numbering
2345       cdofs() = ndofs;       //update cdofs
2346     }
2347 }
2348 
2349 /*! adjust scalar entries to cdofs numbering given
2350     same as extendScalarTo but different method, see general adjustScalarEntries function
2351 */
adjustScalarEntries(const std::vector<DofComponent> & ncdofs)2352 void SuTermVector::adjustScalarEntries(const std::vector<DofComponent>& ncdofs)
2353 {
2354   adjustScalarEntriesG(scalar_entries_p, cdofs_, ncdofs);
2355 }
2356 
2357 //algebraic operations on SuTermVectors
operator +=(const SuTermVector & v)2358 SuTermVector& SuTermVector::operator+=(const SuTermVector& v)           // operation U+=V
2359 {
2360   if(u_p != v.u_p && u_p != v.u_p->dual_p())
2361     {
2362       where("SutermVector::operator+=");
2363       error("term_inconsistent_unknowns"); //different unknowns, error
2364     }
2365   if(v.entries_p == 0 && v.scalar_entries_p == 0) return *this;    //v has no entries, add 0 !
2366 
2367   // first, we have to check if both vectors have the same entries structure
2368   // if no, we have to set v to the same structure, through a copy
2369   bool copyNeeded=false;
2370   bool vToScalar=false;
2371   bool vToVector=false;
2372   if(scalar_entries_p != 0 && scalar_entries_p != entries_p && v.scalar_entries_p == 0)
2373     {
2374       copyNeeded=vToScalar=true;
2375     }
2376   else if(scalar_entries_p == 0 && v.scalar_entries_p != 0 && v.scalar_entries_p != v.entries_p)
2377     {
2378       copyNeeded=vToVector=true;
2379     }
2380 
2381   if(copyNeeded)
2382     {
2383       SuTermVector vcopy(v);
2384       if(vToScalar)
2385         {
2386           vcopy.toScalar();
2387         }
2388       if(vToVector)
2389         {
2390           vcopy.toVector();
2391         }
2392 
2393       Space* spu = space_p, *spv = v.space_p;
2394       if(spu == spv)  // same numbering => go to entries operation
2395         {
2396           if(vToVector)
2397             {
2398               if(entries_p == 0) entries_p = new VectorEntry(vcopy.valueType(), vcopy.strucType(), vcopy.nbDofs(), vcopy.nbOfComponents());
2399               *entries_p += *vcopy.entries_p;
2400             }
2401           if(vToScalar)
2402             {
2403               if(scalar_entries_p == 0) scalar_entries_p = new VectorEntry(vcopy.valueType(), vcopy.strucType(), vcopy.nbDofs()*vcopy.nbOfComponents(), 1);
2404               *scalar_entries_p += *vcopy.scalar_entries_p;
2405             }
2406         }
2407       else // not the same numbering => dynamic renumbering
2408         {
2409           Space* spuv = mergeSubspaces(spu,spv); // create union of subspaces, may be spu or spv or anything else
2410           space_p=spuv;                          // update subspace member
2411 
2412           if(spu != spuv)  // extend current entry if required
2413             {
2414               if(vToVector)
2415                 {
2416                   if(entries_p != 0 && vcopy.entries_p != 0)
2417                     {
2418                       std::vector<number_t> dofrenumber = renumber(spuv, spu);
2419                       if(dofrenumber.size() != 0) entries_p->extendEntries(dofrenumber, spuv->dimSpace());
2420                     }
2421                   VectorEntry* ve = vcopy.entries_p;
2422 
2423                   if(spv != spuv)
2424                     {
2425                       if(entries_p != 0 && vcopy.entries_p != 0)
2426                         {
2427                           ve = new VectorEntry(*vcopy.entries_p); // copy of v entries
2428                           std::vector<number_t> dofrenumber = renumber(spuv, spv);
2429                           if(dofrenumber.size() != 0) ve->extendEntries(dofrenumber, spuv->dimSpace());  // do algebraic operation on entries
2430                         }
2431                     }
2432                   if(entries_p != 0 && vcopy.entries_p != 0)
2433                     {
2434                       *entries_p += *ve;  // do algebraic operation on entries
2435                     }
2436                 }
2437               if(vToScalar)
2438                 {
2439                   if(scalar_entries_p != 0 && scalar_entries_p != entries_p)
2440                     {
2441                       std::vector<number_t> dofrenumber;
2442                       if(u_p == vcopy.u_p) dofrenumber=renumber(cdofs(), vcopy.cdofs());
2443                       else                  dofrenumber=renumber(cdofs(), dualDofComponents(vcopy.cdofs()));
2444                       if(dofrenumber.size() != 0) scalar_entries_p->extendEntries(dofrenumber, cdofs().size());
2445                     }
2446                   VectorEntry* vse = vcopy.scalar_entries_p;
2447 
2448                   if(spv != spuv)
2449                     {
2450                       if(scalar_entries_p != 0 && scalar_entries_p != entries_p)
2451                         {
2452                           vse=new VectorEntry(*vcopy.scalar_entries_p);
2453                           std::vector<number_t> dofrenumber;
2454                           if(u_p == vcopy.u_p) dofrenumber=renumber(vcopy.cdofs(), cdofs());
2455                           else                  dofrenumber=renumber(vcopy.cdofs(), dualDofComponents(cdofs()));
2456                           if(dofrenumber.size() != 0) vse->extendEntries(dofrenumber, vcopy.cdofs().size());
2457                         }
2458                     }
2459                   if(scalar_entries_p != 0 && scalar_entries_p != entries_p)
2460                     {
2461                       *scalar_entries_p += *vse;  // do algebraic operation on entries
2462                     }
2463                 }
2464             }
2465         }
2466     }
2467   else
2468     {
2469       Space* spu = space_p, *spv = v.space_p;
2470       if(spu == spv)  // same numbering => go to entries operation
2471         {
2472           if(v.scalar_entries_p != 0 && v.scalar_entries_p != v.entries_p)
2473             {
2474               if(scalar_entries_p == 0) scalar_entries_p = new VectorEntry(v.valueType(), v.strucType(), v.nbDofs()*v.nbOfComponents(), 1);
2475               if(scalar_entries_p != entries_p) *scalar_entries_p += *v.scalar_entries_p;
2476             }
2477           if(v.entries_p != 0)
2478             {
2479               if(entries_p == 0) entries_p = new VectorEntry(v.valueType(), v.strucType(), v.nbDofs(), v.nbOfComponents());
2480               *entries_p += *v.entries_p;
2481             }
2482         }
2483       else // not the same numbering => dynamic renumbering
2484         {
2485           Space* spuv = mergeSubspaces(spu, spv); // create union of subspaces, may be spu or spv or anything else
2486           space_p = spuv;                         // update subspace member
2487 
2488           if(spu != spuv)  //extend current entry if required
2489             {
2490               if(v.scalar_entries_p != 0 && v.scalar_entries_p != v.entries_p)
2491                 {
2492                   std::vector<number_t> dofrenumber;
2493                   if(u_p == v.u_p) dofrenumber=renumber(cdofs(), v.cdofs());
2494                   else              dofrenumber=renumber(cdofs(), dualDofComponents(v.cdofs()));
2495                   if(dofrenumber.size() != 0) scalar_entries_p->extendEntries(dofrenumber, cdofs().size());
2496                 }
2497               if(v.entries_p != 0)
2498                 {
2499                   std::vector<number_t> dofrenumber = renumber(spuv, spu);
2500                   if(dofrenumber.size() != 0) entries_p->extendEntries(dofrenumber, spuv->dimSpace());
2501                 }
2502             }
2503           VectorEntry* ve = v.entries_p;
2504           VectorEntry* vse = v.scalar_entries_p;
2505           if(spv != spuv)  // extend v entry if required
2506             {
2507               if(v.scalar_entries_p != 0 && v.scalar_entries_p != v.entries_p)
2508                 {
2509                   vse=new VectorEntry(*v.scalar_entries_p);
2510                   std::vector<number_t> dofrenumber;
2511                   if(u_p == v.u_p) dofrenumber=renumber(v.cdofs(), cdofs());
2512                   else              dofrenumber=renumber(v.cdofs(), dualDofComponents(cdofs()));
2513                   if(dofrenumber.size() != 0) vse->extendEntries(dofrenumber, v.cdofs().size());
2514                 }
2515               if(v.entries_p != 0)
2516                 {
2517                   ve = new VectorEntry(*v.entries_p);      //copy of v entries
2518                   std::vector<number_t> dofrenumber = renumber(spuv, spv);
2519                   if(dofrenumber.size() != 0) ve->extendEntries(dofrenumber, spuv->dimSpace());      //do algebraic operation on entries
2520                 }
2521             }
2522           if(v.scalar_entries_p != 0 && v.scalar_entries_p != v.entries_p)
2523             {
2524               *scalar_entries_p += *vse;
2525             }
2526           if(v.entries_p != 0)
2527             {
2528               *entries_p += *ve;  // do algebraic operation on entries
2529             }
2530         }
2531     }
2532 
2533   return *this;
2534 }
2535 
operator -=(const SuTermVector & v)2536 SuTermVector& SuTermVector::operator-=(const SuTermVector& v)           // operation U-=V
2537 {
2538   if(u_p != v.u_p && u_p != v.u_p->dual_p())
2539     {
2540       where("SutermVector::operator-=");
2541       error("term_inconsistent_unknowns"); //different unknowns, error
2542     }
2543   if(v.entries_p == 0 && v.scalar_entries_p == 0) return *this;    //v has no entries, add 0 !
2544 
2545   // first, we have to check if both vectors have the same entries structure
2546   // if no, we have to set v to the same structure, through a copy
2547   bool copyNeeded=false;
2548   bool vToScalar=false;
2549   bool vToVector=false;
2550   if(scalar_entries_p != 0 && scalar_entries_p != entries_p && v.scalar_entries_p == 0)
2551     {
2552       copyNeeded=vToScalar=true;
2553     }
2554   else if(scalar_entries_p == 0 && v.scalar_entries_p !=0 && v.scalar_entries_p != v.entries_p)
2555     {
2556       copyNeeded=vToVector=true;
2557     }
2558 
2559   if(copyNeeded)
2560     {
2561       SuTermVector vcopy(v);
2562       if(vToScalar)
2563         {
2564           vcopy.toScalar();
2565         }
2566       if(vToVector)
2567         {
2568           vcopy.toVector();
2569         }
2570 
2571       Space* spu = space_p, *spv = v.space_p;
2572       if(spu == spv)  // same numbering => go to entries operation
2573         {
2574           if(vToVector)
2575             {
2576               if(entries_p == 0) entries_p = new VectorEntry(vcopy.valueType(), vcopy.strucType(), vcopy.nbDofs(), vcopy.nbOfComponents());
2577               *entries_p -= *vcopy.entries_p;
2578             }
2579           if(vToScalar)
2580             {
2581               if(scalar_entries_p == 0) scalar_entries_p = new VectorEntry(vcopy.valueType(), vcopy.strucType(), vcopy.nbDofs()*vcopy.nbOfComponents(), 1);
2582               *scalar_entries_p -= *vcopy.scalar_entries_p;
2583             }
2584         }
2585       else // not the same numbering => dynamic renumbering
2586         {
2587           Space* spuv = mergeSubspaces(spu,spv); // create union of subspaces, may be spu or spv or anything else
2588           space_p=spuv;                          // update subspace member
2589 
2590           if(spu != spuv)  // extend current entry if required
2591             {
2592               if(vToVector)
2593                 {
2594                   if(entries_p != 0 && vcopy.entries_p != 0)
2595                     {
2596                       std::vector<number_t> dofrenumber = renumber(spuv, spu);
2597                       if(dofrenumber.size() != 0) entries_p->extendEntries(dofrenumber, spuv->dimSpace());
2598                     }
2599                   VectorEntry* ve = vcopy.entries_p;
2600 
2601                   if(spv != spuv)
2602                     {
2603                       if(entries_p != 0 && vcopy.entries_p != 0)
2604                         {
2605                           ve = new VectorEntry(*vcopy.entries_p); // copy of v entries
2606                           std::vector<number_t> dofrenumber = renumber(spuv, spv);
2607                           if(dofrenumber.size() != 0) ve->extendEntries(dofrenumber, spuv->dimSpace());  // do algebraic operation on entries
2608                         }
2609                     }
2610                   if(entries_p != 0 && vcopy.entries_p != 0)
2611                     {
2612                       *entries_p -= *ve;  // do algebraic operation on entries
2613                     }
2614                 }
2615               if(vToScalar)
2616                 {
2617                   if(scalar_entries_p != 0 && scalar_entries_p != entries_p)
2618                     {
2619                       std::vector<number_t> dofrenumber;
2620                       if(u_p == vcopy.u_p) dofrenumber=renumber(cdofs(), vcopy.cdofs());
2621                       else                  dofrenumber=renumber(cdofs(), dualDofComponents(vcopy.cdofs()));
2622                       if(dofrenumber.size() != 0) scalar_entries_p->extendEntries(dofrenumber, cdofs().size());
2623                     }
2624                   VectorEntry* vse = vcopy.scalar_entries_p;
2625 
2626                   if(spv != spuv)
2627                     {
2628                       if(scalar_entries_p != 0 && scalar_entries_p != entries_p)
2629                         {
2630                           vse=new VectorEntry(*vcopy.scalar_entries_p);
2631                           std::vector<number_t> dofrenumber;
2632                           if(u_p == vcopy.u_p) dofrenumber=renumber(vcopy.cdofs(), cdofs());
2633                           else                  dofrenumber=renumber(vcopy.cdofs(), dualDofComponents(cdofs()));
2634                           if(dofrenumber.size() != 0) vse->extendEntries(dofrenumber, vcopy.cdofs().size());
2635                         }
2636                     }
2637                   if(scalar_entries_p != 0 && scalar_entries_p != entries_p)
2638                     {
2639                       *scalar_entries_p -= *vse;  // do algebraic operation on entries
2640                     }
2641                 }
2642             }
2643         }
2644     }
2645   else
2646     {
2647       Space* spu = space_p, *spv = v.space_p;
2648       if(spu == spv)  // same numbering => go to entries operation
2649         {
2650           if(v.scalar_entries_p != 0 && v.scalar_entries_p != v.entries_p)
2651             {
2652               if(scalar_entries_p == 0) scalar_entries_p = new VectorEntry(v.valueType(), v.strucType(), v.nbDofs()*v.nbOfComponents(), 1);
2653               if(scalar_entries_p != entries_p) *scalar_entries_p -= *v.scalar_entries_p;
2654             }
2655           if(v.entries_p != 0)
2656             {
2657               if(entries_p == 0) entries_p = new VectorEntry(v.valueType(), v.strucType(), v.nbDofs(), v.nbOfComponents());
2658               *entries_p -= *v.entries_p;
2659             }
2660         }
2661       else // not the same numbering => dynamic renumbering
2662         {
2663           Space* spuv = mergeSubspaces(spu, spv); // create union of subspaces, may be spu or spv or anything else
2664           space_p = spuv;                         // update subspace member
2665 
2666           if(spu != spuv)  //extend current entry if required
2667             {
2668               if(v.scalar_entries_p != 0 && v.scalar_entries_p != v.entries_p)
2669                 {
2670                   std::vector<number_t> dofrenumber;
2671                   if(u_p == v.u_p) dofrenumber=renumber(cdofs(), v.cdofs());
2672                   else              dofrenumber=renumber(cdofs(), dualDofComponents(v.cdofs()));
2673                   if(dofrenumber.size() != 0) scalar_entries_p->extendEntries(dofrenumber, cdofs().size());
2674                 }
2675               if(v.entries_p != 0)
2676                 {
2677                   std::vector<number_t> dofrenumber = renumber(spuv, spu);
2678                   if(dofrenumber.size() != 0) entries_p->extendEntries(dofrenumber, spuv->dimSpace());
2679                 }
2680             }
2681           VectorEntry* ve = v.entries_p;
2682           VectorEntry* vse = v.scalar_entries_p;
2683           if(spv != spuv)  // extend v entry if required
2684             {
2685               if(v.scalar_entries_p != 0 && v.scalar_entries_p != v.entries_p)
2686                 {
2687                   vse=new VectorEntry(*v.scalar_entries_p);
2688                   std::vector<number_t> dofrenumber;
2689                   if(u_p == v.u_p) dofrenumber=renumber(v.cdofs(), cdofs());
2690                   else              dofrenumber=renumber(v.cdofs(), dualDofComponents(cdofs()));
2691                   if(dofrenumber.size() != 0) vse->extendEntries(dofrenumber, v.cdofs().size());
2692                 }
2693               if(v.entries_p != 0)
2694                 {
2695                   ve = new VectorEntry(*v.entries_p);      //copy of v entries
2696                   std::vector<number_t> dofrenumber = renumber(spuv, spv);
2697                   if(dofrenumber.size() != 0) ve->extendEntries(dofrenumber, spuv->dimSpace());      //do algebraic operation on entries
2698                 }
2699             }
2700           if(v.scalar_entries_p != 0 && v.scalar_entries_p != v.entries_p)
2701             {
2702               *scalar_entries_p -= *vse;
2703             }
2704           if(v.entries_p != 0)
2705             {
2706               *entries_p -= *ve;  // do algebraic operation on entries
2707             }
2708         }
2709     }
2710 
2711   return *this;
2712 }
2713 
2714 // merging a SuTermVector with current one BUT preserving the current value when common dofs
2715 // like a += but without summing values of common dofs
2716 // process works as following :
2717 //    - detect common dofs
2718 //    - if there are some
2719 //         - copy of SuTermVector to merge with
2720 //         - replace by 0 the value related to a common dofs
2721 //    - use += operator
merge(const SuTermVector & v)2722 SuTermVector& SuTermVector::merge(const SuTermVector& v)
2723 {
2724   trace_p->push("SuTermVector::merge(SuTermVector)");
2725   if(u_p != v.u_p && u_p != v.u_p->dual_p())
2726     {
2727       where("SutermVector::merge");
2728       error("term_inconsistent_unknowns"); //different unknowns, error
2729     }
2730   Space* spu = space_p, *spv = v.space_p;
2731   if(spu == spv)    //same numbering, merge do nothing
2732     {
2733       trace_p->pop();
2734       return *this;
2735     }
2736   //find common dofs
2737   std::vector<number_t> dofrenumber = renumber(spu, spv);
2738   bool noCommonDofs = true;
2739   std::vector<number_t>::iterator itn = dofrenumber.begin();
2740   while(itn != dofrenumber.end() && noCommonDofs)
2741     {
2742       if(*itn != 0) noCommonDofs = false;
2743       else ++itn;
2744     }
2745   SuTermVector* vc = const_cast<SuTermVector*>(&v);
2746   if(!noCommonDofs)   //have common dofs, copy v and set 0 values on common dofs
2747     {
2748       vc = new SuTermVector(v);
2749       StrucType st = vc->strucType();
2750       ValueType vt = vc->valueType();
2751       VectorEntry* entries = vc->entries();
2752       complex_t z0(0., 0.);
2753       switch(st)
2754         {
2755           case _scalar :
2756             if(vt == _real)
2757               {
2758                 number_t i = 1;
2759                 for(itn = dofrenumber.begin(); itn != dofrenumber.end(); ++itn, ++i)
2760                   if(*itn != 0)  entries->setValue(i, 0.);
2761               }
2762             else
2763               {
2764                 number_t i = 1;
2765                 for(itn = dofrenumber.begin(); itn != dofrenumber.end(); ++itn, ++i)
2766                   if(*itn != 0)  entries->setValue(i, z0);
2767               }
2768             break;
2769           case _vector :
2770             if(vt == _real)
2771               {
2772                 number_t i = 1;
2773                 Vector<real_t> rv0(vc->nbOfComponents(), 0.);
2774                 for(itn = dofrenumber.begin(); itn != dofrenumber.end(); ++itn, ++i)
2775                   if(*itn != 0)  entries->setValue(i, rv0);
2776               }
2777             else
2778               {
2779                 number_t i = 1;
2780                 Vector<complex_t> rc0(vc->nbOfComponents(), z0);
2781                 for(itn = dofrenumber.begin(); itn != dofrenumber.end(); ++itn, ++i)
2782                   if(*itn != 0)  entries->setValue(i, rc0);
2783               }
2784             break;
2785           default :
2786             error("scalar_or_vector");
2787         }
2788     }
2789   //add to current
2790   (*this) += *vc;
2791 
2792   if(vc != &v) delete vc;
2793   trace_p->pop();
2794   return *this;
2795 }
2796 
2797 /*! compute SuTermVector from a linear combination of SuTermVector's
2798  the current SuTermVector is assumed to be void, this function fills every things
2799  if it is not the case, every thing is clear
2800 */
compute(const LcTerm<SuTermVector> & lc)2801 void SuTermVector::compute(const LcTerm<SuTermVector>& lc)
2802 {
2803   trace_p->push("SuTermVector::compute(LcTerm)");
2804   clear();
2805   if(lc.size() == 0) error("is_void", "LcTerm");
2806 
2807   termType_ = _sutermVector;
2808   if(lc.size() == 1)  //copy and multiplication
2809     {
2810       const SuTermVector* sut = dynamic_cast<const SuTermVector*>(lc.begin()->first);
2811       if(sut == 0) error("null_pointer", "SuTermVector");
2812       complex_t a = lc.begin()->second;
2813       sulf_p = sut->sulf_p;
2814       u_p = sut->u_p;
2815       space_p = sut->space_p;
2816       subspaces = sut->subspaces;
2817       entries_p = new VectorEntry(*sut->entries_p);
2818       if(a != complex_t(1., 0.)) *entries_p *= a;
2819       computed() = true;
2820       trace_p->pop();
2821       return;
2822     }
2823 
2824   //clear current linear form properties
2825   subspaces.clear();
2826   if(sulf_p == 0) delete sulf_p;
2827   sulf_p = 0;
2828 
2829   // create largest space and subspace numberings related to this largest space
2830   std::vector<Space*> spaces(lc.size(), 0);
2831   std::vector<Space*>::iterator its = spaces.begin();
2832   const SuTermVector* stv = dynamic_cast<const SuTermVector*>(lc.begin()->first);
2833   if(stv == 0) error("null_pointer", "SuTermVector");
2834   ValueType vt = stv->valueType();
2835   StrucType st = stv->strucType();
2836   u_p = stv->u_p;
2837   for(LcTerm<SuTermVector>::const_iterator itt = lc.begin(); itt != lc.end(); itt++, its++)
2838     {
2839       const SuTermVector* stv = dynamic_cast<const SuTermVector*>(itt->first);
2840       if(stv == 0) error("null_pointer", "SuTermVector");
2841       *its = stv->space_p; // list of (sub)spaces
2842       if(stv->valueType() == _complex) vt = _complex;
2843       if(stv->strucType() != st)
2844         error("term_mismatch_structures", words("structure", stv->strucType()), words("structure", st));
2845     }
2846   if(lc.coefType() == _complex) vt = _complex;
2847   space_p = mergeSubspaces(spaces, true);
2848 
2849   //allocate entries of current SuTermVector
2850   entries_p = new VectorEntry(vt, st, space_p->dimSpace(), u_p->nbOfComponents());
2851 
2852   //do linear combination
2853   its = spaces.begin();
2854   for(LcTerm<SuTermVector>::const_iterator itt = lc.begin(); itt != lc.end(); itt++, its++)
2855     {
2856       const SuTermVector* stv = dynamic_cast<const SuTermVector*>(itt->first);
2857       if(!stv->computed()) error("not_computed_term", stv->name());
2858       Space* sp = *its;
2859       //if (sp->typeOfSpace() == _subSpace)
2860       if(sp->typeOfSpace() == _subSpace && sp != space_p)
2861         {
2862           if(vt == _real) entries_p->add(*stv->entries_p, sp->subSpace()->dofNumbers(), itt->second.real());
2863           else entries_p->add(*stv->entries_p, sp->subSpace()->dofNumbers(), itt->second);
2864         }
2865       else  //subspace is the largest space (same numbering)
2866         {
2867           if(vt == _real) entries_p->add(*stv->entries_p, itt->second.real());
2868           else entries_p->add(*stv->entries_p, itt->second);
2869         }
2870     }
2871   //may be it is best to delete new subspaces created here (to be done later)
2872   computed() = true;
2873   trace_p->pop();
2874 }
2875 
2876 /*! interpolate current sutermvector on u space and domain dom
2877            sutr(i) = sum_j sutv_j w_j(Mi)  Mi nodes of Lagrange u-space, Mi in dom
2878                                            wj shape functions related to sutv
2879     return a new SuTermMatrix allocated here
2880     quite expansive !!!
2881 */
interpolate(const Unknown & u,const GeomDomain & dom)2882 SuTermVector* SuTermVector::interpolate(const Unknown& u, const GeomDomain& dom)
2883 {
2884   trace_p->push("SuTermVector::interpolate(Unknown, GeomDomain)");
2885   if(u.space() == space_p) return onDomain(dom);  //same space, apply restriction to domain dom
2886   if(!u.space()->isFE()) error("not_fe_space_type", u.space()->name());
2887   if(u.space()->interpolation()->type != _Lagrange) error("lagrange_fe_space_only", u.space()->name());
2888 
2889   //get subspace
2890   Space* spu = u.space();
2891   Space* subsp = Space::findSubSpace(&dom, spu);         //find subspace (linked to domain dom) of spu
2892   if(subsp == 0) subsp = new Space(dom, *spu, spu->name() + "_" + dom.name());  //create if not exist
2893 
2894   //create suTermVector
2895   std::vector<number_t> dofs = subsp->dofIds();
2896   number_t nd = dofs.size();
2897   string_t na = name_ + "_interpolated_" + u.space()->name() + "_" + dom.name();
2898   SuTermVector* sutv = new SuTermVector(na, &u, subsp, valueType(), nd, u.nbOfComponents());
2899 
2900   //travel dofs and interpolate at node, store value
2901   std::vector<number_t>::iterator itd = dofs.begin();
2902   number_t k = 1;
2903   for(; itd != dofs.end(); ++itd, ++k)
2904     {
2905       Point p = subsp->rootSpace()->feSpace()->dofs[*itd - 1].coords();
2906       Value v = evaluate(p);
2907       sutv->entries_p->setValue(k, v);
2908     }
2909   sutv->computed() = true;
2910   trace_p->pop();
2911   return sutv;
2912 
2913 }
2914 
2915 //! print SuTermVector
print(std::ostream & out) const2916 void SuTermVector::print(std::ostream& out) const
2917 {
2918   print(out, false, true);
2919 }
2920 
2921 //if raw=true only x y z v is print
print(std::ostream & out,bool raw,bool header) const2922 void SuTermVector::print(std::ostream& out, bool raw, bool header) const
2923 {
2924   if(theVerboseLevel == 0) return;
2925   if(header && !raw) out << "   SuTermVector " << name() << ", " << " unknown " << u_p->name() << ", "
2926                            << words("value", valueType()) << " " << words("structure", strucType())
2927                            << ", ";
2928   if(sulf_p != 0) out << (*sulf_p) << "\n";
2929   if(!computed())
2930     {
2931       out << words("not computed") << "\n";
2932       return;
2933     }
2934   if(entries_p == 0 && scalar_entries_p == 0)
2935     {
2936       out << "  unallocated SuTermVector block" << eol;
2937       return;
2938     }
2939   if(theVerboseLevel < 2) return;
2940   if(!raw)
2941     {
2942       if(nbOfComponents() > 1) out << " (size=" << nbOfComponents() << "),";
2943       out << " " << size() << " " << words("values");
2944       if(theVerboseLevel < 2)
2945         {
2946           out << eol;
2947           return;
2948         }
2949 
2950       //first and last values
2951       blanks(eol, 3);
2952       number_t s = size();
2953       number_t n = std::min(number_t(theVerboseLevel), s);
2954 
2955       if(entries_p != 0)  //display dofid and coordinates when dof is a ponctual fedof
2956         {
2957           number_t dims = space_p->nbDofs();
2958           number_t wd = std::floor(std::log10(dims))+1;
2959           if(2 * n >= dims)  //print all value
2960             {
2961               out << ", all values" << eol;
2962               std::vector<string_t> com(dims, "");
2963               number_t w=0;
2964               for(number_t i = 0; i < dims; i++)
2965                 { com[i] = space_p->dof(i + 1).dofData(wd); w=std::max(w,com[i].size());}
2966               for(number_t i = 0; i <dims; i++)
2967                 {
2968                   number_t s = w-com[i].size();
2969                   if(s>0) com[i]+= string_t(s,' ');
2970                   com[i]+=" -> ";
2971                 }
2972               entries_p->printFirst(out, dims, com);
2973             }
2974           else
2975             {
2976               out << ", first and last " << tostring(n) << " values" << eol;
2977               std::vector<string_t> comd(n, ""), comf(n, "");
2978               number_t w=0;
2979               for(number_t i = 0; i < n; i++)
2980                 {
2981                   comd[i] = space_p->dof(i + 1).dofData(wd); w=std::max(w,comd[i].size());
2982                   comf[i] = space_p->dof(dims - n + i + 1).dofData(wd); w=std::max(w,comf[i].size());
2983                 }
2984               for(number_t i = 0; i <n; i++)
2985                 {
2986                   number_t s = w-comd[i].size();
2987                   if(s>0) comd[i]+= string_t(s,' ');
2988                   comd[i]+=" -> ";
2989                   s = w-comf[i].size();
2990                   if(s>0) comf[i]+= string_t(s,' ');
2991                   comf[i]+=" -> ";
2992                 }
2993               entries_p->printFirst(out, n, comd);
2994               out << "..." << eol;
2995               entries_p->printLast(out, n, comf);
2996             }
2997         }
2998       if(scalar_entries_p != 0)
2999         {
3000           out << " scalar entries : " << tostring(scalar_entries_p->size()) << " "
3001               << words("value", valueType()) << " values" << eol;
3002           out << words("firste") << " " << words("row") << " cdofs : ";
3003           number_t nbd = cdofs_.size();
3004           number_t m = std::min(number_t(theVerboseLevel), nbd);
3005           std::vector<DofComponent>::const_iterator itd = cdofs_.begin();
3006           for(number_t i = 0; i < m; i++, itd++)  out  << *itd << "  ";
3007           if(m < nbd) out << "...";
3008           out << eol;
3009           if(scalar_entries_p != entries_p) out << (*scalar_entries_p);
3010         }
3011       blanks(eol, -3);
3012       out << eol;
3013     }
3014   else  //raw format
3015     {
3016       if(entries_p != 0)
3017         {
3018           number_t dims = space_p->nbDofs();
3019           std::vector<string_t> com(dims, "");
3020           for(number_t i = 0; i < dims; i++)
3021             {
3022               Point pi = space_p->dof(i + 1).coords();
3023               for(number_t j = 0; j < pi.size(); j++) com[i] +=  tostring(pi[j]) + " ";
3024             }
3025           entries_p->printFirst(out, dims, com);
3026         }
3027       if(scalar_entries_p != 0 && scalar_entries_p != entries_p)
3028         {
3029           number_t dims = nbOfComponents() * space_p->nbDofs();
3030           std::vector<string_t> com(dims, "");
3031           scalar_entries_p->printFirst(out, dims, com);
3032         }
3033     }
3034 }
3035 
innerProduct(const SuTermVector & tv1,const SuTermVector & tv2)3036 complex_t innerProduct(const SuTermVector& tv1, const SuTermVector& tv2)
3037 {
3038   trace_p->push("innerProduct(SuTermVector,SuTermVector)");
3039   if(&tv1 == &tv2)  //same SuTermVectors
3040     {
3041       if(tv1.scalar_entries() != 0)
3042         {
3043           trace_p->pop();
3044           return innerProduct(*tv1.scalar_entries(), *tv1.scalar_entries());
3045         }
3046       else
3047         {
3048           trace_p->pop();
3049           return innerProduct(*tv1.entries(), *tv1.entries());
3050         }
3051     }
3052   //check consistancy of unknowns
3053   complex_t res = 0.;
3054   if(tv1.up() != tv2.up() && tv1.up() != tv2.up()->dual_p()) error("term_inconsistent_unknowns");
3055   number_t n1 = tv1.spacep()->dimSpace(), n2 = tv2.spacep()->dimSpace();
3056   if(n1 > n2) res = innerProduct(tv2, tv1);
3057   else
3058     {
3059       bool copyNeeded2=false;
3060       bool toScalar2=false;
3061       bool toVector2=false;
3062       if(tv1.scalar_entries() != 0 && tv1.scalar_entries() != tv1.entries() && tv2.scalar_entries() == 0)
3063         {
3064           copyNeeded2=toScalar2=true;
3065         }
3066       else if(tv1.scalar_entries() == 0 && tv2.scalar_entries() !=0 && tv2.scalar_entries() != tv2.entries())
3067         {
3068           copyNeeded2=toVector2=true;
3069         }
3070 
3071       if(copyNeeded2)
3072         {
3073           SuTermVector tv2copy(tv2);
3074           if(toScalar2) tv2copy.toScalar();
3075           if(toVector2) tv2copy.toVector();
3076           if(tv1.scalar_entries() != 0 && tv1.scalar_entries() != tv1.entries() &&
3077               tv2copy.scalar_entries() != 0 && tv2copy.scalar_entries() != tv2copy.entries())
3078             {
3079               if(tv1.spacep() == tv2copy.spacep()) res = innerProduct(*tv1.scalar_entries(), *tv2copy.scalar_entries());
3080               else  //align vector
3081                 {
3082                   bool useDual = (tv1.up() == tv2.up()->dual_p());
3083                   tv2copy.extendScalarTo(tv1.cdofs(), useDual);      //align tv2copy on tv1
3084                   res = innerProduct(*tv1.scalar_entries(), *tv2copy.scalar_entries());
3085                 }
3086             }
3087           else
3088             {
3089               if(tv1.entries() == 0) error("null_pointer", "tv1.entries_p");
3090               if(tv2copy.entries() == 0) error("null_pointer", "tv2.entries_p");
3091               if(tv1.spacep() == tv2copy.spacep()) res = innerProduct(*tv1.entries(), *tv2copy.entries());
3092               else  //align vector
3093                 {
3094                   tv2copy.extendTo(tv1);      //align tv2copy on tv1
3095                   res = innerProduct(*tv1.entries(), *tv2copy.entries());
3096                 }
3097             }
3098         }
3099       else
3100         {
3101           if(tv1.scalar_entries() != 0 && tv1.scalar_entries() != tv1.entries() &&
3102               tv2.scalar_entries() != 0 && tv2.scalar_entries() != tv2.entries())
3103             {
3104               if(tv1.spacep() == tv2.spacep()) res = innerProduct(*tv1.scalar_entries(), *tv2.scalar_entries());
3105               else  //align vector
3106                 {
3107                   SuTermVector tw2(tv2);  //copy tv2
3108                   bool useDual = (tv1.up() == tv2.up()->dual_p());
3109                   tw2.extendScalarTo(tv1.cdofs(), useDual);      //align tw2 on tv1
3110                   res = innerProduct(*tv1.scalar_entries(), *tw2.scalar_entries());
3111                 }
3112             }
3113           else
3114             {
3115               if(tv1.entries() == 0) error("null_pointer", "tv1.entries_p");
3116               if(tv2.entries() == 0) error("null_pointer", "tv2.entries_p");
3117               if(tv1.spacep() == tv2.spacep()) res = innerProduct(*tv1.entries(), *tv2.entries());
3118               else  //align vector
3119                 {
3120                   SuTermVector tw2(tv2);  //copy tv2
3121                   tw2.extendTo(tv1);      //align tw2 on tv1
3122                   res = innerProduct(*tv1.entries(), *tw2.entries());
3123                 }
3124             }
3125         }
3126     }
3127   trace_p->pop();
3128   return res;
3129 }
3130 
hermitianProduct(const SuTermVector & tv1,const SuTermVector & tv2)3131 complex_t hermitianProduct(const SuTermVector& tv1, const SuTermVector& tv2)
3132 {
3133   trace_p->push("hermitianProduct(SuTermVector,SuTermVector)");
3134   complex_t res = 0;
3135   if(&tv1 == &tv2)  //same SuTermVectors
3136     {
3137       if(tv1.scalar_entries() != 0)
3138         {
3139           trace_p->pop();
3140           return hermitianProduct(*tv1.scalar_entries(), *tv1.scalar_entries());
3141         }
3142       else
3143         {
3144           trace_p->pop();
3145           return hermitianProduct(*tv1.entries(), *tv1.entries());
3146         }
3147     }
3148   //check consistancy of unknowns
3149   if(tv1.up() != tv2.up() && tv1.up() != tv2.up()->dual_p()) error("term_inconsistent_unknowns");
3150   number_t n1 = tv1.spacep()->dimSpace(), n2 = tv2.spacep()->dimSpace();
3151   if(n1 > n2) res = std::conj(hermitianProduct(tv2, tv1));
3152   else
3153     {
3154       bool copyNeeded2=false;
3155       bool toScalar2=false;
3156       bool toVector2=false;
3157       if(tv1.scalar_entries() != 0 && tv1.scalar_entries() != tv1.entries() && tv2.scalar_entries() == 0)
3158         {
3159           copyNeeded2=toScalar2=true;
3160         }
3161       else if(tv1.scalar_entries() == 0 && tv2.scalar_entries() != 0 && tv2.scalar_entries() != tv2.entries())
3162         {
3163           copyNeeded2=toVector2=true;
3164         }
3165 
3166       if(copyNeeded2)
3167         {
3168           SuTermVector tv2copy(tv2);
3169           if(toScalar2) tv2copy.toScalar();
3170           if(toVector2) tv2copy.toVector();
3171           if(tv1.scalar_entries() != 0 && tv1.scalar_entries() != tv1.entries() &&
3172               tv2copy.scalar_entries() != 0 && tv2copy.scalar_entries() != tv2copy.entries())
3173             {
3174               if(tv1.spacep() == tv2copy.spacep()) res = hermitianProduct(*tv1.scalar_entries(), *tv2copy.scalar_entries());
3175               else  //align vector
3176                 {
3177                   bool useDual = (tv1.up() == tv2.up()->dual_p());
3178                   tv2copy.extendScalarTo(tv1.cdofs(), useDual);      //align tv2copy on tv1
3179                   res = hermitianProduct(*tv1.scalar_entries(), *tv2copy.scalar_entries());
3180                 }
3181             }
3182           else
3183             {
3184               if(tv1.entries() == 0) error("null_pointer", "tv1.entries_p");
3185               if(tv2copy.entries() == 0) error("null_pointer", "tv2.entries_p");
3186               if(tv1.spacep() == tv2copy.spacep()) res = hermitianProduct(*tv1.entries(), *tv2copy.entries());
3187               else  //align vector
3188                 {
3189                   tv2copy.extendTo(tv1);      //align tv2copy on tv1
3190                   res = hermitianProduct(*tv1.entries(), *tv2copy.entries());
3191                 }
3192             }
3193         }
3194       else
3195         {
3196           if(tv1.scalar_entries() != 0 && tv1.scalar_entries() != tv1.entries() &&
3197               tv2.scalar_entries() != 0 && tv2.scalar_entries() != tv2.entries())
3198             {
3199               if(tv1.spacep() == tv2.spacep()) res = hermitianProduct(*tv1.scalar_entries(), *tv2.scalar_entries());
3200               else  //align vector
3201                 {
3202                   SuTermVector tw2(tv2);  //copy tv2
3203                   bool useDual = (tv1.up() == tv2.up()->dual_p());
3204                   tw2.extendScalarTo(tv1.cdofs(), useDual);      //align tw2 on tv1
3205                   res = hermitianProduct(*tv1.scalar_entries(), *tw2.scalar_entries());
3206                 }
3207             }
3208           else
3209             {
3210               if(tv1.entries() == 0) error("null_pointer", "tv1.entries_p");
3211               if(tv2.entries() == 0) error("null_pointer", "tv2.entries_p");
3212               if(tv1.spacep() == tv2.spacep()) res = hermitianProduct(*tv1.entries(), *tv2.entries());
3213               else  //align vector
3214                 {
3215                   SuTermVector tw2(tv2);  //copy tv2
3216                   tw2.extendTo(tv1);      //align tw2 on tv1
3217                   res = hermitianProduct(*tv1.entries(), *tw2.entries());
3218                 }
3219             }
3220         }
3221     }
3222   trace_p->pop();
3223   return res;
3224 }
3225 
3226 // vector norms
norm1(const SuTermVector & tv)3227 real_t norm1(const SuTermVector& tv)
3228 {
3229   if(tv.scalar_entries() != 0) return norm1(*tv.scalar_entries());
3230   if(tv.entries() != 0) return norm1(*tv.entries());
3231   return 0.;
3232 }
3233 
norminfty(const SuTermVector & tv)3234 real_t norminfty(const SuTermVector& tv)
3235 {
3236   if(tv.scalar_entries() != 0) return norminfty(*tv.scalar_entries());
3237   if(tv.entries() != 0) return norminfty(*tv.entries());
3238   return 0.;
3239 }
3240 
3241 // return the value (in complex) of component being the largest one in absolute value
3242 // travel all SCALAR components of SuTermVector using scalar entries if exists
maxValAbs() const3243 complex_t SuTermVector::maxValAbs() const
3244 {
3245   if(scalar_entries_p != 0) return scalar_entries_p->maxValAbs();
3246   if(entries_p != 0) return entries_p->maxValAbs();
3247   return complex_t(0.);
3248 }
3249 
3250 //=================================================================================
3251 // SuTermVectors member functions
3252 //=================================================================================
3253 
3254 // move all SuTermVector's to real
toReal()3255 SuTermVectors& SuTermVectors::toReal()
3256 {
3257   std::vector<SuTermVector>::iterator itv = begin();
3258   for(; itv != end(); itv++) itv->toReal();
3259   return *this;
3260 }
3261 
toImag()3262 SuTermVectors& SuTermVectors::toImag()
3263 {
3264   std::vector<SuTermVector>::iterator itv = begin();
3265   for(; itv != end(); itv++) itv->toImag();
3266   return *this;
3267 }
3268 
print(std::ostream & os) const3269 void SuTermVectors::print(std::ostream& os) const
3270 {
3271   os << "list of SuTermVector's (" << size() << ")" << eol;
3272   if(theVerboseLevel < 2) return;
3273   std::vector<SuTermVector>::const_iterator itv = begin();
3274   for(; itv != end(); itv++) itv->print(os);
3275 }
3276 
operator <<(std::ostream & os,const SuTermVectors & tvs)3277 std::ostream& operator<<(std::ostream& os, const SuTermVectors& tvs)
3278 {
3279   tvs.print(os);
3280   return os;
3281 }
3282 
3283 /*! adjust the  scalar entries to the cdofs numbering newcdofs
3284     when cdofs  is included in newcdofs, new zeros are introduced (extension)
3285     when newcdofs is included in cdofs , coefficients are removed (restriction)
3286     else it is in a same time a restriction (removed cdofs)  and an extension (omitted cdof)
3287     in any case, the coefficient may be permuted and cdofs = newcdofs at the end
3288 
3289     used by SuTermVector and TermVector
3290 */
adjustScalarEntriesG(VectorEntry * & scalar_entries_p,std::vector<DofComponent> & cdofs,const std::vector<DofComponent> & newcdofs)3291 void adjustScalarEntriesG(VectorEntry*& scalar_entries_p, std::vector<DofComponent>& cdofs, const std::vector<DofComponent>& newcdofs)
3292 {
3293   trace_p->push("adjustScalarEntriesG(VectorEntry*, vector<DofComponent>&, vector<DofComponent>&)");
3294   std::map<DofComponent, number_t> mcdofs;
3295   std::vector<DofComponent>::iterator itd = cdofs.begin();
3296   std::vector<DofComponent>::const_iterator itn = newcdofs.begin();
3297   number_t k = 0;
3298   bool sameNum = true;
3299   for(; itd != cdofs.end(); itd++, k++)
3300     {
3301       mcdofs[*itd] = k;
3302       if(sameNum && itn != newcdofs.end())
3303         {
3304           if(*itd != *itn  && *itd != itn->dual()) sameNum = false;  //allows dual unknown (permissive)
3305           itn++;
3306         }
3307     }
3308   if(sameNum && cdofs.size() == newcdofs.size())
3309     {
3310       trace_p->pop();  //nothing done
3311       return;
3312     }
3313 
3314   //create new vector
3315   ValueType vt = _real;
3316   if(scalar_entries_p != 0) vt = scalar_entries_p->valueType_;
3317   VectorEntry* ve = new VectorEntry(vt, _scalar, newcdofs.size());
3318   std::map<DofComponent, number_t>::iterator itmd;
3319   if(vt == _real)  //real case
3320     {
3321       Vector<real_t>::iterator itve = ve->beginr(), itv = scalar_entries_p->beginr();
3322       for(itn = newcdofs.begin(); itn != newcdofs.end(); itn++, itve++)
3323         {
3324           itmd = mcdofs.find(*itn);
3325           if(itmd == mcdofs.end()) itmd = mcdofs.find(itn->dual());
3326           if(itmd != mcdofs.end()) *itve = *(itv + itmd->second);
3327         }
3328     }
3329   else  //complex case
3330     {
3331       Vector<complex_t>::iterator itve = ve->beginc(), itv = scalar_entries_p->beginc();
3332       for(itn = newcdofs.begin(); itn != newcdofs.end(); itn++, itve++)
3333         {
3334           itmd = mcdofs.find(*itn);
3335           if(itmd == mcdofs.end()) itmd = mcdofs.find(itn->dual());  //find with dual (permissive)
3336           if(itmd != mcdofs.end()) *itve = *(itv + itmd->second);
3337         }
3338     }
3339   //update current vector
3340   if(scalar_entries_p != 0) delete scalar_entries_p;
3341   scalar_entries_p = ve;
3342   cdofs = newcdofs;
3343   trace_p->pop();
3344 }
3345 
3346 } //end of namespace xlifepp
3347