axisym_heat_sphere/half_rectangle_with_hole_mesh.h
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Copyright (C) 2006-2022 Matthias Heil and Andrew Hazel
7 //LIC//
8 //LIC// This library is free software; you can redistribute it and/or
9 //LIC// modify it under the terms of the GNU Lesser General Public
10 //LIC// License as published by the Free Software Foundation; either
11 //LIC// version 2.1 of the License, or (at your option) any later version.
12 //LIC//
13 //LIC// This library is distributed in the hope that it will be useful,
14 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 //LIC// Lesser General Public License for more details.
17 //LIC//
18 //LIC// You should have received a copy of the GNU Lesser General Public
19 //LIC// License along with this library; if not, write to the Free Software
20 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 //LIC// 02110-1301 USA.
22 //LIC//
23 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 //LIC//
25 //LIC//====================================================================
26 #ifndef HALF_RECTANGLE_WITH_MESH_HEADER
27 #define HALF_RECTANGLE_WITH_MESH_HEADER
28 
29 #include "generic.h"
30 
31 namespace oomph
32 {
33 
34 using namespace QuadTreeNames;
35 
36 //===============================================
38 //===============================================
39 class HalfEllipse : public GeomObject
40 {
41 
42 public:
43 
45  HalfEllipse(const double &centre_z,
46  const double &a, const double &b)
47  : GeomObject(1,2), Centre_z(centre_z), A(a), B(b)
48  {}
49 
52 
54  void position(const Vector<double> &xi, Vector<double> &r) const
55  {
56  r[0] = A*sin(xi[0]);
57  r[1] = Centre_z + B*cos(xi[0]);
58  }
59 
60 
62  double& centre_z(){return Centre_z;}
63 
65  double& a(){return A;}
66 
68  double& b(){return B;}
69 
70 
71 private:
72 
74  double Centre_z;
75 
77  double A;
78 
80  double B;
81 
82 };
83 
84 
85 
89 
90 
91 
92 //===========================================================
94 //===========================================================
96 {
97 
98 public:
99 
100 
107  const double &radius,
108  const double &length,
109  const double &up_length,
110  const unsigned &nup,
111  const double &down_length,
112  const unsigned &ndown,
113  const double &width_near_cylinder,
114  const unsigned &ncolumn) :
115  Cylinder_pt(cylinder_pt), Nup(nup), Ndown(ndown), Ncolumn(ncolumn)
116  {
117 
118  //Axial spacing between lines
119  double up_spacing = up_length/(double)nup;
120  double down_spacing = down_length/(double)ndown;
121 
122  //Resize the storage for the corners of the squared
123  Up.resize(ncolumn+1); Down.resize(ncolumn+1);
124 
125  //The first column is special
126  {
127  unsigned j=0;
128  Up[j].resize(nup+1); Up[j].resize(nup+1);
129  //Set the coordinates
130  for(unsigned i=0;i<(nup+1);i++)
131  {
132  Up[j][i].resize(2);
133  Up[j][i][0] = 0.0; Up[j][i][1] = i*up_spacing;
134  }
135 
136  //There are going to be ndown+1 lines in the downstream region
137  Down[j].resize(ndown+1); Down[j].resize(ndown+1);
138 
139  //Set the coordinates
140  for(unsigned i=0;i<(ndown+1);i++)
141  {
142  Down[j][i].resize(2); Down[j][i].resize(2);
143  Down[j][i][0] = 0.0;
144  Down[j][i][1] = length - (ndown - i)*down_spacing;
145  }
146  }
147 
148  //What is the column spacing.
149  double radial_start = radius;
150  double radial_spacing = 0.0;
151 
152  if(ncolumn > 1)
153  {
154  radial_start = width_near_cylinder;
155  radial_spacing = (radius - width_near_cylinder)/(double)(ncolumn-1);
156  }
157 
158  //There are going to be nup+1 lines in the upstream region
159  for(unsigned j=1;j<(ncolumn+1);j++)
160  {
161  Up[j].resize(nup+1); Up[j].resize(nup+1);
162  //Set the coordinates
163  for(unsigned i=0;i<(nup+1);i++)
164  {
165  Up[j][i].resize(2);
166  Up[j][i][0] = radial_start + (j-1)*radial_spacing;
167  Up[j][i][1] = i*up_spacing;
168  }
169 
170  //There are going to be ndown+1 lines in the downstream region
171  Down[j].resize(ndown+1); Down[j].resize(ndown+1);
172 
173  //Set the coordinates
174  for(unsigned i=0;i<(ndown+1);i++)
175  {
176  Down[j][i].resize(2); Down[j][i].resize(2);
177  Down[j][i][0] = radial_start + (j-1)*radial_spacing;
178  Down[j][i][1] = length - (ndown - i)*down_spacing;
179  }
180  }
181 
182  //There are three + nup + ndown macro elements in the first column
183  //Plus the additional columns of 1 + nup + ndowm
184  unsigned n_macro = 3 + nup + ndown + (ncolumn-1)*(1 + nup + ndown);
185  Macro_element_pt.resize(n_macro);
186 
187  // Build the 2D macro elements
188  for (unsigned i=0;i<n_macro;i++)
189  {Macro_element_pt[i]= new QMacroElement<2>(this,i);}
190  }
191 
192 
193 
196 
197 
201  const double &s, Vector<double> &f)
202  {
203  for(unsigned i=0;i<2;i++)
204  {
205  f[i] = left[i] + (right[i] - left[i])*0.5*(s+1.0);
206  }
207  }
208 
209 
210 
214  void macro_element_boundary(const unsigned &time,
215  const unsigned &m,
216  const unsigned &direction,
217  const Vector<double> &s,
218  Vector<double>& f)
219  {
220  // Lagrangian coordinate along surface of cylinder
221  Vector<double> xi(1);
222 
223  // Point on circle
224  Vector<double> point_on_circle(2);
225 
226  //Upstream region all rectangular blocks
227  if(m < Nup)
228  {
229  //Switch on the direction
230 
231  switch(direction)
232  {
233  case N:
234  linear_interpolate(Up[0][m+1],Up[1][m+1],s[0],f);
235  break;
236 
237  case S:
238  linear_interpolate(Up[0][m],Up[1][m],s[0],f);
239  break;
240 
241  case W:
242  linear_interpolate(Up[0][m],Up[0][m+1],s[0],f);
243  break;
244 
245  case E:
246  linear_interpolate(Up[1][m],Up[1][m+1],s[0],f);
247  break;
248 
249  default:
250 
251  std::ostringstream error_stream;
252  error_stream << "Direction is incorrect: " << direction << std::endl;
253  throw OomphLibError(
254  error_stream.str(),
257  }
258  }
259  //The special cases around the half-domain
260  else if(m < Nup + 3)
261  {
262  //Scale the macro element number
263  unsigned m_mod = m - Nup;
264 
265  //Switch on the macro element
266  switch(m_mod)
267  {
268  //Macro element 0, is is immediately below the cylinder
269  case 0:
270 
271  switch(direction)
272  {
273  case N:
274  xi[0] = 4.0*atan(1.0) - atan(1.0)*0.5*(1.0+s[0]);
275  Cylinder_pt->position(time,xi,f);
276  break;
277 
278  case S:
279  linear_interpolate(Up[0][Nup],Up[1][Nup],s[0],f);
280  break;
281 
282  case W:
283  xi[0] = 4.0*atan(1.0);
284  Cylinder_pt->position(time,xi,point_on_circle);
285  linear_interpolate(Up[0][Nup],point_on_circle,s[0],f);
286  break;
287 
288  case E:
289  xi[0] = 3.0*atan(1.0);
290  Cylinder_pt->position(time,xi,point_on_circle);
291  linear_interpolate(Up[1][Nup],point_on_circle,s[0],f);
292  break;
293 
294  default:
295 
296  std::ostringstream error_stream;
297  error_stream << "Direction is incorrect: " << direction
298  << std::endl;
299  throw OomphLibError(
300  error_stream.str(),
303  }
304 
305  break;
306 
307  //Macro element 1, is immediately to the right the cylinder
308  case 1:
309 
310  switch(direction)
311  {
312  case N:
313  xi[0] = atan(1.0);
314  Cylinder_pt->position(time,xi,point_on_circle);
315  linear_interpolate(point_on_circle,Down[1][0],s[0],f);
316  break;
317 
318  case S:
319  xi[0] = 3.0*atan(1.0);
320  Cylinder_pt->position(time,xi,point_on_circle);
321  linear_interpolate(point_on_circle,Up[1][Nup],s[0],f);
322  break;
323 
324  case W:
325  xi[0] = 3.0*atan(1.0) - 2.0*atan(1.0)*0.5*(1.0+s[0]);
326  Cylinder_pt->position(time,xi,f);
327  break;
328 
329  case E:
330  linear_interpolate(Up[1][Nup],Down[1][0],s[0],f);
331  break;
332 
333  default:
334 
335  std::ostringstream error_stream;
336  error_stream << "Direction is incorrect: " << direction << std::endl;
337  throw OomphLibError(
338  error_stream.str(),
341  }
342 
343  break;
344 
345  //Macro element 2, is immediately above the cylinder
346  case 2:
347 
348  switch(direction)
349  {
350  case N:
351  linear_interpolate(Down[0][0],Down[1][0],s[0],f);
352  break;
353 
354  case S:
355  xi[0] = atan(1.0)*0.5*(1.0+s[0]);
356  Cylinder_pt->position(time,xi,f);
357  break;
358 
359  case W:
360  xi[0] = 0.0;
361  Cylinder_pt->position(time,xi,point_on_circle);
362  linear_interpolate(point_on_circle,Down[0][0],s[0],f);
363  break;
364 
365  case E:
366  xi[0] = atan(1.0);
367  Cylinder_pt->position(time,xi,point_on_circle);
368  linear_interpolate(point_on_circle,Down[1][0],s[0],f);
369  break;
370 
371 
372  default:
373 
374  std::ostringstream error_stream;
375  error_stream << "Direction is incorrect: " << direction << std::endl;
376  throw OomphLibError(error_stream.str(),
379  }
380  break;
381  }
382  } //End of macro elements around the half-cylinder
383  else
384  {
385  //Other cases
386  if(m < Nup+Ndown+3)
387  {
388  unsigned m_mod = m - Nup -3;
389 
390  //Switch on the direction
391 
392  switch(direction)
393  {
394  case N:
395  linear_interpolate(Down[0][m_mod+1],Down[1][m_mod+1],s[0],f);
396  break;
397 
398  case S:
399  linear_interpolate(Down[0][m_mod],Down[1][m_mod],s[0],f);
400  break;
401 
402  case W:
403  linear_interpolate(Down[0][m_mod],Down[0][m_mod+1],s[0],f);
404  break;
405 
406  case E:
407  linear_interpolate(Down[1][m_mod],Down[1][m_mod+1],s[0],f);
408  break;
409 
410  default:
411 
412  std::ostringstream error_stream;
413  error_stream << "Direction is incorrect: " << direction << std::endl;
414  throw OomphLibError(
415  error_stream.str(),
418  }
419  }
420  else if(m < Nup+Ndown+3 + (Ncolumn-1)*(Nup+Ndown+1))
421  {
422  //Work out the modified m
423  unsigned m_col = m - (Nup+Ndown+3);
424  //Work out which column we are in
425  unsigned j_col = 1 + m_col/(Nup+Ndown+1);
426  //Work out the actual vertical position
427  unsigned m_mod = m_col%(Nup+Ndown+1);
428 
429  //If we're in the upstream region
430  if(m_mod < Nup)
431  {
432  switch(direction)
433  {
434  case N:
435  linear_interpolate(Up[j_col][m_mod+1],Up[j_col+1][m_mod+1],s[0],f);
436  break;
437 
438  case S:
439  linear_interpolate(Up[j_col][m_mod],Up[j_col+1][m_mod],s[0],f);
440  break;
441 
442  case W:
443  linear_interpolate(Up[j_col][m_mod],Up[j_col][m_mod+1],s[0],f);
444  break;
445 
446  case E:
447  linear_interpolate(Up[j_col+1][m_mod],Up[j_col+1][m_mod+1],s[0],f);
448  break;
449 
450  default:
451 
452  std::ostringstream error_stream;
453  error_stream << "Direction is incorrect: " << direction << std::endl;
454  throw OomphLibError(
455  error_stream.str(),
458  }
459  }
460  //Otherwise central zone
461  else if(m_mod==Nup)
462  {
463  switch(direction)
464  {
465  case N:
466  linear_interpolate(Down[j_col][0],Down[j_col+1][0],s[0],f);
467  break;
468 
469  case S:
470  linear_interpolate(Up[j_col][Nup],Up[j_col+1][Nup],s[0],f);
471  break;
472 
473  case W:
474  linear_interpolate(Up[j_col][Nup],Down[j_col][0],s[0],f);
475  break;
476 
477  case E:
478  linear_interpolate(Up[j_col+1][Nup],Down[j_col+1][0],s[0],f);
479  break;
480 
481  default:
482 
483  std::ostringstream error_stream;
484  error_stream << "Direction is incorrect: " << direction << std::endl;
485  throw OomphLibError(
486  error_stream.str(),
489  }
490  }
491  else if(m_mod < Nup+Ndown+1)
492  {
493  unsigned m_mod2 = m_mod - Nup -1;
494 
495  //Switch on the direction
496 
497  switch(direction)
498  {
499  case N:
500  linear_interpolate(Down[j_col][m_mod2+1],Down[j_col+1][m_mod2+1],s[0],f);
501  break;
502 
503  case S:
504  linear_interpolate(Down[j_col][m_mod2],Down[j_col+1][m_mod2],s[0],f);
505  break;
506 
507  case W:
508  linear_interpolate(Down[j_col][m_mod2],Down[j_col][m_mod2+1],s[0],f);
509  break;
510 
511  case E:
512  linear_interpolate(Down[j_col+1][m_mod2],Down[j_col+1][m_mod2+1],s[0],f);
513  break;
514 
515  default:
516 
517  std::ostringstream error_stream;
518  error_stream << "Direction is incorrect: " << direction << std::endl;
519  throw OomphLibError(
520  error_stream.str(),
523  }
524  }
525  }
526  else
527  {
528  std::ostringstream error_stream;
529  error_stream << "Wrong macro element number" << m << std::endl;
530  throw OomphLibError(
531  error_stream.str(),
534  }
535  }
536  }
537 
538 private:
539 
542 
545 
548 
550  unsigned Nup;
551 
553  unsigned Ndown;
554 
556  unsigned Ncolumn;
557 
558 };
559 
560 
561 
562 
566 
567 
568 //=============================================================
570 //=============================================================
571 template<class ELEMENT>
572 class HalfRectangleWithHoleMesh : public virtual Mesh
573 {
574 
575 public:
576 
577 
585  const double &radius, const double &length,
586  const double &up_length, const unsigned &nup,
587  const double &down_length, const unsigned &ndown,
588  const double &width_near_cylinder,
589  const unsigned &ncolumn,
590  TimeStepper* time_stepper_pt=
592  {
593  //Create the domain
594  Domain_pt = new HalfRectangleWithHoleDomain(cylinder_pt,radius,length,
595  up_length,nup,down_length,
596  ndown,width_near_cylinder,
597  ncolumn);
598 
599  //Initialise the node counter
600  unsigned long node_count=0;
601 
602  //Vectors used to get data from domains
603  Vector<double> s(2),r(2);
604 
605  //Setup temporary storage for the Node
606  Vector<Node*> Tmp_node_pt;
607 
608  //Now blindly loop over the macro elements and associate and finite
609  //element with each
610  unsigned nmacro_element = Domain_pt->nmacro_element();
611  for(unsigned e=0;e<nmacro_element;e++)
612  {
613  //Create the FiniteElement and add to the Element_pt Vector
614  Element_pt.push_back(new ELEMENT);
615 
616  //Read out the number of linear points in the element
617  unsigned np =
618  dynamic_cast<ELEMENT*>(finite_element_pt(e))->nnode_1d();
619 
620  //Loop over nodes in the column
621  for(unsigned l1=0;l1<np;l1++)
622  {
623  //Loop over the nodes in the row
624  for(unsigned l2=0;l2<np;l2++)
625  {
626  //Allocate the memory for the node
627  Tmp_node_pt.push_back(finite_element_pt(e)->
628  construct_node(l1*np+l2,time_stepper_pt));
629 
630  //Read out the position of the node from the macro element
631  s[0] = -1.0 + 2.0*(double)l2/(double)(np-1);
632  s[1] = -1.0 + 2.0*(double)l1/(double)(np-1);
633  Domain_pt->macro_element_pt(e)->macro_map(s,r);
634 
635  //Set the position of the node
636  Tmp_node_pt[node_count]->x(0) = r[0];
637  Tmp_node_pt[node_count]->x(1) = r[1];
638 
639  //Increment the node number
640  node_count++;
641  }
642  }
643  } //End of loop over macro elements
644 
645  //Now the elements have been created, but there will be nodes in
646  //common, need to loop over the common edges and sort it, by reassigning
647  //pointers and the deleting excess nodes
648 
649  //Read out the number of linear points in the element
650  unsigned np=dynamic_cast<ELEMENT*>(finite_element_pt(0))->nnode_1d();
651 
652  //Edges between the upstream elements including that immediately below
653  //the cylinder
654  for(unsigned m=0;m<(nup+1);m++)
655  {
656  //Edge between Elements m and m+1
657  for(unsigned n=0;n<np;n++)
658  {
659  //Set the nodes in element m+1 to be the same as in element m
660  finite_element_pt(m+1)->node_pt(n)
661  = finite_element_pt(m)->node_pt(np*(np-1) + n);
662 
663  //Remove the nodes in element m+1 from the temporary node list
664  delete Tmp_node_pt[(m+1)*np*np + n];
665  Tmp_node_pt[(m+1)*np*np + n] = 0;
666  }
667  }
668 
669  //Edge between Elements nup and nup+1
670  for(unsigned n=0;n<np;n++)
671  {
672  //Set the nodes in element nup+1 to be the same as in element nup
673  finite_element_pt(nup+1)->node_pt(n)
674  = finite_element_pt(nup)->node_pt((np-n-1)*np + (np-1));
675 
676  //Remove the nodes in element nup+1 from the temporary node list
677  delete Tmp_node_pt[(nup+1)*np*np + n];
678  Tmp_node_pt[(nup+1)*np*np + n] = 0;
679  }
680 
681  //Edge between Element nup+1 and nup2
682  for(unsigned n=0;n<np;n++)
683  {
684  //Set the nodes in element nup+2 to be the same as in element nup+1
685  finite_element_pt(nup+2)->node_pt(np*n + np-1)
686  = finite_element_pt(nup+1)->node_pt(np*(np-1) + n);
687 
688  //Remove the nodes in element nup+2 from the temporary node list
689  delete Tmp_node_pt[(nup+2)*np*np + np*n + np-1];
690  Tmp_node_pt[(nup+2)*np*np + np*n + np-1] = 0;
691  }
692 
693  //Edges between the downstream elements including that immediately above
694  //the cylinder
695  for(unsigned m=nup+2;m<(nup+2+ndown);m++)
696  {
697  //Edge between Elements m and m+1
698  for(unsigned n=0;n<np;n++)
699  {
700  //Set the nodes in element m+1 to be the same as in element m
701  finite_element_pt(m+1)->node_pt(n)
702  = finite_element_pt(m)->node_pt(np*(np-1) + n);
703 
704  //Remove the nodes in element m+1 from the temporary node list
705  delete Tmp_node_pt[(m+1)*np*np + n];
706  Tmp_node_pt[(m+1)*np*np + n] = 0;
707  }
708  }
709 
710 
711  //Now we need to sort out all the edges between the remaining columns
712  //and rows
713  bool first_col=true;
714 
715  unsigned left_col_offset = 0;
716  unsigned right_col_offset = nup+ndown+3;
717  //Loop over the columns
718  for(unsigned j=1;j<ncolumn;j++)
719  {
720  for(unsigned i=0;i<(nup+ndown+1);i++)
721  {
722  //Sort out the left-hand boundary of elements
723  for(unsigned n=0;n<np;n++)
724  {
725  finite_element_pt(right_col_offset)->node_pt(n*np)
726  = finite_element_pt(left_col_offset)->node_pt(n*np + np-1);
727 
728  //Remove the nodes in the element from the temporary node list
729  delete Tmp_node_pt[right_col_offset*np*np + n*np];
730  Tmp_node_pt[right_col_offset*np*np + n*np] = 0;
731  }
732 
733 
734  //Sort out the bottom of the element
735  if(i!=(nup+ndown))
736  {
737  for(unsigned n=1;n<np;n++)
738  {
739  finite_element_pt(right_col_offset+1)->node_pt(n)
740  = finite_element_pt(right_col_offset)->node_pt((np-1)*np + n);
741 
742  //Remove the nodes in the element from the temporary node list
743  delete Tmp_node_pt[(right_col_offset+1)*np*np + n];
744  Tmp_node_pt[(right_col_offset+1)*np*np + n] = 0;
745  }
746  }
747 
748  ++right_col_offset; ++left_col_offset;
749  //Add another offset if the first column
750  if(first_col==true)
751  {
752  if((i==nup-1) || (i==nup)) {++left_col_offset;}
753  }
754  }
755  if(j==1) {first_col=false;}
756  }
757 
758 
759  //Now set the actual true nodes
760  for(unsigned long n=0;n<node_count;n++)
761  {
762  if(Tmp_node_pt[n]!=0) {Node_pt.push_back(Tmp_node_pt[n]);}
763  }
764 
765  //Finally set the nodes on the boundaries
766  set_nboundary(5);
767 
768  //Find the offset for the right hand side
769  unsigned rhs_offset=0;
770  if(ncolumn > 1) {rhs_offset = nup+ndown+3 + (ncolumn-2)*(nup+ndown+1);}
771 
772  for(unsigned n=0;n<np;n++)
773  {
774  //First part of left hand side
775  Node* nod_pt=finite_element_pt(0)->node_pt(n*np);
776  convert_to_boundary_node(nod_pt);
777  add_boundary_node(3,nod_pt);
778 
779  //Part of LHS immediately after hole
780  nod_pt=finite_element_pt(nup+2)->node_pt(n*np);
781  convert_to_boundary_node(nod_pt);
782  add_boundary_node(3,nod_pt);
783 
784  //First part of right hand side
785  nod_pt=finite_element_pt(rhs_offset)->node_pt(n*np + np-1);
786  convert_to_boundary_node(nod_pt);
787  add_boundary_node(1,nod_pt);
788 
789  //First part of lower boundary
790  nod_pt=finite_element_pt(0)->node_pt(n);
791  convert_to_boundary_node(nod_pt);
792  add_boundary_node(0,nod_pt);
793 
794  //First part of upper boundary
795  nod_pt=finite_element_pt(nup+ndown+2)->node_pt(np*(np-1)+n);
796  convert_to_boundary_node(nod_pt);
797  add_boundary_node(2,nod_pt);
798 
799  //First part of hole boundary
800  nod_pt=finite_element_pt(nup)->node_pt(np*(np-1)+n);
801  convert_to_boundary_node(nod_pt);
802  add_boundary_node(4,nod_pt);
803  }
804 
805  //Upstream section
806  for(unsigned n=1;n<np;n++)
807  {
808  for(unsigned m=1;m<nup;m++)
809  {
810  //Next part of left hand side
811  Node* nod_pt=finite_element_pt(m)->node_pt(n*np);
812  convert_to_boundary_node(nod_pt);
813  add_boundary_node(3,nod_pt);
814 
815  //Next part of right hand side
816  nod_pt=finite_element_pt(rhs_offset + m)->node_pt(n*np + np-1);
817  convert_to_boundary_node(nod_pt);
818  add_boundary_node(1,nod_pt);
819  }
820 
821  //Next part of hole
822  Node* nod_pt=finite_element_pt(nup+1)->node_pt(n*np);
823  convert_to_boundary_node(nod_pt);
824  add_boundary_node(4,nod_pt);
825  }
826 
827  //Need to take care with the region around the hole in the special
828  //case of a single column
829  unsigned rhs_extra_offset=1;
830  if(ncolumn>1) {rhs_extra_offset=0;}
831  for(unsigned n=1;n<np;n++)
832  {
833  //Next two parts of left boundary
834  Node* nod_pt=finite_element_pt(nup)->node_pt(n*np);
835  convert_to_boundary_node(nod_pt);
836  add_boundary_node(3,nod_pt);
837 
838  // Next part of right boundary
839  nod_pt=finite_element_pt(rhs_offset + rhs_extra_offset + nup)
840  ->node_pt(n*np + np-1);
841  convert_to_boundary_node(nod_pt);
842  add_boundary_node(1,nod_pt);
843 
844  //Final part of hole boundary
845  nod_pt=finite_element_pt(nup+2)->node_pt(np-1-n);
846  convert_to_boundary_node(nod_pt);
847  add_boundary_node(4,nod_pt);
848  }
849 
850  //Downstream section
851  for(unsigned n=1;n<np;n++)
852  {
853  for(unsigned m=nup+3;m<(nup+ndown+3);m++)
854  {
855  //Next part of left hand side
856  Node* nod_pt=finite_element_pt(m)->node_pt(n*np);
857  convert_to_boundary_node(nod_pt);
858  add_boundary_node(3,nod_pt);
859 
860  //Next part of right hand side
861  if(rhs_offset==0)
862  {
863  nod_pt=finite_element_pt(m)->node_pt(n*np + np-1);
864  convert_to_boundary_node(nod_pt);
865  add_boundary_node(1,nod_pt);
866  }
867  }
868  if(rhs_offset!=0)
869  {
870  for(unsigned m=nup+1;m<(nup+ndown+1);m++)
871  {
872  Node* nod_pt=finite_element_pt(rhs_offset + m)->node_pt(n*np + np-1);
873  convert_to_boundary_node(nod_pt);
874  add_boundary_node(1,nod_pt);
875  }
876  }
877  }
878 
879  //Upper and Lower boundaries
880  unsigned lower_index = nup + ndown + 3;
881  for(unsigned j=1;j<ncolumn;j++)
882  {
883  for(unsigned n=1;n<np;n++)
884  {
885  Node* nod_pt = finite_element_pt(lower_index)->node_pt(n);
886  convert_to_boundary_node(nod_pt);
887  add_boundary_node(0,nod_pt);
888 
889  nod_pt =
890  finite_element_pt(lower_index+nup+ndown)->node_pt(np*(np-1) + n);
891  convert_to_boundary_node(nod_pt);
892  add_boundary_node(2,nod_pt);
893  }
894  lower_index += nup+ndown+1;
895  }
896 
897 
898  //Setup the info
899  this->setup_boundary_element_info();
900 
901  }
902 
904  HalfRectangleWithHoleDomain* domain_pt() {return Domain_pt;}
905 
906 protected:
907 
910 
911 };
912 
913 
917 
918 
919 //===================================================================
923 //===================================================================
924 template<class ELEMENT>
926  public HalfRectangleWithHoleMesh<ELEMENT>, public RefineableQuadMesh<ELEMENT>
927 {
928 public:
929 
937  const double &radius,
938  const double &length,
939  const double &up_length,
940  const unsigned &nup,
941  const double &down_length,
942  const unsigned &ndown,
943  const double &width_near_cylinder,
944  const unsigned &ncolumn,
945  TimeStepper* time_stepper_pt=
947  HalfRectangleWithHoleMesh<ELEMENT>(cylinder_pt,radius,length,up_length,nup,
948  down_length,ndown,
949  width_near_cylinder,
950  ncolumn,time_stepper_pt)
951  {
952 
953  // Nodal positions etc. were created in constructor for
954  // Cylinder...<...>. Need to setup adaptive information.
955 
956  // Loop over all elements and set macro element pointer
957  for (unsigned e=0;e<(ndown+nup+3);e++)
958  {
959  dynamic_cast<ELEMENT*>(this->element_pt(e))->
960  set_macro_elem_pt(this->Domain_pt->macro_element_pt(e));
961  }
962 
963  // Setup quadtree forest for mesh refinement
964  this->setup_quadtree_forest();
965 
966  // Do one round of uniform refinement to avoid problems
967  // with automatic application of boundary conditions
968  // in subsequent refinements
969  this->refine_uniformly();
970 
971  // Automatically setup the boundary element lookup scheme
972  this->setup_boundary_element_info();
973  }
974 
975 
978 
979 };
980 
981 }
982 #endif
AnnoyingScalar cos(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:136
AnnoyingScalar sin(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:137
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
Array< double, 1, 3 > e(1./3., 0.5, 2.)
Scalar * b
Definition: benchVecAdd.cpp:17
Matrix< SCALARA, Dynamic, Dynamic, opt_A > A
Definition: bench_gemm.cpp:47
Matrix< SCALARB, Dynamic, Dynamic, opt_B > B
Definition: bench_gemm.cpp:48
The matrix class, also used for vectors and row-vectors.
Definition: Eigen/Eigen/src/Core/Matrix.h:186
void position(const Vector< double > &xi, Vector< double > &r) const
Definition: extrude_with_macro_element_representation.cc:78
Definition: domain.h:67
Definition: geom_objects.h:101
My own Ellipse class.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:40
double & b()
Access to z-half axis.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:68
void position(const Vector< double > &xi, Vector< double > &r) const
Return the position of the Half Ellipse.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:54
double Centre_z
z-coordinate of centre
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:74
HalfEllipse(const double &centre_z, const double &a, const double &b)
Constructor.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:45
double B
z-half axis
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:80
~HalfEllipse()
Destructor (empty)
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:51
double & centre_z()
Access to z-coordinate of centre.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:62
double & a()
Access to r-half axis.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:65
double A
r-half axis
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:77
Rectangular domain with Half-elliptical hole.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:96
void macro_element_boundary(const unsigned &time, const unsigned &m, const unsigned &direction, const Vector< double > &s, Vector< double > &f)
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:214
Vector< Vector< Vector< double > > > Up
Left and right side of lines in the upstream region.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:541
unsigned Nup
Number of upstream macro elements.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:550
~HalfRectangleWithHoleDomain()
Destructor: Empty; cleanup done in base class.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:195
void linear_interpolate(Vector< double > left, Vector< double > right, const double &s, Vector< double > &f)
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:200
Vector< Vector< Vector< double > > > Down
Left and right side of lines in the downstream region.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:544
unsigned Ncolumn
Number of columns.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:556
GeomObject * Cylinder_pt
Pointer to geometric object that represents the central cylinder.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:547
HalfRectangleWithHoleDomain(GeomObject *cylinder_pt, const double &radius, const double &length, const double &up_length, const unsigned &nup, const double &down_length, const unsigned &ndown, const double &width_near_cylinder, const unsigned &ncolumn)
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:106
unsigned Ndown
Number of downstream macro elements.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:553
Domain-based mesh for rectangular mesh with circular hole.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:573
HalfRectangleWithHoleDomain * Domain_pt
Pointer to the domain.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:909
HalfRectangleWithHoleDomain * domain_pt()
Access function to the domain.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:904
HalfRectangleWithHoleMesh(GeomObject *cylinder_pt, const double &radius, const double &length, const double &up_length, const unsigned &nup, const double &down_length, const unsigned &ndown, const double &width_near_cylinder, const unsigned &ncolumn, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:584
Definition: matrices.h:74
Definition: mesh.h:67
static Steady< 0 > Default_TimeStepper
The Steady Timestepper.
Definition: mesh.h:75
Definition: nodes.h:906
Definition: oomph_definitions.h:222
Definition: macro_element.h:279
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:927
virtual ~RefineableHalfRectangleWithHoleMesh()
Destructor: Empty.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:977
RefineableHalfRectangleWithHoleMesh(GeomObject *cylinder_pt, const double &radius, const double &length, const double &up_length, const unsigned &nup, const double &down_length, const unsigned &ndown, const double &width_near_cylinder, const unsigned &ncolumn, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:936
Definition: refineable_quad_mesh.h:53
Definition: timesteppers.h:231
static int f(const TensorMap< Tensor< int, 3 > > &tensor)
Definition: cxx11_tensor_map.cpp:237
RealScalar s
Definition: level1_cplx_impl.h:130
const Scalar * a
Definition: level2_cplx_impl.h:32
int * m
Definition: level2_cplx_impl.h:294
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 atan(const bfloat16 &a)
Definition: BFloat16.h:636
OscillatingCylinder * Cylinder_pt
---------------------------------—TIME-INTEGRATION PARAMETERS---—
Definition: extrude_with_macro_element_representation.cc:248
r
Definition: UniformPSDSelfTest.py:20
radius
Definition: UniformPSDSelfTest.py:15
@ E
Definition: quadtree.h:61
@ S
Definition: quadtree.h:62
@ W
Definition: quadtree.h:63
@ N
Definition: quadtree.h:60
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2