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