-
Notifications
You must be signed in to change notification settings - Fork 0
/
two_d_nst_with_face_element.cc
1228 lines (947 loc) · 39.4 KB
/
two_d_nst_with_face_element.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//LIC// ====================================================================
//LIC// This file forms part of oomph-lib, the object-oriented,
//LIC// multi-physics finite-element library, available
//LIC// at http://www.oomph-lib.org.
//LIC//
//LIC// Version 1.0; svn revision $LastChangedRevision: 1097 $
//LIC//
//LIC// $LastChangedDate: 2015-12-17 11:53:17 +0000 (Thu, 17 Dec 2015) $
//LIC//
//LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
//LIC//
//LIC// This library is free software; you can redistribute it and/or
//LIC// modify it under the terms of the GNU Lesser General Public
//LIC// License as published by the Free Software Foundation; either
//LIC// version 2.1 of the License, or (at your option) any later version.
//LIC//
//LIC// This library is distributed in the hope that it will be useful,
//LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
//LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//LIC// Lesser General Public License for more details.
//LIC//
//LIC// You should have received a copy of the GNU Lesser General Public
//LIC// License along with this library; if not, write to the Free Software
//LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
//LIC// 02110-1301 USA.
//LIC//
//LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
//LIC//
//LIC//====================================================================
//Driver for Navier Stokes in backward step domain -- meshed with triangle
//Generic includes
#include "generic.h"
#include "navier_stokes.h"
// The mesh
#include "meshes/triangle_mesh.h"
// Dev header
#include "new_nst_sing_face_element.h"
#include "fluid_traction_elements.h"
using namespace std;
using namespace oomph;
// Hierher we introduce u
//==start_of_namespace==============================
/// Namespace for physical parameters
//==================================================
namespace Global_Physical_Variables
{
// Dimensionless domain values
// ---------------------------
/// Dimless width of inflow channel
double H_up = 1.0;
/// Dimless length of channel upstream of step
double L_up = 2.0;
/// \short Dimless length of channel downstream of step
double L_down = 2.0;
/// Dimless width of outflow channel
double H_down = 2.0;
/// Quadratic nromalized inflow profile: x-velocity as a fct of y coordinate
double quadratic_flow(const double& y)
{
// Bottom of inflow is at y=0; top is at H_up
return 4.0*y*(H_up - y);
}
/// Radius of internal boundary (surrounding the singularity)
double Radius_of_internal_boundary = 0.5;
// Bit of a hack but it facilitates reuse...
#include "unstructured_backward_step_mesh.h"
double u_additional(const Vector<double>& x);
/// \short "Singular" function (in cartesian)
/// and gradient (in polar coordinates, bc it's easier for the stress tensor
/// computation)
void singular_fct_and_gradient(const Vector<double>& x,
Vector<double>& u,
Vector<Vector<double> >& du_dpolar)
{
// Definition of the constants
const double K = 1.0;
const long double firstLambda = 1.5444837367824622;
const double alpha = 3.0 * MathematicalConstants::Pi / 4.0;
// The dynamic viscosity (water's one i.e. 1e-3)
const double mu = 1;
// Radius & polar angle (hireher be careful, the L_up term is designed to
// recentered the singularity on the corner)
double y = x[1];
double r = sqrt((x[0]-L_up)*(x[0]-L_up) + y*y);
double phi = atan2(y, x[0] - L_up);
// Define another phi, to rotate the corner and get it the right position
double phi2 = phi - MathematicalConstants::Pi / 4.0;
// // Stream function computation
// // Hierher enable this line if you want to get access to it
// double radius_part = K*pow(r, firstLambda);
double first_cos = std::cos(firstLambda*phi2)*
std::cos((firstLambda - 2.0)*alpha);
double second_cos = std::cos((firstLambda - 2.0)*phi2)*
std::cos(firstLambda*alpha);
// // Hierher renable if you want to check the validity of \psi
// double stream_function = radius_part*(first_cos - second_cos);
// Velocities w.r.t radius and angle
double u_r = K*pow(r, firstLambda - 1.0)
*((firstLambda - 2.0)*std::cos(alpha*firstLambda)
*std::sin((phi2*(firstLambda - 2.0)))
- firstLambda*std::cos(alpha*(-2.0 + firstLambda))
*std::sin(phi2*firstLambda));
double u_phi = - K*firstLambda*pow(r, firstLambda - 1.0)
*((first_cos - second_cos));
double pressure = 0.0, du_dr = 0.0, du_dphi = 0.0,
dv_dr = 0.0, dv_dphi = 0.0;
// Make sure we don't get a NaN!
if (r != 0.0)
{
// Possible solution of the Stokes flow
// Since the problem is linear,
// could every linear combination fit with the finite element solution?
double pressure1 = 4.0*K*(firstLambda - 1.0)*pow(r, firstLambda - 2.0)
*std::cos(alpha*firstLambda)
*std::sin(phi2*(firstLambda - 2.0));
pressure = mu*pressure1;
// Compute the derivatives of the velocities
// du_r/dr, du_r/dphi, du_phi/dr, du_phi/dphi
du_dr = K*(firstLambda - 1.0)*pow(r, firstLambda - 2.0)
*((firstLambda - 2.0)*std::cos(alpha*firstLambda)
*std::sin(phi2*(firstLambda - 2.0))
- firstLambda*std::cos(alpha*(-2.0 + firstLambda))
*std::sin(phi2*firstLambda));
du_dphi = K*pow(r, firstLambda - 1.0)*( - firstLambda*firstLambda
*std::cos(firstLambda*phi2)
*std::cos(alpha*(firstLambda - 2.0))
+ std::cos(alpha*firstLambda)
*std::cos(phi2*(firstLambda - 2.0))*(firstLambda - 2.0)
*(firstLambda - 2.0));
dv_dr = - K*firstLambda*(firstLambda - 1.0)*pow(r, firstLambda - 2.0)
*(first_cos - second_cos);
dv_dphi = - K*firstLambda*pow(r, firstLambda - 1.0)
*(std::cos(alpha*firstLambda)
*std::sin(phi2*(firstLambda - 2.0))*(firstLambda - 2.0)
- firstLambda*std::sin(firstLambda*phi2)
*std::cos(alpha*(firstLambda - 2.0)));
}
double u_x = u_r*std::cos(phi) - u_phi*std::sin(phi);
double u_y = u_r*std::sin(phi) + u_phi*std::cos(phi);
// A singular fonction that solves Stokes flow
u[0] = u_x;
u[1] = u_y;
u[2] = pressure;
// The associated gradient in polar coordinates
du_dpolar[0][0] = du_dr;
du_dpolar[0][1] = du_dphi;
du_dpolar[1][0] = dv_dr;
du_dpolar[1][1] = dv_dphi;
// Hierher discard this .B.
// double dudr = -2.0/3.0*pow(r,-1.0/3.0)*
// sin(2.0/3.0 * (phi + MathematicalConstants::Pi/2.0));
// double dudphi = pow(r,2.0/3.0)*2.0/3.0*
// cos(2.0/3.0 * (phi + MathematicalConstants::Pi/2.0));
// du_dx[0][0] = dudr*cos(phi) - 1.0/r*dudphi*sin(phi);
// du_dx[1][0] = dudr*sin(phi) + 1.0/r*dudphi*cos(phi);
// std::fill(u.begin(), u.end(), 2019);
// std::fill(du_dx[0].begin(), du_dx[0].end(), 0.0);
}
/// \short "Singular" function
Vector<double> singular_fct(const Vector<double>& x)
{
// hierher just taylored to dim 2!!
Vector<double> u(3, 0);
Vector<Vector<double> > du_dpolar(2, Vector<double>(2, 0.0));
singular_fct_and_gradient(x, u, du_dpolar);
return u;
}
/// \short Gradient of "singular" function (in polar coordinates)
Vector<Vector<double> > gradient_of_singular_fct(const Vector<double>& x)
{
Vector<double> u(3, 0); // hierher just taylored to dim 2 !!
Vector<Vector<double> > du_dpolar(2, u);
singular_fct_and_gradient(x, u, du_dpolar);
return du_dpolar;
}
/// Exact solution
Vector<double> u_exact(const Vector<double>& x)
{
Vector<double> u(3, 0);
if (!CommandLineArgs::command_line_flag_has_been_set
("--suppress_sing_in_exact_soln"))
{
Vector<double> temp = singular_fct(x);
for (unsigned i = 0; i < u.size(); ++i)
{
u[i] += temp[i];
}
}
if (CommandLineArgs::command_line_flag_has_been_set
("--add_sin_cosh_to_exact_soln"))
{
double temp2 = u_additional(x);
for (unsigned j = 0; j < u.size(); ++j)
{
u[j] += temp2;
}
}
return u;
}
double u_additional(const Vector<double>& x)
{
return (sin(MathematicalConstants::Pi * x[0]/2)
*sinh(MathematicalConstants::Pi * x[1]/2));
}
// Compute stress tensor coeff \T_ij in cartesian at global coordinates x
// based on the Moffat singular solution
Vector<Vector<double> > singular_traction_stress_tensor_nst(
const Vector<double> &x)
{
// Polar coordinates w.r.t. the origin
double r = sqrt((x[0]-L_up)*(x[0]-L_up) + x[1]*x[1]);
double phi = atan2(x[1], x[0] - 2.0);
// Get the values of the singular function at our current location
Vector<double> sing_fct_value = singular_fct(x);
Vector<Vector<double> > grad_u_sing = gradient_of_singular_fct(x);
double u_x = sing_fct_value[0];
double u_y = sing_fct_value[1];
double pressure = sing_fct_value[2];
// Compute polar velocities
double u_r = u_x*std::cos(phi) + u_y*std::sin(phi);
double u_theta = - u_x*std::sin(phi) + u_y*std::cos(phi);
Vector<Vector<double> > local_stress(2, Vector<double>(2, 0.0));
double D_rr, D_rt, D_tr, D_tt;
double D_xx_hat, D_xy_hat, D_yx_hat, D_yy_hat;
double D_xx, D_xy, D_yx, D_yy;
// Deformation tensor in polar coordinates
// r stands for radius and t for theta
D_rr = 2.0 * grad_u_sing[0][0];
D_rt = (grad_u_sing[0][1]/r + grad_u_sing[1][0]
- u_theta/r);
D_tr = D_rt;
D_tt = 2.0 * (grad_u_sing[1][1] + u_r)/r;
// 'Half' mapping of deformation tensor in cartesian coord
// We will also need to multiply this matrix by the transpose of
// the rotation matrix, to get the real cartesian D_ij
D_xx_hat = std::cos(phi)*D_rr - std::sin(phi)*D_tr;
D_xy_hat = std::cos(phi)*D_rt - std::sin(phi)*D_tt;
// D_yx_hat = D_xy_hat;
D_yx_hat = std::sin(phi)*D_rr + std::cos(phi)*D_tr;
D_yy_hat = std::sin(phi)*D_rt + std::cos(phi)*D_tt;
// We finally get our correct strain tensor D_ij in cartesian
D_xx = std::cos(phi)*D_xx_hat - std::sin(phi)*D_xy_hat;
D_xy = std::sin(phi)*D_xx_hat + std::cos(phi)*D_xy_hat;
D_yx = std::cos(phi)*D_yx_hat - std::sin(phi)*D_yy_hat;
D_yy = std::sin(phi)*D_yx_hat + std::cos(phi)*D_yy_hat;
// Compute T_ij = -p delta_ij * D_ij
// local_stress[0][0] = - sing_fct_value[2] + D_xx;
local_stress[0][0] = - pressure + D_xx;
local_stress[0][1] = D_xy;
local_stress[1][0] = D_yx;
// local_stress[1][1] = - sing_fct_value[2] + D_yy;
local_stress[1][1] = - pressure + D_yy;
// Avoid Nan value at the corner
if (r == 0.0)
{
local_stress[0][0] = 0.0;
local_stress[0][1] = 0.0;
local_stress[1][0] = 0.0;
local_stress[1][1] = 0.0;
}
return local_stress;
}
/// Traction required at boundary 2
void prescribed_traction(const double &t,
const Vector<double>& x,
const Vector<double> &n,
Vector<double>& traction)
{
Vector<Vector<double> > traction_stress_tensor =
singular_traction_stress_tensor_nst(x);
traction[0] = traction_stress_tensor[0][0];
traction[1] = traction_stress_tensor[0][1];
// Renable if you want to see the effet of the traction amplitude
// traction[0] = 0.0;
// traction[1] = 0.0;
}
// Take a x coordinates vector, return the cartesian singular velocities
Vector<double> moffat_singular_function(const Vector<double>& x)
{
// Definition of the constant
const double K = 1.0;
const long double firstLambda = 1.544483736;
const double alpha = 3.0 * MathematicalConstants::Pi / 4.0;
// The dynamic viscosity (here water's one)
const double mu = 1;
// Radius & polar angle (hierher be careful, the L_up term is designed to
// recentered the singularity on the corner)
double y = x[1];
double r = sqrt((x[0]-L_up)*(x[0]-L_up) + y*y);
double phi = atan2(y, x[0] - L_up);
// Define another phi, to rotate the corner and get it the right position
double phi2 = phi - MathematicalConstants::Pi / 4.0;
// Stream function
double first_cos = std::cos(firstLambda*phi2)*
std::cos((firstLambda - 2.0)*alpha);
double second_cos = std::cos((firstLambda - 2.0)*phi2)*
std::cos(firstLambda*alpha);
// double radius_part = K*pow(r, firstLambda);
// double stream_function = radius_part*(first_cos - second_cos);
// double stream_function = K*pow(r, firstLambda)*
// (std::cos((firstLambda - 2.0)*alpha)*std::cos(firstLambda*phi/alpha)
// - std::cos(firstLambda*alpha)*std::cos((firstLambda - 2.0)*phi/alpha));
// Velocities w.r.t radius and angle
double u_r = K*pow(r, firstLambda - 1.0)
*((firstLambda - 2.0)*std::cos(alpha*firstLambda)
*std::sin((phi2*(firstLambda - 2.0)))
- firstLambda*std::cos(alpha*(-2.0 + firstLambda))
*std::sin(phi2*firstLambda));
double u_phi = - K*firstLambda*pow(r, firstLambda - 1.0)
*((first_cos - second_cos));
double pressure;
// Make sure we don't get a NaN!
if (r != 0.0)
{
double pressure1 = 4.0*K*pow(r, firstLambda - 2.0)
*std::cos(alpha*firstLambda)
*std::sin(phi2*(firstLambda - 2.0))
*(firstLambda - 1)
- 2*K*pow(r,(firstLambda - 2.0))
*std::sin(firstLambda*phi2)
*std::cos(alpha*(firstLambda - 2.0))
*(2.0*firstLambda*firstLambda
- 5.0*firstLambda + 2.0);
// double pressure2 = -(2.0*K*pow(r,firstLambda - 2.0)
// *(2.0*std::cos(alpha*firstLambda)
// *std::sin(phi2*(firstLambda - 2.0))
// + 2.0*firstLambda*firstLambda
// *std::sin(firstLambda*phi2)
// *std::cos(alpha*(firstLambda - 2.0))
// - firstLambda*std::cos(alpha*firstLambda)
// *std::sin(phi2*(firstLambda - 2.0))
// - firstLambda*std::sin(firstLambda*phi2)
// *std::cos(alpha*(firstLambda - 2.0))))
// /(firstLambda - 2.0);
pressure = mu*pressure1;
}
else
{
pressure = 0.0;
}
Vector<double> u_s(4, 0.0);
// We get back to the cartesian coordinates
u_s[0] = u_r*std::cos(phi) - u_phi*std::sin(phi);
u_s[1] = u_r*std::sin(phi) + u_phi*std::cos(phi);
u_s[2] = pressure;
// u_s[0] = stream_function;
// u_s[1] = u_r*std::cos(phi) - u_phi*std::sin(phi);
// u_s[2] = u_r*std::sin(phi) + u_phi*std::cos(phi);
// u_s[3] = pressure;
return u_s;
}
} // end_of_namespace
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//==start_of_problem_class============================================
/// NavierStokes in backward-facing step. Dirichlet boundary conditions along
/// all boundaries.
//====================================================================
template<class ELEMENT>
class StepProblem : public Problem
{
public:
/// Constructor
StepProblem();
/// Destructor
~StepProblem()
{
// hierher: at some point delete things properly and do memory leak
// check .B.
delete Bulk_mesh_pt->spatial_error_estimator_pt();
delete Bulk_mesh_pt;
}
/// Update the after solve (empty)
void actions_after_newton_solve() {
delete_face_elements(); // Hierher be carefull!
}
/// \short Update the problem specs before solve (empty)
void actions_before_newton_solve() {}
// Perform actions after mesh adaptation
void actions_after_adapt()
{
// Recreate face elements
// hierher renable create_face_elements();
// Complete problem setup
complete_problem_setup();
// Rebuild global mesh
rebuild_global_mesh();
}
/// Perform actions after mesh adaptation (empty)
void actions_before_adapt()
{
// Kill face elements
// hierher renable delete_face_elements();
// Rebuild global mesh
rebuild_global_mesh();
}
/// Access function for the specific mesh
RefineableTriangleMesh<ELEMENT>* mesh_pt()
{
return dynamic_cast<RefineableTriangleMesh<ELEMENT>*>(Problem::mesh_pt());
}
/// \short Create traction elements on boundary b of the Mesh pointed
/// to by bulk_mesh_pt and add them to the Mesh object pointed to by
/// surface_mesh_pt
void create_traction_elements(const unsigned &b,
Mesh* const &bulk_mesh_pt,
Mesh* const &surface_mesh_pt);
/// Doc the solution
void doc_solution(DocInfo& doc_info);
private:
/// Do what it says
void complete_problem_setup();
/// Helper function to apply boundary conditions
void apply_boundary_conditions();
/// sDelete face elements and flush meshes
void delete_face_elements()
{
if (CommandLineArgs::command_line_flag_has_been_set
("--dont_use_singularity"))
{
return;
}
// // hierher
// // Wipe the mesh
// Face_mesh_for_singularity_integral_pt->flush_element_and_node_storage();
// n_element = Singular_fct_element_mesh_pt->nelement();
// for(unsigned e=0;e<n_element;e++)
// {
// delete Singular_fct_element_mesh_pt->element_pt(e);
// }
// Singular_fct_element_mesh_pt->flush_element_and_node_storage();
}
// hierher renable!
/// Create face elements
void create_face_elements()
{
if (CommandLineArgs::command_line_flag_has_been_set
("--dont_use_singularity"))
{
return;
}
// Hierher renable to set the amplitude .B.
// // We set the amplitude of the sing func with that
// dynamic_cast<TemplateFreeScalableSingularityForNavierStokesElement*>(
// Singular_fct_element_mesh_pt->element_pt(0))
// ->set_amplitude_of_singular_fct(3.0);
/// Map keeps a running count of duplicate nodes already created;
/// existing_duplicate_node_pt[orig_node_pt]=new_node_pt.
std::map<Node*,Node*> existing_duplicate_node_pt;
// Create the face elements needed to compute the amplitude of
// the singular function,
// hierher change this to include the outer boundaries only!
for(unsigned i_bound = 0; i_bound < 6; i_bound++)
{
unsigned n_element = Bulk_mesh_pt->nboundary_element(i_bound);
for(unsigned e = 0; e < n_element; e++)
{
// Create Pointer to bulk element adjacent to the boundary
ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>
(Bulk_mesh_pt->boundary_element_pt(i_bound, e));
// Get Face index of boundary in the bulk element
int face_index = Bulk_mesh_pt->face_index_at_boundary(i_bound, e);
// Create corresponding face element
FluxElementForSingularityEquation<ELEMENT>* flux_element_pt =
new FluxElementForSingularityEquation<ELEMENT>(bulk_elem_pt,face_index);
// We pass the pointer of singular function to the face element
flux_element_pt->navier_stokes_sing_el_pt()
->unscaled_singular_fct_pt()
= &Global_Physical_Variables::singular_fct;
// We pass the pointer of the gradient of the singular function to
// the face element
flux_element_pt->navier_stokes_sing_el_pt()
->gradient_of_unscaled_singular_fct_pt() =
&Global_Physical_Variables::gradient_of_singular_fct;
// Attach it to the mesh
Face_mesh_for_singularity_integral_pt->add_element_pt(flux_element_pt);
}
}
// Update the pointer to the face elements
dynamic_cast<ScalableSingularityForNavierStokesElement<ELEMENT>*>(
Singular_fct_element_mesh_pt->element_pt(0))->
set_mesh_of_face_elements(Face_mesh_for_singularity_integral_pt);
// Be cautious with this code, can be removed .B.
// Now loop over bulk elements
//----------------------------------------------------
// and swap over any of their nodes have been replaced
//----------------------------------------------------
unsigned n_el = Bulk_mesh_pt->nelement();
for (unsigned e = 0; e < n_el; e++)
{
ELEMENT* bulk_el_pt = dynamic_cast<ELEMENT*>(
Bulk_mesh_pt->element_pt(e));
// Loop over all nodes and check if they're amongst the replaced
// ones
unsigned nnod=bulk_el_pt->nnode();
for (unsigned j = 0; j < nnod; j++)
{
Node* nod_pt = bulk_el_pt->node_pt(j);
// Find this original node in the map; if we find it
// it's already been duplicated
std::map<Node*,Node*>::iterator it =
existing_duplicate_node_pt.find(nod_pt);
if (it != existing_duplicate_node_pt.end())
{
// Use the existing duplicate node
bulk_el_pt->node_pt(j) = (*it).second;
}
}
}
}
// Hierher mesh definition
/// Pointer to the bulk mesh
RefineableTriangleMesh<ELEMENT> *Bulk_mesh_pt;
/// \short Face elements used to compute the amplitude of the singular
/// function
Mesh* Face_mesh_for_singularity_integral_pt;
/// Mesh for (single) element containing singular fct
Mesh* Singular_fct_element_mesh_pt;
/// Pointer to the "surface" mesh (for traction elements)
Mesh* Surface_mesh_pt;
/// \short Enumeration for IDs of FaceElements (used to figure out
/// who's added what additional nodal data...)
enum{Flux_jump_el_id, BC_el_id};
}; // end_of_problem_class
//==start_of_constructor==================================================
/// Constructor for StepProblem problem
//========================================================================
template<class ELEMENT>
StepProblem<ELEMENT>::StepProblem()
{
// Build the mesh
double uniform_element_area=0.01;
Bulk_mesh_pt = Global_Physical_Variables::build_the_mesh<ELEMENT>
(uniform_element_area);
// // Let's have a look at the boundary enumeration (don't need this)
// Bulk_mesh_pt->output_boundaries("RESLT/boundaries.dat");
// Set error estimator for bulk mesh
Z2ErrorEstimator* error_estimator_pt = new Z2ErrorEstimator;
Bulk_mesh_pt->spatial_error_estimator_pt() = error_estimator_pt;
// Set element size limits
Bulk_mesh_pt->max_element_size() = 0.01;
Bulk_mesh_pt->min_element_size() = 1e-30;
Bulk_mesh_pt->max_permitted_error() = 0.005;
Bulk_mesh_pt->min_permitted_error() = 0.0;
// Hierher traction elements implementation (dev)
// Create "surface mesh" that will contain only the prescribed-traction
// elements. The constructor just creates the mesh without
// giving it any elements, nodes, etc.
Surface_mesh_pt = new Mesh;
// Create prescribed-traction elements from all elements that are
// adjacent to boundary 2, but add them to a separate mesh.
create_traction_elements(2, Bulk_mesh_pt, Surface_mesh_pt);
// Add sub-mesh
add_sub_mesh(Bulk_mesh_pt);
// Add traction elements sub mesh
add_sub_mesh(Surface_mesh_pt);
// hierher renable
if (!CommandLineArgs::command_line_flag_has_been_set
("--dont_use_singularity"))
{
// Create element that stores the singular fct and its amplitude
// ---------------------------------------------------------------
ScalableSingularityForNavierStokesElement<ELEMENT>* el_pt=
new ScalableSingularityForNavierStokesElement<ELEMENT>;
// cout << "Pointer of singularity is ready: \033[7;41m"
// << el_pt << "\033[0m\n" << std::endl;
// Pass fct pointers:
el_pt->unscaled_singular_fct_pt()
= &Global_Physical_Variables::singular_fct;
el_pt->gradient_of_unscaled_singular_fct_pt() =
&Global_Physical_Variables::gradient_of_singular_fct;
// Add to mesh
Singular_fct_element_mesh_pt = new Mesh;
Singular_fct_element_mesh_pt->add_element_pt(el_pt);
add_sub_mesh(Singular_fct_element_mesh_pt); // reach oomph error
Face_mesh_for_singularity_integral_pt = new Mesh;
create_face_elements();
add_sub_mesh(Face_mesh_for_singularity_integral_pt);
// // I think it is not needed
}
// Build global mesh
build_global_mesh();
// Complete problem setup
complete_problem_setup();
// Setup equation numbering scheme
oomph_info << "Number of equations: "
<< this->assign_eqn_numbers()
<< std::endl;
} // end_of_constructor
//==start_of_complete======================================================
/// Set boundary condition, and complete the build of
/// all elements
//========================================================================
template<class ELEMENT>
void StepProblem<ELEMENT>::complete_problem_setup()
{
if (!CommandLineArgs::command_line_flag_has_been_set
("--dont_use_singularity"))
{
// Loop over the elements to set up element-specific
// things that cannot be handled by constructor
// hierher renable this one first!
// Bulk elements
unsigned n_el = Bulk_mesh_pt->nelement();
for (unsigned e = 0; e < n_el; e++)
{
ELEMENT* bulk_el_pt = dynamic_cast<ELEMENT*>(
Bulk_mesh_pt->element_pt(e));
// Tell the bulk element about the singular fct
bulk_el_pt->navier_stokes_sing_el_pt() =
dynamic_cast<TemplateFreeScalableSingularityForNavierStokesElement*>(
Singular_fct_element_mesh_pt->element_pt(0));
}
}
// Apply bcs
apply_boundary_conditions();
/// Assign traction elements values
// Loop over the flux elements to pass pointer to prescribed traction function
// and pointer to global time object
unsigned n_traction_el = Surface_mesh_pt->nelement();
for(unsigned e = 0; e < n_traction_el; ++e)
{
// Upcast from GeneralisedElement to traction element
NavierStokesTractionElement<ELEMENT> *el_pt =
dynamic_cast< NavierStokesTractionElement<ELEMENT>*>(
Surface_mesh_pt->element_pt(e));
// Set the pointer to the prescribed traction function
el_pt->traction_fct_pt() =
&Global_Physical_Variables::prescribed_traction;
}
// How many traction elements?
cout << "Number of traction elements: " << n_traction_el << std::endl;
}
//==start_of_apply_bc=====================================================
/// Helper function to apply boundary conditions
//========================================================================
template<class ELEMENT>
void StepProblem<ELEMENT>::apply_boundary_conditions()
{
//Set the boundary conditions for this problem: All nodes are
//free by default -- just pin the ones that have Dirichlet conditions
//here.
unsigned num_bound = Bulk_mesh_pt->nboundary();
for(unsigned ibound = 0; ibound < num_bound; ibound++)
{
// Leave internal boundary alone
if (ibound != 6 && ibound != 2)
{
unsigned num_nod = Bulk_mesh_pt->nboundary_node(ibound);
for (unsigned inod = 0; inod < num_nod; inod++)
{
Node* nod_pt = Bulk_mesh_pt->boundary_node_pt(ibound, inod);
Vector<double> x_position(2);
x_position[0] = nod_pt->x(0);
x_position[1] = nod_pt->x(1);
// if (!( (x_position[0] == 4.0)
// && (x_position[1] == 1.0 || x_position[1] == -1.0) ))
// {
Vector<double> singular_velocities;
singular_velocities = Global_Physical_Variables
::singular_fct(x_position);
nod_pt->pin(0);
nod_pt->pin(1);
nod_pt->set_value(0, singular_velocities[0]);
nod_pt->set_value(1, singular_velocities[1]);
// }
// // x velocity is pinned at and on no slip boundaries
// // i.e. everywhere apart from outflow boundary 2
// if (ibound != 2)
// {
// Bulk_mesh_pt->boundary_node_pt(ibound, inod)->pin(0);
// }
// // y velocity is zero either because of no slip or
// // horizontal flow
// Bulk_mesh_pt->boundary_node_pt(ibound, inod)->pin(1);
}
}
} // end loop over boundaries
// Hierher renable
// // Now set boundary values on inflow
// unsigned ibound = 0;
// unsigned num_nod = Bulk_mesh_pt->nboundary_node(ibound);
// for (unsigned inod = 0; inod < num_nod; inod++)
// {
// Node* nod_pt = Bulk_mesh_pt->boundary_node_pt(ibound, inod);
// double y = nod_pt->x(1);
// double u = Global_Physical_Variables::quadratic_flow(y);
// nod_pt->set_value(0, u);
// }
// // Hierher quick test: impose u = u_s on all boundaries != 6
// unsigned num_bound = Bulk_mesh_pt->nboundary();
// for(unsigned ibound = 0; ibound < num_bound; ibound++)
// {
// // Leave internal boundary alone
// if (ibound != 6)
// {
// unsigned num_nod = Bulk_mesh_pt->nboundary_node(ibound);
// for (unsigned inod = 0; inod < num_nod; inod++)
// {
// Node* nod_pt = Bulk_mesh_pt->boundary_node_pt(ibound, inod);
// Vector<double> x_position(2);
// x_position[0] = nod_pt->x(0);
// x_position[1] = nod_pt->x(1);
// // if (!( (x_position[0] == Global_Physical_Variables::L_up)
// // && (x_position[1] == 0.0) ))
// {
// Vector<double> singular_velocities;
// singular_velocities = Global_Physical_Variables::singular_fct(
// x_position);
// double phi = atan2(x_position[1],
// x_position[0] - Global_Physical_Variables::L_up);
// double u_x = singular_velocities[0]*std::cos(phi)
// - singular_velocities[1]*std::sin(phi);
// double u_y = singular_velocities[0]*std::sin(phi)
// + singular_velocities[1]*std::cos(phi);
// if (!( (x_position[0] == Global_Physical_Variables::L_up)
// && (x_position[1] == 0.0) ))
// {
// nod_pt->pin(0);
// }
// else
// {
// oomph_info << "at the corner...\n";
// }
// nod_pt->pin(1);
// nod_pt->set_value(0, u_x);
// nod_pt->set_value(1, u_y);
// }
// // else {
// // // nod_pt->pin(0);
// // // nod_pt->pin(1);
// // // nod_pt->set_value(0, 0.0);
// // // nod_pt->set_value(1, 0.0);
// // }
// }
// }
// } // end loop over boundaries
// hierher
// Assign solution everywhere
{
unsigned num_nod = Bulk_mesh_pt->nnode();
for (unsigned inod = 0; inod < num_nod; inod++)
{
Node* nod_pt = Bulk_mesh_pt->node_pt(inod);
Vector<double> x_position(2);
x_position[0] = nod_pt->x(0);
x_position[1] = nod_pt->x(1);
Vector<double> singular_velocities;
singular_velocities = Global_Physical_Variables::singular_fct(x_position);
nod_pt->set_value(0, singular_velocities[0]);
nod_pt->set_value(1, singular_velocities[1]);
if (nod_pt->nvalue() == 3)
{
double p = 0.0; // dummy infinity
if (!( (x_position[0] == Global_Physical_Variables::L_up)
&& (x_position[1] == 0.0) ))
{
p = singular_velocities[2];
}
nod_pt->set_value(2, p);
}
}
}
} // end set bc
//==start_of_doc_solution=================================================
/// Doc the solution
//========================================================================
template<class ELEMENT>
void StepProblem<ELEMENT>::doc_solution(DocInfo& doc_info)
{
ofstream some_file;
char filename[100];
// Number of plot points