2
/// This file is part of Rheolef.
4
/// Copyright (C) 2000-2009 Pierre Saramito <Pierre.Saramito@imag.fr>
6
/// Rheolef is free software; you can redistribute it and/or modify
7
/// it under the terms of the GNU General Public License as published by
8
/// the Free Software Foundation; either version 2 of the License, or
9
/// (at your option) any later version.
11
/// Rheolef is distributed in the hope that it will be useful,
12
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
/// GNU General Public License for more details.
16
/// You should have received a copy of the GNU General Public License
17
/// along with Rheolef; if not, write to the Free Software
18
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
/// =========================================================================
22
// geo-interface : provides normal, tangent to subdomains
25
// J.Etienne@damtp.cam.ac.uk
26
// contribution : splines by B. Balde
32
#include "geo-connectivity.h"
39
geo::normal (const class space& Nh, const domain& d, const std::string& region) const
42
return data().get_normal(Nh, d, false, bc);
45
geo::normal (const space& Nh, const domain& d, const interface& bc) const
47
return data().get_normal(Nh, d, false, bc);
50
geo::tangent (const space& Nh, const domain& d, const string& region) const
53
return tangent(Nh, d, bc);
56
geo::tangent (const space& Nh, const domain& d, const interface& bc) const
58
field n=data().get_normal(Nh, d, false, bc);
59
field t(n.get_space());
60
t[0]=n[1]; t[1]=-1.*n[0];
64
geo::axisymmetric_curvature (const space& Nh, const domain& d) const
67
return data().axi_curvature(Nh, d, bc);
70
geo::axisymmetric_curvature (const space& Nh, const domain& d,
71
const interface& bc) const
73
return data().axi_curvature(Nh, d, bc);
76
geo::plane_curvature (const space& Nh, const domain& d,
77
const interface& bc) const
79
return data().plane_curvature(Nh, d, bc);
82
geo::tangent_spline (const space& Nh, const domain& d,
83
const interface& bc) const
85
return data().tangent_spline(Nh, d, bc);
88
geo::plane_curvature_spline (const space& Nh, const domain& d,
89
const interface& bc) const
91
return data().plane_curvature_spline(Nh, d, bc);
94
geo::plane_curvature_quadratic (const space& Nh, const domain& d,
95
const interface& bc) const
97
return data().plane_curvature_quadratic(Nh, d, bc);
101
georep::set_interface_orientation(const domain& d, const interface& bc) const
103
// set of the vertices of domain d
104
map< size_type, size_type > domain_element;
105
domain::const_iterator iE=d.begin();
106
domain::const_iterator eE=d.end();
107
for (size_type i=0 ; iE!=eE; iE++, i++)
108
{ domain_element.insert(pair<size_type,size_type>((*iE).index(),i)); }
110
// find an element of the inside-region with a side on the interface
111
Vector<geo_element>::const_iterator iK, eK;
113
{ iK=begin(); eK=end(); }
115
{ iK=operator[](bc.region).begin(); eK=operator[](bc.region).end(); }
116
map<size_type,size_type>::const_iterator side;
117
map<size_type,size_type>::const_iterator not_found=domain_element.end();
119
for ( ; !found && iK != eK ; iK++ )
120
for (size_type i=0; i<(*iK).n_subgeo((*iK).dimension()-1); i++)
122
side=domain_element.find((*iK).side(i));
125
// Get the outward normal to element iK, whose side is on the interface
126
point n = normal ((*iK), i);
127
// remember that this element has this outward normal
128
bc.set_known_normal((*side).second,n);
132
check_macro(found, "Interface is not on the boundary of region " << bc.region);
135
// computes a P0 normal (no inverse connectivity reconstructed)
137
georep::get_normal_P0 (const space& Nh, const domain& d,
138
bool axisymmetric_curvature, const interface& bc) const
141
if (axisymmetric_curvature)
143
check_macro(Nh.coordinate_system()=="rz"||Nh.coordinate_system()=="zr",
144
"Non-axisymmetric geometry");
145
if (Nh.coordinate_system()=="rz") { er=point(1,0); ez=point(0,1); }
146
else { er=point(0,1); ez=point(1,0); }
148
// fill in with zeros in case only part of domain d is bounding region
149
field nh(Nh, Float(0));
151
// set of the vertices of domain d
152
map< size_type, size_type > domain_element;
153
domain::const_iterator iE=d.begin();
154
domain::const_iterator eE=d.end();
155
for (size_type i=0 ; iE!=eE; iE++, i++)
156
{ //cerr << (*iE).index() <<":"<<(*iE)[0]<<"-"<<(*iE)[1] << " ";
157
domain_element.insert(pair<size_type,size_type>((*iE).index(),i)); }
159
// go through all elements in region (or whole mesh) and build normal
160
Vector<geo_element>::const_iterator iK, eK;
162
{ iK=begin(); eK=end(); }
164
{ iK=operator[](bc.region).begin(); eK=operator[](bc.region).end(); }
165
tiny_vector<size_type> dofs;
166
map<size_type,size_type>::const_iterator side;
167
map<size_type,size_type>::const_iterator not_found=domain_element.end();
168
bool first_time=true;
169
for ( ; iK != eK ; iK++ )
170
for (size_type i=0; i<(*iK).n_subgeo((*iK).dimension()-1); i++)
172
side=domain_element.find((*iK).side(i));
175
// Get the outward normal to element iK, whose side is on the interface
176
// WARNING: straight sided elements assumed, and P0 normal ...!
177
point n = normal ((*iK), i);
179
{ // remember that this element has this outward normal for
180
// use in plane_curvature (gives order on interface)
181
//std::cerr << " $ elenorm: " << _x.begin()[(*iK)[i]] << " || "
182
// << _x.begin()[(*iK)[(i+1)%3]] << " || " << _x.begin()[(*iK)[(i+2)%3]]
184
bc.set_known_normal((*side).second,n);
187
if (axisymmetric_curvature)
189
// n.er gives the tan of angle of edge to horizontal,
190
// then curvature is calculated as the inverse of the distance
191
// form middle of edge to a point on the axis s.t....
192
point Me=0.5*(_x.begin()[(*iK)[i]]+_x.begin()[(*iK)[(i+1)%3]]);
193
n= -dot(n,er)/dot(Me,er) *n;
196
for (size_type id=0; id<Nh.n_component(); id++)
198
// get nh dofs corresponding
199
Nh.set_dof((Nh.get_geo().begin())[(*side).second],dofs,id);
201
for (size_type idof=0; idof<dofs.size(); idof++)
202
nh.at(dofs[idof])=n[id];
208
// computes a P1 or P2 normal after reordering the elements of the interface (required to be open
209
// because of the reordering)
211
georep::get_normal_P1P2 (const space& Nh, const domain& d, const interface& bc) const
213
string approx = Nh.get_approx();
214
// fill in with zeros in case only part of domain d is bounding region
215
field nh(Nh, Float(0));
216
const_iterator_node sommets = begin_node();
217
(*this).sort_interface(d, bc);
218
Vector<size_t>::const_iterator bI = bc.begin();
219
Vector<size_t>::const_iterator eI = bc.end();
220
//we take care of the first two edges
221
geo_element e0 = d.at(*bI++);
222
geo_element e1 = d.at(*bI++);
223
//the edges are sorted, but not necessarily the nodes
224
size_type OrderedLocalIndex0 [2];
225
size_type OrderedLocalIndex1 [2];
227
OrderedLocalIndex0[0] = 1;
228
OrderedLocalIndex0[1] = 0;
229
OrderedLocalIndex1[0] = 1;
230
OrderedLocalIndex1[1] = 0;
232
else if (e0[1]==e1[1]) {
233
OrderedLocalIndex0[0] = 0;
234
OrderedLocalIndex0[1] = 1;
235
OrderedLocalIndex1[0] = 1;
236
OrderedLocalIndex1[1] = 0;
238
else if (e0[1]==e1[0]) {
239
OrderedLocalIndex0[0] = 0;
240
OrderedLocalIndex0[1] = 1;
241
OrderedLocalIndex1[0] = 0;
242
OrderedLocalIndex1[1] = 1;
244
else /* e0[0]==e1[0] */ {
245
OrderedLocalIndex0[0] = 1;
246
OrderedLocalIndex0[1] = 0;
247
OrderedLocalIndex1[0] = 0;
248
OrderedLocalIndex1[1] = 1;
252
for (size_type i = 0 ; i < 2 ; i++) {
253
for (size_type j = 0 ; j < 2 ; j++) {
254
coord0[i][j] = sommets[e0[OrderedLocalIndex0[i]]][j];
255
coord1[i][j] = sommets[e1[OrderedLocalIndex1[i]]][j];
258
point n0(-(coord0[1][1]-coord0[0][1]), coord0[1][0]-coord0[0][0]);
259
point n1(-(coord1[1][1]-coord1[0][1]), coord1[1][0]-coord1[0][0]);
260
point n_avrg = n0 + n1;
261
n_avrg = n_avrg/norm(n_avrg);
262
Float edge0 = norm(n0);
263
Float edge1 = norm(n1);
264
tiny_vector<size_t> dof;
266
for (size_type id = 0 ; id < Nh.n_component(); id++){
267
Nh.set_global_dof(e0, dof, id);
268
d0 = dof[OrderedLocalIndex0[0]];
269
d1 = dof[OrderedLocalIndex0[1]];
270
if (bc.first_normal_imposed()||bc.first_tangent_imposed())
271
nh.at(Nh.domain_index(d0)) = (bc.first_normal())(id);
273
nh.at(Nh.domain_index(d0)) = n0(id)/edge0;
274
//warning_macro("first normal is not imposed. Use set_first_normal() if you want to impose it");
277
nh.at(Nh.domain_index(dof[2])) = n0(id)/edge0;
278
nh.at(Nh.domain_index(d1)) = n_avrg(id);
279
if (approx == "P2") {
280
Nh.set_global_dof(e1, dof, id);
281
nh.at(Nh.domain_index(dof[2])) = n1(id)/edge1;
285
size_type indexp = e1[OrderedLocalIndex1[1]];
286
for( ; bI != eI ; bI++) {
287
geo_element e = d.at(*bI);
288
if (indexp == e[0]) {
289
OrderedLocalIndex1[0] = 0;
290
OrderedLocalIndex1[1] = 1;
292
OrderedLocalIndex1[0] = 1;
293
OrderedLocalIndex1[1] = 0;
295
for (size_type i = 0 ; i < 2 ; i++) {
296
for (size_type j = 0 ; j < 2 ; j++) {
297
coord1[i][j] = sommets[e[OrderedLocalIndex1[i]]][j];
300
n1 = point(-(coord1[1][1]-coord1[0][1]), (coord1[1][0]-coord1[0][0]));
304
n_avrg = n_avrg/sqrt(dot(n_avrg,n_avrg));
305
for (size_type id = 0 ; id < Nh.n_component(); id++){
306
Nh.set_global_dof(e, dof, id);
307
d0 = dof[OrderedLocalIndex1[0]];
308
d1 = dof[OrderedLocalIndex1[1]];
309
nh.at(Nh.domain_index(d0)) = n_avrg(id);
311
nh.at(Nh.domain_index(dof[2])) = n1(id)/edge1;
313
indexp = e[OrderedLocalIndex1[1]];
316
geo_element e = d.at(*(--bI));
317
for (size_type id = 0 ; id < Nh.n_component(); id++){
318
Nh.set_global_dof(e, dof, id);
319
d1 = dof[OrderedLocalIndex1[1]];
320
if (bc.last_normal_imposed()||bc.last_tangent_imposed())
321
nh.at(Nh.domain_index(d1)) = (bc.last_normal())(id);
323
nh.at(Nh.domain_index(d1)) = n1(id)/edge1;
324
//warning_macro("last normal is not imposed. Use set_last_normal() if you want to impose it");
329
// computes a P0, P1, or P2 normal
331
georep::get_normal (const space& Nh, const domain& d,
332
bool axisymmetric_curvature, const interface& bc) const
334
string approx = Nh.get_approx();
335
check_macro((approx=="P0"||approx=="P1"||approx=="P2"),
336
approx + " normal not implemented.");
338
return get_normal_P0 (Nh, d, axisymmetric_curvature, bc);
340
check_macro(!axisymmetric_curvature, "axisymetric curvature not implemented for " + approx + " normals.");
341
return get_normal_P1P2 (Nh, d, bc);
344
point ortho2d(const point& AB)
346
return point(-AB[1],AB[0]);
349
point normal2d(const point& AB)
351
return point(-AB[1],AB[0])/norm(AB);
355
Float curvature2d(const point& AB, const point& BC)
356
// calculates the curvature at B using a quadratic approximation
357
// with sA=-|AB|, sB=0, sC=|BC|, we get
358
// x'y''-x''y' = -2 |AB x BC| / ( sA sC (sC-sA) )
359
// (which is indep of s), and
360
// (x'^2+y'^2)(s=0) = |AC|^2 /(sC-sA)^2
364
return -2*(sC-sA)*vect2d(AB,BC) / sA / sC / norm2(AB+BC);
367
point vcurvature2d(const point& AB, const point& BC)
368
// calculates the curvature at B using a quadratic approximation
370
Float sA2=norm2(AB); Float sA=-sqrt(sA2);
371
Float sC2=norm2(BC); Float sC=sqrt(sC2);
372
return 2*(sC-sA)*vect2d(AB,BC) / sA2 / sC2 / pow(norm2(AB+BC), Float(1.5))
373
*(sA2*ortho2d(BC)+sC2*ortho2d(AB));
376
point normal2d(const point& AB, const point& BC)
377
// calculates the normal at B using a quadratic approximation
379
Float sA2=norm2(AB); Float sA=-sqrt(sA2);
380
Float sC2=norm2(BC); Float sC=sqrt(sC2);
381
return -1 / sA / sC / norm(AB+BC) *(sA2*ortho2d(BC)+sC2*ortho2d(AB));
384
Float curvature2d_axi(const point& M, const point& AB, const point& er)
385
// n.er = |AB x er|/|AB| gives the tan of angle of edge to horizontal,
386
// then curvature is calculated as the inverse of the distance
387
// form middle of edge to a point on the axis s.t....
389
return -vect2d(AB,er)/dot(M,er)/norm(AB);
393
// calculates the inverse of the radius of a circle going through A, B and C
394
// curvature sign is determined independently
396
if (abs(vect2d(AB,BC))<sqrt(numeric_limits<Float>::epsilon()))
397
// points are aligned
400
if (vect2d(AB,BC)<0) sign=-1;
401
// let M be the middle of BC:
402
Float dist_OM=-.5*dot(AB+BC,AB)/dot(normal2d(BC),AB);
403
return sign/sqrt(sqr(dist_OM)+norm2(BC)/4.);
406
point vcurvature2d(const point& AB, const point& BC)
408
if (abs(vect2d(AB,BC))<sqrt(numeric_limits<Float>::epsilon()))
409
// points are aligned
411
Float signed_dist_OM=-.5*dot(AB+BC,AB)/dot(normal2d(BC),AB);
412
return .5*BC+signed_dist_OM*normal2d(BC);
417
georep::sort_interface (const domain& d, const interface& bc) const
419
if (bc.is_sorted()) return;
420
// Initialize interface boundary condition
421
if (!bc.initialized())
422
set_interface_orientation(d, bc);
423
// Sort contiguous elements of the interface
424
// first, group them in contiguous stubs listing element #s that are merged
425
// together as the jigsaw progresses...
426
typedef list< size_type > stub;
427
typedef list< stub > set_of_stubs;
429
set_of_stubs::iterator iS;
430
set_of_stubs::iterator eS;
431
set_of_stubs::iterator iS_attached;
432
// lists of the first and last element in stubs -- misleadingly of type 'stub' as
433
// well, these contain *vertex indices*, not *element* ones.
435
stub::iterator iF, iL, iF_attached, iL_attached;
436
domain::const_iterator bd=d.begin();
437
domain::const_iterator ed=d.end();
439
bool actual_order_is_set=false;
440
for (domain::const_iterator id=bd; id!=ed; id++, d_index++)
445
for (size_type i=0; i<2; i++) // examine both orders for attachment
446
for (iS=S.begin(), eS=S.end(),
449
!over && iS!=eS; iS++, iF++, iL++)
453
// first element of the stub has a common vertex with *id, then
454
// attach *id to front of stub *iS
456
// other end of id is still free
458
(*iS).push_front(d_index);
459
*iF=((*id)[(i+1)%2]);
468
// other end is already attached to a stub: merge them
470
if (i==0) // the other stub is in the other order
473
(*iS_attached).reverse();
475
else *iF=*iF_attached;
476
(*iS).splice((*iS).begin(),*iS_attached);
477
(*iS_attached).~stub();
478
F.erase(iF_attached);
479
L.erase(iL_attached);
480
S.erase(iS_attached);
484
// if (bd[*(*iS).rbegin()][1]==(*id)[i])
487
// last element of the stub has a common vertex with *id, then
488
// attach *id to back of stub *iS
491
(*iS).push_back(d_index);
492
*iL=((*id)[(i+1)%2]);
502
if (i==1) // the other stub is in the other order
505
(*iS_attached).reverse();
507
else *iL=*iL_attached;
508
(*iS_attached).splice((*iS_attached).begin(), *iS);
510
F.erase(iF_attached);
511
L.erase(iL_attached);
517
if (!attached) // we have to create a new stub for this element
519
stub* newstub =new stub;
520
(*newstub).push_front(d_index);
521
S.push_front(*newstub);
522
F.push_front((*id)[0]);
523
L.push_front((*id)[1]);
526
if (d_index==bc.element_of_known_normal)
528
check_macro(attached_dir!=-1,"Attached direction not set !" << S.size());
529
bc.set_actual_order( ((attached_dir==0)?1:-1)
530
*(_x.begin()[(*id)[1]] - _x.begin()[(*id)[0]]));
531
// cerr << "$$ Actual order : " << ((attached_dir==0)?1:-1)*(_x.begin()[(*id)[1]] - _x.begin()[(*id)[0]]) << "( dir " << ((attached_dir==0)?1:-1) << " )"<< endl;
532
actual_order_is_set=true;
535
check_macro (actual_order_is_set, "Element whose normal is marked "
536
<< bc.element_of_known_normal << " not found!");
537
check_macro (S.size()==1, "The interface has to be a connected set!");
538
check_macro ((*F.begin())!=(*L.begin()), "Closed interfaces not supported yet!");
539
check_macro ((*S.begin()).size()==d.size(), "Not all elements found?");
540
if (bc.is_reversed())
541
bc.set_sorted( (*S.begin()).size(), (*S.begin()).rbegin(), (*S.begin()).rend());
543
bc.set_sorted( (*S.begin()).size(), (*S.begin()).begin(), (*S.begin()).end());
545
// get global dof number for first and last dof
546
Vector<size_t>::const_iterator iAB=bc.begin();
547
Vector<size_t>::const_iterator iBC=bc.begin(); iBC++;
548
size_t AB0=bd[*iAB][0];
549
size_t AB1=bd[*iAB][1];
550
size_t BC0=bd[*iBC][0];
551
size_t BC1=bd[*iBC][1];
552
// check that nodes are in the same order as elements, otherwise reverse
553
if (AB1==BC0||AB1==BC1) { bc.set_first_node(*iAB, 0); }
555
if (AB0==BC0||AB0==BC1) { bc.set_first_node(*iAB, 1); }
556
else error_macro("Fatal: non consecutive edges!");
564
// check that nodes are in the same order as elements, otherwise reverse
565
if (AB1==BC0||AB1==BC1) { bc.set_last_node(*iAB,0); }
567
if (AB0==BC0||AB0==BC1) { bc.set_last_node(*iAB,1); }
568
else error_macro("Fatal: non consecutive edges!");
571
georep::plane_curvature (const space& Nh, const domain& d,
572
const interface& bc) const
574
return plane_curvature_spline (Nh, d, bc);
578
georep::tangent_spline (const space& Nh, const domain& d,
579
const interface& bc) const
581
check_macro(Nh.get_geo() .dimension()==2,"plane curvature is for 2D geometries only");
582
check_macro(Nh.n_component ()==2,"2-component vector space needed");
583
// Sort contiguous elements of the interface
584
// first ,group them in contiguous stubs listing element #s that are merged
585
// together as the jidsaw progresses....
586
sort_interface(d,bc);
587
// get coodinate of lagrange interpolation points on edge elements :
588
vector<point> hat_node;
589
domain::const_iterator bd=d.begin () ;
590
Nh.get_basis().hat_node(*bd,hat_node) ;
592
Vector<size_t>::const_iterator iAB=bc.begin() ;
593
Vector<size_t>::const_iterator iBC=bc.begin() ; iBC++;
594
Vector<size_t>::const_iterator the_end=bc.end() ;
596
// calculate interface curvature using a parametric spline
598
field kh(Nh,float(0));
599
tiny_vector<size_type> dofs;
601
point AB0=_x.begin()[bd[*iAB][0]];
602
point AB1=_x.begin()[bd[*iAB][1]];
603
point BC0=_x.begin()[bd[*iBC][0]];
604
point BC1=_x.begin()[bd[*iBC][1]];
609
compute the hi and the bi */
610
size_type n=d.size();
611
vector<Float> u(n+1),h(n);
612
vector<point> v(n+1),b(n+1),z(n+1) ,y(n+1),w(n+1);
614
for (i=0 ; iBC!=the_end; iAB++,iBC++,i++)
616
// check that nodes are in the same order as elements ,otherwise reverse
617
BC0=_x.begin()[bd[*iBC][0]];
618
BC1=_x.begin()[bd[*iBC][1]];
619
if(AB1==BC0) { rev_AB=false; AB=AB1-AB0 ; BC=BC1-BC0; }
621
if(AB0==BC0) { rev_AB=true; AB=AB0-AB1; BC=BC1-BC0 ; }
623
if(AB1==BC1) { rev_AB=false;AB=AB1-AB0; BC=BC0-BC1 ; }
626
check_macro (AB0==BC1, "Fatal :non consecutive edges!");
627
rev_AB=true; AB=AB0-AB1; BC=BC0-BC1;
631
AB0=BC0; AB1=BC1 ;AB=BC;
635
h[n-1]=norm(BC); b[n-1]=1./h[n-1]*BC;
636
// GAUSSIAN ELIMINATION
638
size_type start_loop=1;
641
if (bc.first_tangent_imposed())
643
t0=bc.first_tangent();
646
u[1]=2*(h[0]+h[1])-sqr(h[0])/u[0];
647
v[1]=6*(b[1]-b[0])- (h[0]/u[0])*v[0];
656
for (i=2; i<=(n-1); i++)
658
u[i]=2.*(h[i-1]+h[i])-sqr(h[i-1])/u[i-1];
659
v[i]=6.*(b[i]-b[i-1])-h[i-1]/u[i-1]*v[i-1];
661
if (bc.last_tangent_imposed())
663
tn=bc.last_tangent();
665
u[n]=2*h[n-1]-sqr(h[n-1])/u[n-1] ;
666
v[n]= 6*(tn-b[n-1])-h[n-1]/u[n-1]*v[n-1];
671
u[n]=2*h[n-1]-sqr(h[n-1])/u[n-1] ;
672
v[n]= 6*(tn-b[n-1])-h[n-1]/u[n-1]*v[n-1];
677
if (!bc.last_tangent_imposed()) {z[n]=point(0,0);}
678
else z[n]=1./u[n]*v[n];
679
for (int j=n-1; j>=int(start_loop); j--)
681
z[j]=1./u[j]*( v[j] -h[j]*z[j+1] );
683
w[j]=-h[j]/6 *(z[j+1]-z[j]) +b[j];
686
if (!bc.first_tangent_imposed()){z[0]=point(0,0);w[0]=-h[0]/6 *(z[1]-z[0]) +b[0];}
688
// curvature calculation
690
iBC=bc.begin() ; iBC++;
691
AB0=_x.begin()[bd[*iAB][0]];
692
AB1=_x.begin()[bd[*iAB][1]];
695
for (i=0 ; iBC!=the_end; iAB++,iBC++,i++)
697
BC0=_x.begin()[bd[*iBC][0]];
698
BC1=_x.begin()[bd[*iBC][1]];
699
// check that nodes are in the same order as elements ,otherwise reverse
701
if(AB1==BC0) { rev_AB=false; AB=AB1-AB0 ; BC=BC1-BC0; }
703
if(AB0==BC0) { rev_AB=true; AB=AB0-AB1; BC=BC1-BC0 ; }
705
if(AB1==BC1) { rev_AB=false;AB=AB1-AB0; BC=BC0-BC1 ; }
708
check_macro (AB0==BC1, "Fatal :non consecutive edges!");
709
rev_AB=true; AB=AB0-AB1; BC=BC0-BC1;
711
for (size_type j=0;j<Nh.n_component();j++)
713
// get nh dofs corresponding
715
Nh.set_dof((Nh.get_geo().begin())[*iAB],dofs,j);
718
for (size_type idof=0;idof<dofs.size();idof++)
722
tang=-sqr(1-hat_node[idof][0])*z[i]/2*h[i]
723
+sqr(hat_node[idof][0])*z[i+1]/2*h[i]
728
//cerr << (1-hat_node[idof][0]) << "*" << z[i][j]
729
// << " + " << hat_node[idof][0] << "*" << z[i+1][j] << endl;
730
tang=sqr(1-hat_node[idof][0])* z[i+1]/2*h[i]
731
-sqr(hat_node[idof][0])*z[i]/2*h[i]
734
kh.at(dofs[idof])= tang[j];
738
AB0=BC0; AB1=BC1 ;AB=BC;
740
// don't need to check that nodes are in the same order as elements,as BC was
742
rev_AB=(AB==AB0 -AB1);
744
for (size_type j=0;j<Nh.n_component();j++)
746
// get nh dofs corresponding
748
Nh.set_dof((Nh.get_geo().begin())[*iAB],dofs,j);
751
for (size_type idof=0;idof<dofs.size();idof++)
756
tang=-sqr(1-hat_node[idof][0])*z[i]/2*h[i]
757
+sqr(hat_node[idof][0])* z[i+1]/2*h[i]
762
//cerr << (1-hat_node[idof][0]) << "*" << z[i][j]
763
// << " + " << hat_node[idof][0] << "*" << z[i+1][j] << endl;
764
tang=sqr(1-hat_node[idof][0])*z[i+1]/2*h[i]
765
-sqr(hat_node[idof][0])*z[i]/2*h[i]
768
kh.at(dofs[idof])= tang[j];
776
georep::plane_curvature_spline (const space& Nh, const domain& d,
777
const interface& bc) const
779
check_macro(Nh.get_geo() .dimension()==2,"plane curvature is for 2D geometries only");
780
check_macro(Nh.n_component ()==2,"2-component vector space needed");
781
// Sort contiguous elements of the interface
782
// first ,group them in contiguous stubs listing element #s that are merged
783
// together as the jidsaw progresses....
784
sort_interface(d,bc);
785
// get coodinate of lagrange interpolation points on edge elements :
786
vector<point> hat_node;
787
domain::const_iterator bd=d.begin () ;
788
Nh.get_basis().hat_node(*bd,hat_node) ;
790
Vector<size_t>::const_iterator iAB=bc.begin() ;
791
Vector<size_t>::const_iterator iBC=bc.begin() ; iBC++;
792
Vector<size_t>::const_iterator the_end=bc.end() ;
794
// calculate interface curvature using a parametric spline
796
field kh(Nh,float(0));
797
tiny_vector<size_type> dofs;
799
point AB0=_x.begin()[bd[*iAB][0]];
800
point AB1=_x.begin()[bd[*iAB][1]];
801
point BC0=_x.begin()[bd[*iBC][0]];
802
point BC1=_x.begin()[bd[*iBC][1]];
807
compute the hi and the bi */
808
size_type n=d.size();
809
vector<Float> u(n+1),h(n);
810
vector<point> v(n+1),b(n+1),z(n+1) ,y(n+1),w(n+1);
812
for (i=0 ; iBC!=the_end; iAB++,iBC++,i++)
814
// check that nodes are in the same order as elements ,otherwise reverse
815
BC0=_x.begin()[bd[*iBC][0]];
816
BC1=_x.begin()[bd[*iBC][1]];
817
if(AB1==BC0) { rev_AB=false; AB=AB1-AB0 ; BC=BC1-BC0; }
819
if(AB0==BC0) { rev_AB=true; AB=AB0-AB1; BC=BC1-BC0 ; }
821
if(AB1==BC1) { rev_AB=false;AB=AB1-AB0; BC=BC0-BC1 ; }
824
check_macro (AB0==BC1, "Fatal :non consecutive edges!");
825
rev_AB=true; AB=AB0-AB1; BC=BC0-BC1;
829
AB0=BC0; AB1=BC1 ;AB=BC;
833
h[n-1]=norm(BC); b[n-1]=1./h[n-1]*BC;
834
// GAUSSIAN ELIMINATION
836
size_type start_loop=1;
839
if (bc.first_tangent_imposed())
841
t0=bc.first_tangent();
844
u[1]=2*(h[0]+h[1])-sqr(h[0])/u[0];
845
v[1]=6*(b[1]-b[0])- (h[0]/u[0])*v[0];
854
for (i=2; i<=(n-1); i++)
856
u[i]=2.*(h[i-1]+h[i])-sqr(h[i-1])/u[i-1];
857
v[i]=6.*(b[i]-b[i-1])-h[i-1]/u[i-1]*v[i-1];
859
if (bc.last_tangent_imposed())
861
tn=bc.last_tangent();
863
u[n]=2*h[n-1]-sqr(h[n-1])/u[n-1] ;
864
v[n]= 6*(tn-b[n-1])-h[n-1]/u[n-1]*v[n-1];
869
u[n]=2*h[n-1]-sqr(h[n-1])/u[n-1] ;
870
v[n]= 6*(tn-b[n-1])-h[n-1]/u[n-1]*v[n-1];
875
if (!bc.last_tangent_imposed()) {z[n]=point(0,0);}
876
else z[n]=1./u[n]*v[n];
877
for (int j=n-1; j>=int(start_loop); j--)
879
z[j]=1./u[j]*( v[j] -h[j]*z[j+1] );
881
w[j]=-h[j]/6 *(z[j+1]-z[j]) +b[j];
884
if (!bc.first_tangent_imposed()){z[0]=point(0,0);w[0]=-h[0]/6 *(z[1]-z[0]) +b[0];}
886
// curvature calculation
888
iBC=bc.begin() ; iBC++;
889
AB0=_x.begin()[bd[*iAB][0]];
890
AB1=_x.begin()[bd[*iAB][1]];
892
point z_at_dof, devy_at_dof, n1;
893
for (i=0 ; iBC!=the_end; iAB++,iBC++,i++)
895
BC0=_x.begin()[bd[*iBC][0]];
896
BC1=_x.begin()[bd[*iBC][1]];
897
// check that nodes are in the same order as elements ,otherwise reverse
899
if(AB1==BC0) { rev_AB=false; AB=AB1-AB0 ; BC=BC1-BC0; }
901
if(AB0==BC0) { rev_AB=true; AB=AB0-AB1; BC=BC1-BC0 ; }
903
if(AB1==BC1) { rev_AB=false;AB=AB1-AB0; BC=BC0-BC1 ; }
906
check_macro (AB0==BC1, "Fatal :non consecutive edges!");
907
rev_AB=true; AB=AB0-AB1; BC=BC0-BC1;
909
for (size_type j=0;j<Nh.n_component();j++)
911
// get nh dofs corresponding
913
Nh.set_dof((Nh.get_geo().begin())[*iAB],dofs,j);
916
for (size_type idof=0;idof<dofs.size();idof++)
920
z_at_dof= (1-hat_node[idof][0])* z[i] + hat_node[idof][0]*z[i+1] ;
921
devy_at_dof=-sqr(1-hat_node[idof][0])*z[i]/2*h[i]
922
+sqr(hat_node[idof][0])*z[i+1]/2*h[i]
924
n1=point(devy_at_dof[1],-devy_at_dof[0]);
928
//cerr << (1-hat_node[idof][0]) << "*" << z[i][j]
929
// << " + " << hat_node[idof][0] << "*" << z[i+1][j] << endl;
930
z_at_dof=(1-hat_node[idof][0])* z[i+1] + hat_node[idof][0] *z[i];
931
devy_at_dof=sqr(1-hat_node[idof][0])* z[i+1]/2*h[i]
932
-sqr(hat_node[idof][0])*z[i]/2*h[i]
934
n1=point(devy_at_dof[1],-devy_at_dof[0]);
936
kh.at(dofs[idof])= -1./(sqr(sqr(devy_at_dof[0])+sqr(devy_at_dof[1])))
937
*(z_at_dof[1]*devy_at_dof[0]-z_at_dof[0]*devy_at_dof[1])
942
AB0=BC0; AB1=BC1 ;AB=BC;
944
// don't need to check that nodes are in the same order as elements,as BC was
946
rev_AB=(AB==AB0 -AB1);
948
for (size_type j=0;j<Nh.n_component();j++)
950
// get nh dofs corresponding
952
Nh.set_dof((Nh.get_geo().begin())[*iAB],dofs,j);
955
for (size_type idof=0;idof<dofs.size();idof++)
960
z_at_dof= (1-hat_node[idof][0])* z[i] + hat_node[idof][0] *z[i+1];
961
devy_at_dof=-sqr(1-hat_node[idof][0])*z[i]/2*h[i]
962
+sqr(hat_node[idof][0])* z[i+1]/2*h[i]
964
n1=point(devy_at_dof[1],-devy_at_dof[0]);
968
//cerr << (1-hat_node[idof][0]) << "*" << z[i][j]
969
// << " + " << hat_node[idof][0] << "*" << z[i+1][j] << endl;
970
z_at_dof=(1-hat_node[idof][0])* z[i+1] + hat_node[idof][0] *z[i];
971
devy_at_dof=sqr(1-hat_node[idof][0])*z[i+1]/2*h[i]
972
-sqr(hat_node[idof][0])*z[i]/2*h[i]
974
n1=point(devy_at_dof[1],-devy_at_dof[0]);
976
kh.at(dofs[idof])= -1./(sqr(sqr(devy_at_dof[0])+sqr(devy_at_dof[1])))
977
*(z_at_dof[1]*devy_at_dof[0]-z_at_dof[0]*devy_at_dof[1])
986
georep::plane_curvature_quadratic (const space& Nh, const domain& d,
987
const interface& bc) const
989
check_macro(Nh.get_geo().dimension()==2,"Plane curvature is for 2D geometries only");
990
check_macro(Nh.n_component()==2,"2-component vector space needed");
991
// Sort contiguous elements of the interface
992
// first, group them in contiguous stubs listing element #s that are merged
993
// together as the jigsaw progresses...
994
sort_interface(d,bc);
996
// get coordinates of Lagrange interpolation points on edge elements:
997
vector<point> hat_node;
998
domain::const_iterator bd=d.begin();
999
Nh.get_basis().hat_node(*bd, hat_node);
1001
Vector<size_t>::const_iterator iAB=bc.begin();
1002
Vector<size_t>::const_iterator iBC=bc.begin(); iBC++;
1003
Vector<size_t>::const_iterator the_end=bc.end();
1004
// Calculate interface curvature using the mean of the curvature of
1005
// circles passing through points e--,e-,e+ (curv1) and e-,e+,e++ (curv2)
1006
field kh(Nh, Float(0));
1007
tiny_vector<size_type> dofs;
1008
point vcurv1, vcurv2;
1009
point AB0=_x.begin()[bd[*iAB][0]];
1010
point AB1=_x.begin()[bd[*iAB][1]];
1011
point BC0=_x.begin()[bd[*iBC][0]];
1012
point BC1=_x.begin()[bd[*iBC][1]];
1015
// check that nodes are in the same order as elements, otherwise reverse
1016
if (AB1==BC0) { rev_AB=false; AB=AB1-AB0; BC=BC1-BC0; }
1018
if (AB0==BC0) { rev_AB=true; AB=AB0-AB1; BC=BC1-BC0; }
1020
if (AB1==BC1) { rev_AB=false; AB=AB1-AB0; BC=BC0-BC1; }
1023
check_macro(AB0==BC1, "Fatal: non consecutive edges!");
1024
rev_AB=true; AB=AB0-AB1; BC=BC0-BC1;
1026
if (bc.first_tangent_imposed())
1028
vcurv1=vcurvature2d(AB-2*dot(AB,bc.first_normal())*bc.first_normal(), AB);
1031
vcurv1=vcurvature2d(AB,BC);
1032
for ( ; iBC!=the_end; iAB++, iBC++)
1034
BC0=_x.begin()[bd[*iBC][0]];
1035
BC1=_x.begin()[bd[*iBC][1]];
1036
// check that nodes are in the same order as elements, otherwise reverse
1037
if (AB1==BC0) { rev_AB=false; AB=AB1-AB0; BC=BC1-BC0; }
1039
if (AB0==BC0) { rev_AB=true; AB=AB0-AB1; BC=BC1-BC0; }
1041
if (AB1==BC1) { rev_AB=false; AB=AB1-AB0; BC=BC0-BC1; }
1044
check_macro(AB0==BC1, "Fatal: non consecutive edges!");
1045
rev_AB=true; AB=AB0-AB1; BC=BC0-BC1;
1047
vcurv2=vcurvature2d(AB,BC);
1049
check_macro(abs(norm(vcurv2)-abs(curvature2d(AB,BC)))<1e-12,
1050
"curvature error " << AB << " U " << BC << " " << norm(vcurv2)
1051
<< "-" << curvature2d(AB,BC) << "=" << norm(vcurv2)-abs(curvature2d(AB,BC)));
1053
for (size_type i=0; i<Nh.n_component(); i++)
1055
// get nh dofs corresponding
1056
Nh.set_dof((Nh.get_geo().begin())[*iAB],dofs,i);
1058
for (size_type idof=0; idof<dofs.size(); idof++)
1060
kh.at(dofs[idof])=(1-hat_node[idof][0])*vcurv1[i] + hat_node[idof][0]*vcurv2[i];
1062
kh.at(dofs[idof])=(1-hat_node[idof][0])*vcurv2[i] + hat_node[idof][0]*vcurv1[i];
1065
AB0=BC0; AB1=BC1; AB=BC;
1067
// don't need to check that nodes are in the same order as elements, as BC was
1068
rev_AB=(AB==AB0-AB1);
1069
if (bc.last_tangent_imposed())
1071
vcurv2=vcurvature2d(AB, AB-2*dot(AB,bc.last_normal())*bc.last_normal());
1074
for (size_type i=0; i<Nh.n_component(); i++)
1076
// get nh dofs corresponding
1077
Nh.set_dof((Nh.get_geo().begin())[*iAB],dofs,i);
1079
for (size_type idof=0; idof<dofs.size(); idof++)
1081
kh.at(dofs[idof])=(1-hat_node[idof][0])*vcurv1[i] + hat_node[idof][0]*vcurv2[i];
1083
kh.at(dofs[idof])=(1-hat_node[idof][0])*vcurv2[i] + hat_node[idof][0]*vcurv1[i];
1090
georep::axi_curvature (const space& Nh, const domain& d,
1091
const interface& bc) const
1093
check_macro(Nh.coordinate_system()=="rz"||Nh.coordinate_system()=="zr",
1094
"Axisymmetric curvature is for 2D-axisymmetric geometries only");
1095
check_macro(Nh.n_component()==2,"2-component vector space needed");
1096
// Sort contiguous elements of the interface
1097
// first, group them in contiguous stubs listing element #s that are merged
1098
// together as the jigsaw progresses...
1099
sort_interface(d,bc);
1102
if (Nh.coordinate_system()=="rz") { er=point(1,0); }
1103
else { er=point(0,1); }
1104
// fill in with zeros in case only part of domain d is bounding region
1105
field nh(Nh, Float(0));
1107
// get coordinates of Lagrange interpolation points on edge elements:
1108
vector<point> hat_node;
1109
domain::const_iterator bd=d.begin();
1110
Nh.get_basis().hat_node(*bd, hat_node);
1112
Vector<size_t>::const_iterator iAB=bc.begin();
1113
Vector<size_t>::const_iterator iBC=bc.begin(); iBC++;
1114
Vector<size_t>::const_iterator the_end=bc.end();
1115
field kh(Nh, Float(0));
1116
tiny_vector<size_type> dofs;
1117
Float curv0, curv1, curv2;
1119
point AB0=_x.begin()[bd[*iAB][0]];
1120
point AB1=_x.begin()[bd[*iAB][1]];
1121
point BC0=_x.begin()[bd[*iBC][0]];
1122
point BC1=_x.begin()[bd[*iBC][1]];
1125
// check that nodes are in the same order as elements, otherwise reverse
1126
if (AB1==BC0) { rev_AB=false; AB=AB1-AB0; BC=BC1-BC0; }
1128
if (AB0==BC0) { rev_AB=true; AB=AB0-AB1; BC=BC1-BC0; }
1130
if (AB1==BC1) { rev_AB=false; AB=AB1-AB0; BC=BC0-BC1; }
1133
check_macro(AB0==BC1, "Fatal: non consecutive edges!");
1134
rev_AB=true; AB=AB0-AB1; BC=BC0-BC1;
1136
curv0=curv1=curvature2d_axi((AB0+AB1)/2, AB, er);
1137
if (bc.first_tangent_imposed())
1138
nA=normal2d(AB-2*dot(AB,bc.first_normal())*bc.first_normal(), AB);
1141
for ( ; iBC!=the_end; iAB++, iBC++)
1143
BC0=_x.begin()[bd[*iBC][0]];
1144
BC1=_x.begin()[bd[*iBC][1]];
1145
// check that nodes are in the same order as elements, otherwise reverse
1146
if (AB1==BC0) { rev_AB=false; AB=AB1-AB0; BC=BC1-BC0; }
1148
if (AB0==BC0) { rev_AB=true; AB=AB0-AB1; BC=BC1-BC0; }
1150
if (AB1==BC1) { rev_AB=false; AB=AB1-AB0; BC=BC0-BC1; }
1153
check_macro(AB0==BC1, "Fatal: non consecutive edges!");
1154
rev_AB=true; AB=AB0-AB1; BC=BC0-BC1;
1156
nB=normal2d(AB, BC);
1157
curv2=curvature2d_axi((BC0+BC1)/2, BC, er);
1158
for (size_type i=0; i<Nh.n_component(); i++)
1160
// get nh dofs corresponding
1161
Nh.set_dof((Nh.get_geo().begin())[*iAB],dofs,i);
1163
for (size_type idof=0; idof<dofs.size(); idof++)
1165
kh.at(dofs[idof])=.5*(1-hat_node[idof][0])*(curv0+curv1)*nA[i]
1166
+ .5*hat_node[idof][0]*(curv1+curv2)*nB[i];
1168
kh.at(dofs[idof])=.5*hat_node[idof][0]*(curv0+curv1)*nA[i]
1169
+ .5*(1-hat_node[idof][0])*(curv1+curv2)*nB[i];
1173
AB0=BC0; AB1=BC1; AB=BC;
1176
// don't need to check that nodes are in the same order as elements, as BC was
1177
rev_AB=(AB==AB0-AB1);
1179
if (bc.last_tangent_imposed())
1180
nB=normal2d(AB, AB-2*dot(AB,bc.last_normal())*bc.last_normal());
1183
for (size_type i=0; i<Nh.n_component(); i++)
1185
// get nh dofs corresponding
1186
Nh.set_dof((Nh.get_geo().begin())[*iAB],dofs,i);
1188
for (size_type idof=0; idof<dofs.size(); idof++)
1190
kh.at(dofs[idof])=.5*(1-hat_node[idof][0])*(curv0+curv1)*nA[i]
1191
+ .5*hat_node[idof][0]*(curv1+curv2)*nB[i];
1193
kh.at(dofs[idof])=.5*hat_node[idof][0]*(curv0+curv1)*nA[i]
1194
+ .5*(1-hat_node[idof][0])*(curv1+curv2)*nB[i];
1200
geo::interface_process (const domain& d, const interface& bc,
1201
geometric_event& event) const
1203
if (!bc.initialized())
1205
space Nh(*this, d, "P0");
1206
data().get_normal(Nh, d, false, bc);
1208
data().interface_process(d, bc, event);
1211
georep::interface_process (const domain& d, const interface& bc,
1212
geometric_event& event) const
1214
sort_interface(d, bc);
1215
vector<point> hat_node;
1216
domain::const_iterator bd=d.begin();
1218
Vector<size_t>::const_iterator iAB=bc.begin();
1219
Vector<size_t>::const_iterator iBC=bc.begin(); iBC++;
1220
Vector<size_t>::const_iterator the_end=bc.end();
1222
point AB0=_x.begin()[bd[*iAB][0]];
1223
point AB1=_x.begin()[bd[*iAB][1]];
1224
point BC0=_x.begin()[bd[*iBC][0]];
1225
point BC1=_x.begin()[bd[*iBC][1]];
1227
cerr << "!\tA=" << AB0;
1228
for ( ; iBC!=the_end; iAB++, iBC++)
1230
BC0=_x.begin()[bd[*iBC][0]];
1231
BC1=_x.begin()[bd[*iBC][1]];
1232
// check that nodes are in the same order as elements, otherwise reverse
1233
if (AB1==BC0) { A=AB0; B=AB1; }
1235
if (AB0==BC0) { A=AB1; B=AB0; }
1237
if (AB1==BC1) { A=AB0; B=AB1; }
1240
check_macro(AB0==BC1, "Fatal: non consecutive edges!");
1244
AB0=BC0; AB1=BC1; A=B;
1246
cerr << " B=" << BC1 << endl;
1248
if (BC0==B) event(A,BC1); else event(A,BC0);