1 // $Id$
2 
3 #include <iostream>
4 #include <cfloat>
5 #include <cmath>
6 #include <complex>
7 using namespace std;
8 #include "error.hpp"
9 #include "AFunction.hpp"
10 using namespace std;
11 #include "rgraph.hpp"
12 #include "RNM.hpp"
13 #include "fem.hpp"
14 
15 
16 #include "FESpacen.hpp"
17 #include "FESpace.hpp"
18 #include "HashMatrix.hpp"
19 
20 #include "SparseLinearSolver.hpp"
21 
22 #include "MeshPoint.hpp"
23 #include "Operator.hpp"
24 #include "lex.hpp"
25 
26 #include "lgfem.hpp"
27 #include "lgmesh3.hpp"
28 #include "lgsolver.hpp"
29 #include "problem.hpp"
30 
31 #include <set>
32 #include <vector>
33 #include <fstream>
34 
35 
36 using namespace  Fem2D;
37 
38 class listMesh {
39 public:
40   list<Mesh const  *> *lth;
init()41   void init()  { lth=new list<Mesh const  *>;}
destroy()42   void destroy() { delete lth;}
listMesh(Stack s,Mesh const * th)43   listMesh(Stack s,Mesh const*th) : lth(Add2StackOfPtr2Free(s,new list<Mesh const*>)) { lth->push_back(th);}
listMesh(Stack s,Mesh const * const tha,Mesh const * const thb)44   listMesh(Stack s,Mesh const*const tha,Mesh const* const thb) : lth(Add2StackOfPtr2Free(s,new list<Mesh const*>)) { lth->push_back(tha);lth->push_back(thb);}
listMesh(Stack s,const listMesh & l,Mesh const * const th)45   listMesh(Stack s,const listMesh &l,Mesh const*const th) : lth(Add2StackOfPtr2Free(s,new list<Mesh const*>(*l.lth))) { lth->push_back(th);}
46 
47 };
48 
49 
GluMesh(list<Mesh const * > const & lth,long labtodel=-1,double eps=-1)50 Mesh * GluMesh(list<Mesh const *> const & lth, long labtodel = -1,double eps=-1)
51 {
52   int nbt=0;
53   int neb=0;
54   int nebx=0;
55   int nbv=0;
56   int nbvx=0;
57   double hmin=1e100;
58   R2 Pn(1e100,1e100),Px(-1e100,-1e100);
59   const  Mesh * th0=0;
60     int kk=0;
61   for(list<Mesh const *>::const_iterator i=lth.begin();i != lth.end();++i)
62     {
63        if(! *i ) continue;
64         ++kk;
65        const Mesh &Th(**i);
66       th0=&Th;
67       if(verbosity>1)  cout << " GluMesh  "<< kk << " + "<<  Th.nv << " " << Th.nt << endl;
68       nbt+= Th.nt;
69       nbvx += Th.nv;
70       nebx += Th.neb;
71       for (int k=0;k<Th.nt;k++)
72 	for (int e=0;e<3;e++)
73 	  hmin=min(hmin,Th[k].lenEdge(e));
74 
75       for (int i=0;i<Th.nv;i++)
76 	{
77 	  R2 P(Th(i));
78 	  Pn=Minc(P,Pn);
79 	  Px=Maxc(P,Px);
80 	}
81     }
82     if(kk==0) return 0; //  no mesh ...
83   if(verbosity>2)
84     cout << "      - hmin =" <<  hmin << " ,  Bounding Box: " << Pn
85 	 << " "<< Px << endl;
86 
87   Vertex * v= new Vertex[nbvx];
88   Triangle *t= new Triangle[nbt];
89   Triangle *tt=t;
90   BoundaryEdge *b= new BoundaryEdge[nebx];
91   BoundaryEdge *bb= b;
92 
93   ffassert(hmin>Norme2(Pn-Px)/1e9);
94   double hseuil =hmin/10.;
95   if( eps >=0. ) hseuil= eps;
96 
97     FQuadTree *quadtree=hseuil ? new Fem2D::FQuadTree(th0,Pn,Px,0):0 ;
98   {
99     map<pair<int,int>,int> bbe;
100       kk=0;
101     for(list<Mesh const  *>::const_iterator i=lth.begin();i != lth.end();++i)
102       {
103         if(! *i ) continue;
104         int offset= nbv;
105 	const Mesh &Th(**i);
106 	if(verbosity>1)  cout << "        GluMesh + "<< Th.nv << " " << Th.nt << " " << hseuil << " " << offset << endl;
107 
108 	for (int ii=0;ii<Th.nv;ii++)
109 	{
110 	  const Vertex &vi(Th(ii));
111             Vertex * pvi=0;
112             if(quadtree) pvi = quadtree->ToClose(vi,hseuil);
113 	    if(!pvi) {
114 	    v[nbv].x = vi.x;
115 	    v[nbv].y = vi.y;
116 	    v[nbv].lab = vi.lab;
117 	    if(quadtree)  quadtree->Add(v[nbv]);
118             ++nbv;
119 	  }
120 	}
121 
122 	for (int k=0;k<Th.nt;k++)
123 	  {
124 	    const Triangle  &K(Th[k]);
125               int i0,i1,i2;
126              if(quadtree)
127              {
128 	     i0=quadtree->ToClose(K[0],hseuil)-v; //NearestVertex(K[0])-v;
129 	     i1=quadtree->ToClose(K[1],hseuil)-v; //NearestVertex(K[1])-v;
130 	     i2=quadtree->ToClose(K[2],hseuil)-v; //NearestVertex(K[2])-v;
131              }
132              else
133              {
134                  i0 = offset + Th(K[0]);
135                  i1 = offset + Th(K[1]);
136                  i2 = offset + Th(K[2]);
137              }
138 	    (*tt++).set(v,i0,i1,i2,K.lab);
139 	  }
140 
141 
142 	for (int k=0;k<Th.neb;k++)
143 	  {
144 	    const BoundaryEdge & be(Th.bedges[k]);
145                int i0,i1;
146               if(quadtree)
147               {
148 	     i0=quadtree->ToClose(be[0],hseuil)-v;
149 	     i1=quadtree->ToClose(be[1],hseuil)-v;
150 	    int ii0=i0,ii1=i1;
151 	    if(ii1<ii0) Exchange(ii0,ii1);
152 	    pair<int,int> i01(ii0,ii1);
153 	    if(be.lab != labtodel && bbe.find(i01) == bbe.end())
154 	    {
155 	      (*bb++).set(v,i0,i1,be.lab);
156 	      bbe[i01]=	  neb++;
157 	    }
158               }
159               else
160               {
161                   i0 = offset + Th(be[0]);
162                   i1 = offset + Th(be[1]);
163                   (*bb++).set(v,i0,i1,be.lab);
164               }
165 	  }
166           if(verbosity>9) cout << "               " << quadtree << " "<<offset + Th.nv << " " << nbv << endl;
167           ffassert( quadtree || ( offset + Th.nv == nbv));
168       }
169   }
170 
171   delete quadtree;
172 
173 
174   if(verbosity>1)
175     {
176       cout << "     eps for equal points "<< hseuil << " (0 => no equal points) "<< endl;
177       cout << "     Nb points :  "<< nbv << " , nb edges : " << neb << endl;
178       cout << "     Nb of glue point         " << nbvx -nbv;
179       cout << "     Nb of glue Boundary edge " << nebx-neb;
180     }
181 
182   {
183     Mesh * m = new Mesh(nbv,nbt,neb,v,t,b);
184     R2 Pn,Px;
185     m->BoundingBox(Pn,Px);
186     m->quadtree=new Fem2D::FQuadTree(m,Pn,Px,m->nv);
187     return m;
188   }
189 
190 }
191 
192 template<class RR,class AA=RR,class BB=AA>
193 struct Op2_addmesh: public binary_function<AA,BB,RR> {
fOp2_addmesh194   static RR f(Stack s,const AA & a,const BB & b)
195   { return RR(s, a, b );}
196 };
197 
198 template<bool INIT,class RR,class AA=RR,class BB=AA>
199 struct Op2_setmesh: public binary_function<AA,BB,RR> {
fOp2_setmesh200   static RR f(Stack stack, const AA & a,const BB & b)
201   {
202     ffassert(a );
203     pmesh  p=GluMesh(*(b.lth));
204 
205       if(!INIT &&  *a) (**a).destroy() ;
206     return *a=p,a;
207   }
208 };
209 
210 class SetMesh_Op : public E_F0mps
211 {
212 public:
213   Expression a;
214 
215   static const int n_name_param =2+2+2+2+2; //  add nbiter FH 30/01/2007 11 -> 12
216   static basicAC_F0::name_and_type name_param[] ;
217   Expression nargs[n_name_param];
218 
arg(int i,Stack stack,KN_<long> a) const219   KN_<long>  arg(int i,Stack stack,KN_<long> a ) const{ return nargs[i] ? GetAny<KN_<long> >( (*nargs[i])(stack) ): a;}
arg(int i,Stack stack,long a) const220   long  arg(int i,Stack stack, long  a ) const{ return nargs[i] ? GetAny<long>( (*nargs[i])(stack) ): a;}
arg(int i,Stack stack,bool a) const221   bool   arg(int i,Stack stack, bool   a ) const{ return nargs[i] ? GetAny<long>( (*nargs[i])(stack) ): a;}
222 
223 
224 public:
SetMesh_Op(const basicAC_F0 & args,Expression aa)225   SetMesh_Op(const basicAC_F0 &  args,Expression aa) : a(aa) {
226     args.SetNameParam(n_name_param,name_param,nargs);
227       if( nargs[0] && nargs[2] )
228 	  CompileError("uncompatible change (Th, label= , refe=  ");
229       if( nargs[1] && nargs[3] )
230 	  CompileError("uncompatible change (Th, region= , reft=  ");
231 
232   }
233 
234   AnyType operator()(Stack stack)  const ;
235 };
236 
237 basicAC_F0::name_and_type SetMesh_Op::name_param[]= {
238   {  "refe", &typeid(KN_<long> )},
239   {  "reft", &typeid(KN_<long> )},
240   {  "label", &typeid(KN_<long> )},
241   {  "region", &typeid(KN_<long> )},
242   {  "renumv",&typeid(KN_<long>)},
243   {  "renumt",&typeid(KN_<long>)},
244   {  "flabel", &typeid(long)},
245   {  "fregion", &typeid(long)},
246   {  "rmledges", &typeid(long)},
247   {  "rmInternalEdges", &typeid(bool)}
248 };
249 
ChangeLab(const map<int,int> & m,int lab)250 int  ChangeLab(const map<int,int> & m,int lab)
251 {
252   map<int,int>::const_iterator i=m.find(lab);
253   if(i != m.end())
254     lab=i->second;
255   return lab;
256 }
257 
operator ()(Stack stack) const258 AnyType SetMesh_Op::operator()(Stack stack)  const
259 {
260     MeshPoint *mp=MeshPointStack(stack),smp=*mp;
261   Mesh * pTh= GetAny<Mesh *>((*a)(stack));
262   Mesh & Th=*pTh;
263   Mesh *m= pTh;
264   int nbv=Th.nv; // nombre de sommet
265   int nbt=Th.nt; // nombre de triangles
266   int neb=Th.neb; // nombre d'aretes fontiere
267   KN<long> zz;
268   KN<long> nre (arg(0,stack,arg(2,stack,zz)));
269   KN<long> nrt (arg(1,stack,arg(3,stack,zz)));
270   KN<long> rv (arg(4,stack,zz));
271   KN<long> rt (arg(5,stack,zz));
272   Expression flab = nargs[6] ;
273   Expression freg = nargs[7] ;
274   bool  rm_edge = nargs[8];
275   long  rmlabedges (arg(8,stack,0L));
276   bool  rm_i_edges = (arg(9,stack,false));
277 
278   bool rV =  (rv.size()== nbv);
279   bool rT =  (rt.size()== nbt);
280     if(verbosity>1)
281 	cout << "  -- SetMesh_Op: nb vertices" << nbv<< " nb Trai "<< nbt << " nb b. edges  "
282 	     << neb << "renum V " << rV << " , renum T "<< rT << " rm internal edges " << rm_i_edges<< endl;
283 
284   if(nre.N() <=0 && nrt.N()<=0  && !rV && ! rT  && ! flab && ! freg && !rm_i_edges &&   !rm_edge ) return m;
285   ffassert( nre.N() %2 ==0);
286   ffassert( nrt.N() %2 ==0);
287   map<int,int> mape,mapt;
288   int z00 = false;
289   for(int i=0;i<nre.N();i+=2)
290     { z00 = z00 || ( nre[i]==0 && nre[i+1]==0);
291       if(nre[i] != nre[i+1])
292 	mape[nre[i]]=nre[i+1];
293     }
294   for(int i=0;i<nrt.N();i+=2)
295     mapt[nrt[i]]=nrt[i+1];
296   int nebn =0;
297     for(int i=0;i<neb;++i)
298       {
299 	int l0,l1=ChangeLab(mape,l0=m->bedges[i].lab) ;
300 	 nebn++;
301       }
302 
303   Vertex * v= new Vertex[nbv];
304   Triangle *t= new Triangle[nbt];
305   BoundaryEdge *b= new BoundaryEdge[nebn];
306   // generation des nouveaux sommets
307   Vertex *vv=v;
308   // copie des anciens sommets (remarque il n'y a pas operateur de copy des sommets)
309   for (int i=0;i<nbv;i++)
310     {
311       int ii=rV? rv(i): i;
312       vv = v + ii;
313      Vertex & V=Th(i);
314      vv->x=V.x;
315      vv->y=V.y;
316      vv->lab = V.lab;
317 
318    }
319 
320   //  generation des triangles
321   int nberr=0;
322   R2 PtHat(1./3.,1./3.);
323   for (int i=0;i<nbt;i++)
324     {
325       int ii= rT ? rt(i) : i;
326       int i0=Th(i,0), i1=Th(i,1),i2=Th(i,2);
327       if(rV) {
328 	  i0=rv(i0);
329 	  i1=rv(i1);
330 	  i2=rv(i2);
331       }
332       // les 3 triangles par triangles origines
333       t[ii].set(v,i0,i1,i2,ChangeLab(mapt,Th[i].lab));
334       if(freg)
335 	{
336 	  mp->set(Th,Th[i](PtHat),PtHat,Th[i],Th[i].lab);
337 	  t[ii].lab =GetAny<long>( (* freg)(stack)) ;
338 	}
339 
340     }
341   int  nrmedge=0;
342   // les arete frontieres qui n'ont pas change
343   BoundaryEdge * bb=b;
344   for (int i=0;i<neb;i++)
345     {
346       int ke,k =Th.BoundaryElement(i,ke);
347       int kke,kk= Th.ElementAdj(k,kke=ke);
348       int intern = ! (( kk == k )|| ( kk < 0)) ;
349       const   Triangle &K(Th[k]);
350       int i1=Th(Th.bedges[i][0]);
351       int i2=Th(Th.bedges[i][1]);
352 
353 	if(rV) {
354 	    i1=rv(i1);
355 	    i2=rv(i2);
356 	}
357 
358       int l0,l1=ChangeLab(mape,l0=m->bedges[i].lab) ;
359       mp->set(Th,Th[k](PtHat),PtHat,Th[k],l1);
360       if(flab)
361       {
362           R2 E=K.Edge(ke);
363           double le = sqrt((E,E));
364           double sa=0.5,sb=1-sa;
365           R2 PA(TriangleHat[VerticesOfTriangularEdge[ke][0]]),
366           PB(TriangleHat[VerticesOfTriangularEdge[ke][1]]);
367           R2 Pt(PA*sa+PB*sb );
368           MeshPointStack(stack)->set(Th,K(Pt),Pt,K,l1,R2(E.y,-E.x)/le,ke);
369 	  l1 =GetAny<long>( (*flab)(stack)) ;
370       }
371      if( !( intern && ( rm_i_edges || (rmlabedges && (l1 == rmlabedges)) )   ))
372       *bb++ = BoundaryEdge(v,i1,i2,l1);
373      else ++nrmedge;
374     }
375     nebn -= nrmedge;
376     if(nrmedge && verbosity > 2) cout << "   change  mesh2 : number of removed  internal edges " << nrmedge << endl;
377   assert(nebn==bb-b);
378   m =  new Mesh(nbv,nbt,nebn,v,t,b);
379 
380   R2 Pn,Px;
381   m->BoundingBox(Pn,Px);
382   m->quadtree=new Fem2D::FQuadTree(m,Pn,Px,m->nv);
383   Add2StackOfPtr2FreeRC(stack,m);
384     *mp=smp;
385   return m;
386 }
387 
388 class SetMesh : public OneOperator { public:
389 typedef Mesh const *pmesh;
SetMesh()390     SetMesh() : OneOperator(atype<pmesh>(),atype<pmesh>() ) {}
391 
code(const basicAC_F0 & args) const392   E_F0 * code(const basicAC_F0 & args) const
393   {
394     return  new SetMesh_Op(args,t[0]->CastTo(args[0]));
395   }
396 };
397 
GluMeshtab(KN<pmesh> * const & tab,long const & lab_delete,double eps=-1)398 Mesh* GluMeshtab (KN<pmesh> *const &tab, long const &lab_delete,double eps=-1) {
399   list<Mesh const *> l;
400   for (int i=0; i<tab->n; i++)
401     l.push_back((*tab)[i]);
402   return GluMesh(l,lab_delete,eps);
403 }
404 
405 struct Op_GluMeshtab: public OneOperator {
406     typedef const Mesh *pmesh;
407     class Op: public E_F0mps   {
408     public:
409         static basicAC_F0::name_and_type name_param [];
410         static const int n_name_param = 2;
411         Expression nargs[n_name_param];
412         Expression getmeshtab;
413          KN<Expression> te;
414         aType tgetmeshtab;
arg(int i,Stack stack,long a) const415         long arg (int i, Stack stack, long a) const {return nargs[i] ? GetAny<long>((*nargs[i])(stack)) : a;}
416 
Op(const basicAC_F0 & args,Expression t,aType tt)417         Op (const basicAC_F0 &args, Expression t, aType tt): getmeshtab(t),tgetmeshtab(tt),te(0)
418         {args.SetNameParam(n_name_param, name_param, nargs);
419             E_Array * at= dynamic_cast<E_Array*>(t);
420             if( at)
421             {
422                 te.resize(at->size());
423                 for(int i=0; i<at->size();++i)
424                     te[i]= CastTo<pmesh>((*at)[i]);
425                 if(te.N()==0) CompileError("EMPTY MESH ARRAY",tt);
426             }
427         }
428 
429         AnyType operator () (Stack s)  const;
430     };
431 
codeOp_GluMeshtab432     E_F0*code (const basicAC_F0 &args) const
433     {return new Op(args, t[0]->CastTo(args[0]),t[0]);}
434 
Op_GluMeshtabOp_GluMeshtab435     Op_GluMeshtab ():
436     OneOperator(atype<const pmesh>(), atype<KN<pmesh> *>()) {};
Op_GluMeshtabOp_GluMeshtab437     Op_GluMeshtab (int i):
438     OneOperator(atype<const pmesh>(), atype<listMesh>()) {};
Op_GluMeshtabOp_GluMeshtab439     Op_GluMeshtab (int i,int j):
440     OneOperator(atype<const pmesh>(), atype<E_Array>()) {};
441 
442 };
443 basicAC_F0::name_and_type Op_GluMeshtab::Op::name_param[Op_GluMeshtab::Op::n_name_param] =
444 {
445     {"labtodel", &typeid(long)},
446       {"eps", &typeid(double)}
447 };
operator ()(Stack stack) const448 AnyType Op_GluMeshtab::Op::operator () (Stack stack)  const {
449     KN<const Mesh *> *tab=0;
450     KN<const Mesh *> ttab(te.N());
451     list<Mesh const  *> *lth=0;
452     if (tgetmeshtab==(aType)atype<KN<pmesh> *>() )
453      tab= GetAny<KN<const Mesh *> *>((*getmeshtab)(stack));
454     else if (tgetmeshtab==(aType) atype<listMesh>())
455      lth =  GetAny<listMesh>((*getmeshtab)(stack)).lth;
456     else if (tgetmeshtab==(aType) atype<E_Array>())
457     {
458         for(int i=0;i<te.N();++i)
459            ttab[i] =  GetAny<pmesh>((*te[i])(stack));
460         tab = & ttab;
461     }
462     else
463         ffassert(0); // type inconnue
464     long labtodel = arg(0, stack, LONG_MIN);
465     double eps = arg(1, stack, -1.);
466     Mesh *Tht =0;
467     if(tab)
468      Tht = GluMeshtab(tab, labtodel,eps);
469     else
470      Tht=GluMesh(*lth,labtodel,eps);
471     ffassert(Tht);
472     Add2StackOfPtr2FreeRC(stack, Tht);
473     return Tht;
474 }
475 
476 //  truc pour que la fonction
477 // Init::Init() soit appele a moment du chargement dynamique
478 // du fichier
479 //
480 #ifndef  DYNAMICS_LIBS
init_glumesh2D()481 void init_glumesh2D()
482 {
483   Dcl_Type<listMesh>();
484   typedef Mesh const  *pmesh;
485 
486   if(verbosity>2)
487     cout << " glumesh2D " ;
488   TheOperators->Add("+",new OneBinaryOperator_st< Op2_addmesh<listMesh,pmesh,pmesh>  >      );
489   TheOperators->Add("+",new OneBinaryOperator_st< Op2_addmesh<listMesh,listMesh,pmesh>  >      );
490   TheOperators->Add("=",new OneBinaryOperator_st< Op2_setmesh<false,pmesh*,pmesh*,listMesh>  >     );
491   TheOperators->Add("<-",new OneBinaryOperator_st< Op2_setmesh<true,pmesh*,pmesh*,listMesh>  >     );
492 
493   Global.Add("change","(",new SetMesh);
494 
495   Global.Add("gluemesh", "(", new Op_GluMeshtab);
496   Global.Add("gluemesh", "(", new Op_GluMeshtab(1));
497   Global.Add("gluemesh", "(", new Op_GluMeshtab(1,1));
498 }
499 #else
500 class Init { public:
501   Init();
502 };
503 
504 static Init init;  //  une variable globale qui serat construite  au chargement dynamique
505 
Init()506 Init::Init(){  // le constructeur qui ajoute la fonction "splitmesh3"  a freefem++
507   Dcl_Type<listMesh>();
508   typedef Mesh *pmesh;
509 
510   if (verbosity)
511     cout << "  glumesh2D " ;
512   TheOperators->Add("+",new OneBinaryOperator_st< Op2_addmesh<listMesh,pmesh,pmesh>  >      );
513   TheOperators->Add("+",new OneBinaryOperator_st< Op2_addmesh<listMesh,listMesh,pmesh>  >      );
514   TheOperators->Add("=",new OneBinaryOperator_st< Op2_setmesh<false,pmesh*,pmesh*,listMesh>  >     );
515   TheOperators->Add("<-",new OneBinaryOperator_st< Op2_setmesh<true,pmesh*,pmesh*,listMesh>  >     );
516 
517   Global.Add("change","(",new SetMesh);
518 
519   Global.Add("gluemesh", "(", new Op_GluMeshtab);
520   Global.Add("gluemesh", "(", new Op_GluMeshtab(1));
521 }
522 #endif
523