b_convection_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 //===========================================================
95 class HalfRectangleWithHoleDomain : public Domain
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 
200  const double &s, Vector<double> &f)
201  {
202  for(unsigned i=0;i<2;i++)
203  {
204  f[i] = left[i] + (right[i] - left[i])*0.5*(s+1.0);
205  }
206  }
207 
208 
209 
213  void macro_element_boundary(const unsigned &time,
214  const unsigned &m,
215  const unsigned &direction,
216  const Vector<double> &s,
217  Vector<double>& f)
218  {
219  // Lagrangian coordinate along surface of cylinder
220  Vector<double> xi(1);
221 
222  // Point on circle
223  Vector<double> point_on_circle(2);
224 
225  //Upstream region all rectangular blocks
226  if(m < Nup)
227  {
228  //Switch on the direction
229 
230  switch(direction)
231  {
232  case N:
233  linear_interpolate(Up[0][m+1],Up[1][m+1],s[0],f);
234  break;
235 
236  case S:
237  linear_interpolate(Up[0][m],Up[1][m],s[0],f);
238  break;
239 
240  case W:
241  linear_interpolate(Up[0][m],Up[0][m+1],s[0],f);
242  break;
243 
244  case E:
245  linear_interpolate(Up[1][m],Up[1][m+1],s[0],f);
246  break;
247 
248  default:
249 
250  std::ostringstream error_stream;
251  error_stream << "Direction is incorrect: " << direction << std::endl;
252  throw OomphLibError(
253  error_stream.str(),
256  }
257  }
258  //The special cases around the half-domain
259  else if(m < Nup + 3)
260  {
261  //Scale the macro element number
262  unsigned m_mod = m - Nup;
263 
264  //Switch on the macro element
265  switch(m_mod)
266  {
267  //Macro element 0, is is immediately below the cylinder
268  case 0:
269 
270  switch(direction)
271  {
272  case N:
273  xi[0] = 4.0*atan(1.0) - atan(1.0)*0.5*(1.0+s[0]);
274  Cylinder_pt->position(time,xi,f);
275  break;
276 
277  case S:
278  linear_interpolate(Up[0][Nup],Up[1][Nup],s[0],f);
279  break;
280 
281  case W:
282  xi[0] = 4.0*atan(1.0);
283  Cylinder_pt->position(time,xi,point_on_circle);
284  linear_interpolate(Up[0][Nup],point_on_circle,s[0],f);
285  break;
286 
287  case E:
288  xi[0] = 3.0*atan(1.0);
289  Cylinder_pt->position(time,xi,point_on_circle);
290  linear_interpolate(Up[1][Nup],point_on_circle,s[0],f);
291  break;
292 
293  default:
294 
295  std::ostringstream error_stream;
296  error_stream << "Direction is incorrect: " << direction
297  << std::endl;
298  throw OomphLibError(
299  error_stream.str(),
302  }
303 
304  break;
305 
306  //Macro element 1, is immediately to the right the cylinder
307  case 1:
308 
309  switch(direction)
310  {
311  case N:
312  xi[0] = atan(1.0);
313  Cylinder_pt->position(time,xi,point_on_circle);
314  linear_interpolate(point_on_circle,Down[1][0],s[0],f);
315  break;
316 
317  case S:
318  xi[0] = 3.0*atan(1.0);
319  Cylinder_pt->position(time,xi,point_on_circle);
320  linear_interpolate(point_on_circle,Up[1][Nup],s[0],f);
321  break;
322 
323  case W:
324  xi[0] = 3.0*atan(1.0) - 2.0*atan(1.0)*0.5*(1.0+s[0]);
325  Cylinder_pt->position(time,xi,f);
326  break;
327 
328  case E:
329  linear_interpolate(Up[1][Nup],Down[1][0],s[0],f);
330  break;
331 
332  default:
333 
334  std::ostringstream error_stream;
335  error_stream << "Direction is incorrect: " << direction << std::endl;
336  throw OomphLibError(
337  error_stream.str(),
340  }
341 
342  break;
343 
344  //Macro element 2, is immediately above the cylinder
345  case 2:
346 
347  switch(direction)
348  {
349  case N:
350  linear_interpolate(Down[0][0],Down[1][0],s[0],f);
351  break;
352 
353  case S:
354  xi[0] = atan(1.0)*0.5*(1.0+s[0]);
355  Cylinder_pt->position(time,xi,f);
356  break;
357 
358  case W:
359  xi[0] = 0.0;
360  Cylinder_pt->position(time,xi,point_on_circle);
361  linear_interpolate(point_on_circle,Down[0][0],s[0],f);
362  break;
363 
364  case E:
365  xi[0] = atan(1.0);
366  Cylinder_pt->position(time,xi,point_on_circle);
367  linear_interpolate(point_on_circle,Down[1][0],s[0],f);
368  break;
369 
370 
371  default:
372 
373  std::ostringstream error_stream;
374  error_stream << "Direction is incorrect: " << direction << std::endl;
375  throw OomphLibError(error_stream.str(),
378  }
379  break;
380  }
381  } //End of macro elements around the half-cylinder
382  else
383  {
384  //Other cases
385  if(m < Nup+Ndown+3)
386  {
387  unsigned m_mod = m - Nup -3;
388 
389  //Switch on the direction
390 
391  switch(direction)
392  {
393  case N:
394  linear_interpolate(Down[0][m_mod+1],Down[1][m_mod+1],s[0],f);
395  break;
396 
397  case S:
398  linear_interpolate(Down[0][m_mod],Down[1][m_mod],s[0],f);
399  break;
400 
401  case W:
402  linear_interpolate(Down[0][m_mod],Down[0][m_mod+1],s[0],f);
403  break;
404 
405  case E:
406  linear_interpolate(Down[1][m_mod],Down[1][m_mod+1],s[0],f);
407  break;
408 
409  default:
410 
411  std::ostringstream error_stream;
412  error_stream << "Direction is incorrect: " << direction << std::endl;
413  throw OomphLibError(
414  error_stream.str(),
417  }
418  }
419  else if(m < Nup+Ndown+3 + (Ncolumn-1)*(Nup+Ndown+1))
420  {
421  //Work out the modified m
422  unsigned m_col = m - (Nup+Ndown+3);
423  //Work out which column we are in
424  unsigned j_col = 1 + m_col/(Nup+Ndown+1);
425  //Work out the actual vertical position
426  unsigned m_mod = m_col%(Nup+Ndown+1);
427 
428  //If we're in the upstream region
429  if(m_mod < Nup)
430  {
431  switch(direction)
432  {
433  case N:
434  linear_interpolate(Up[j_col][m_mod+1],Up[j_col+1][m_mod+1],s[0],f);
435  break;
436 
437  case S:
438  linear_interpolate(Up[j_col][m_mod],Up[j_col+1][m_mod],s[0],f);
439  break;
440 
441  case W:
442  linear_interpolate(Up[j_col][m_mod],Up[j_col][m_mod+1],s[0],f);
443  break;
444 
445  case E:
446  linear_interpolate(Up[j_col+1][m_mod],Up[j_col+1][m_mod+1],s[0],f);
447  break;
448 
449  default:
450 
451  std::ostringstream error_stream;
452  error_stream << "Direction is incorrect: " << direction << std::endl;
453  throw OomphLibError(
454  error_stream.str(),
457  }
458  }
459  //Otherwise central zone
460  else if(m_mod==Nup)
461  {
462  switch(direction)
463  {
464  case N:
465  linear_interpolate(Down[j_col][0],Down[j_col+1][0],s[0],f);
466  break;
467 
468  case S:
469  linear_interpolate(Up[j_col][Nup],Up[j_col+1][Nup],s[0],f);
470  break;
471 
472  case W:
473  linear_interpolate(Up[j_col][Nup],Down[j_col][0],s[0],f);
474  break;
475 
476  case E:
477  linear_interpolate(Up[j_col+1][Nup],Down[j_col+1][0],s[0],f);
478  break;
479 
480  default:
481 
482  std::ostringstream error_stream;
483  error_stream << "Direction is incorrect: " << direction << std::endl;
484  throw OomphLibError(
485  error_stream.str(),
488  }
489  }
490  else if(m_mod < Nup+Ndown+1)
491  {
492  unsigned m_mod2 = m_mod - Nup -1;
493 
494  //Switch on the direction
495 
496  switch(direction)
497  {
498  case N:
499  linear_interpolate(Down[j_col][m_mod2+1],Down[j_col+1][m_mod2+1],s[0],f);
500  break;
501 
502  case S:
503  linear_interpolate(Down[j_col][m_mod2],Down[j_col+1][m_mod2],s[0],f);
504  break;
505 
506  case W:
507  linear_interpolate(Down[j_col][m_mod2],Down[j_col][m_mod2+1],s[0],f);
508  break;
509 
510  case E:
511  linear_interpolate(Down[j_col+1][m_mod2],Down[j_col+1][m_mod2+1],s[0],f);
512  break;
513 
514  default:
515 
516  std::ostringstream error_stream;
517  error_stream << "Direction is incorrect: " << direction << std::endl;
518  throw OomphLibError(
519  error_stream.str(),
522  }
523  }
524  }
525  else
526  {
527  std::ostringstream error_stream;
528  error_stream << "Wrong macro element number" << m << std::endl;
529  throw OomphLibError(
530  error_stream.str(),
533  }
534  }
535  }
536 
537 private:
538 
541 
544 
547 
549  unsigned Nup;
550 
552  unsigned Ndown;
553 
555  unsigned Ncolumn;
556 
557 };
558 
559 
560 
561 
565 
566 
567 //=============================================================
569 //=============================================================
570 template<class ELEMENT>
571 class HalfRectangleWithHoleMesh : public virtual Mesh
572 {
573 
574 public:
575 
576 
584  const double &radius, const double &length,
585  const double &up_length, const unsigned &nup,
586  const double &down_length, const unsigned &ndown,
587  const double &width_near_cylinder,
588  const unsigned &ncolumn,
589  TimeStepper* time_stepper_pt=
591  {
592  //Create the domain
593  Domain_pt = new HalfRectangleWithHoleDomain(cylinder_pt,radius,length,
594  up_length,nup,down_length,
595  ndown,width_near_cylinder,
596  ncolumn);
597 
598  //Initialise the node counter
599  unsigned long node_count=0;
600 
601  //Vectors used to get data from domains
602  Vector<double> s(2),r(2);
603 
604  //Setup temporary storage for the Node
605  Vector<Node*> Tmp_node_pt;
606 
607  //Now blindly loop over the macro elements and associate and finite
608  //element with each
609  unsigned nmacro_element = Domain_pt->nmacro_element();
610  for(unsigned e=0;e<nmacro_element;e++)
611  {
612  //Create the FiniteElement and add to the Element_pt Vector
613  Element_pt.push_back(new ELEMENT);
614 
615  //Read out the number of linear points in the element
616  unsigned np =
617  dynamic_cast<ELEMENT*>(finite_element_pt(e))->nnode_1d();
618 
619  //Loop over nodes in the column
620  for(unsigned l1=0;l1<np;l1++)
621  {
622  //Loop over the nodes in the row
623  for(unsigned l2=0;l2<np;l2++)
624  {
625  //Allocate the memory for the node
626  Tmp_node_pt.push_back(finite_element_pt(e)->
627  construct_node(l1*np+l2,time_stepper_pt));
628 
629  //Read out the position of the node from the macro element
630  s[0] = -1.0 + 2.0*(double)l2/(double)(np-1);
631  s[1] = -1.0 + 2.0*(double)l1/(double)(np-1);
632  Domain_pt->macro_element_pt(e)->macro_map(s,r);
633 
634  //Set the position of the node
635  Tmp_node_pt[node_count]->x(0) = r[0];
636  Tmp_node_pt[node_count]->x(1) = r[1];
637 
638  //Increment the node number
639  node_count++;
640  }
641  }
642  } //End of loop over macro elements
643 
644  //Now the elements have been created, but there will be nodes in
645  //common, need to loop over the common edges and sort it, by reassigning
646  //pointers and the deleting excess nodes
647 
648  //Read out the number of linear points in the element
649  unsigned np=dynamic_cast<ELEMENT*>(finite_element_pt(0))->nnode_1d();
650 
651  //Edges between the upstream elements including that immediately below
652  //the cylinder
653  for(unsigned m=0;m<(nup+1);m++)
654  {
655  //Edge between Elements m and m+1
656  for(unsigned n=0;n<np;n++)
657  {
658  //Set the nodes in element m+1 to be the same as in element m
659  finite_element_pt(m+1)->node_pt(n)
660  = finite_element_pt(m)->node_pt(np*(np-1) + n);
661 
662  //Remove the nodes in element m+1 from the temporary node list
663  delete Tmp_node_pt[(m+1)*np*np + n];
664  Tmp_node_pt[(m+1)*np*np + n] = 0;
665  }
666  }
667 
668  //Edge between Elements nup and nup+1
669  for(unsigned n=0;n<np;n++)
670  {
671  //Set the nodes in element nup+1 to be the same as in element nup
672  finite_element_pt(nup+1)->node_pt(n)
673  = finite_element_pt(nup)->node_pt((np-n-1)*np + (np-1));
674 
675  //Remove the nodes in element nup+1 from the temporary node list
676  delete Tmp_node_pt[(nup+1)*np*np + n];
677  Tmp_node_pt[(nup+1)*np*np + n] = 0;
678  }
679 
680  //Edge between Element nup+1 and nup2
681  for(unsigned n=0;n<np;n++)
682  {
683  //Set the nodes in element nup+2 to be the same as in element nup+1
684  finite_element_pt(nup+2)->node_pt(np*n + np-1)
685  = finite_element_pt(nup+1)->node_pt(np*(np-1) + n);
686 
687  //Remove the nodes in element nup+2 from the temporary node list
688  delete Tmp_node_pt[(nup+2)*np*np + np*n + np-1];
689  Tmp_node_pt[(nup+2)*np*np + np*n + np-1] = 0;
690  }
691 
692  //Edges between the downstream elements including that immediately above
693  //the cylinder
694  for(unsigned m=nup+2;m<(nup+2+ndown);m++)
695  {
696  //Edge between Elements m and m+1
697  for(unsigned n=0;n<np;n++)
698  {
699  //Set the nodes in element m+1 to be the same as in element m
700  finite_element_pt(m+1)->node_pt(n)
701  = finite_element_pt(m)->node_pt(np*(np-1) + n);
702 
703  //Remove the nodes in element m+1 from the temporary node list
704  delete Tmp_node_pt[(m+1)*np*np + n];
705  Tmp_node_pt[(m+1)*np*np + n] = 0;
706  }
707  }
708 
709 
710  //Now we need to sort out all the edges between the remaining columns
711  //and rows
712  bool first_col=true;
713 
714  unsigned left_col_offset = 0;
715  unsigned right_col_offset = nup+ndown+3;
716  //Loop over the columns
717  for(unsigned j=1;j<ncolumn;j++)
718  {
719  for(unsigned i=0;i<(nup+ndown+1);i++)
720  {
721  //Sort out the left-hand boundary of elements
722  for(unsigned n=0;n<np;n++)
723  {
724  finite_element_pt(right_col_offset)->node_pt(n*np)
725  = finite_element_pt(left_col_offset)->node_pt(n*np + np-1);
726 
727  //Remove the nodes in the element from the temporary node list
728  delete Tmp_node_pt[right_col_offset*np*np + n*np];
729  Tmp_node_pt[right_col_offset*np*np + n*np] = 0;
730  }
731 
732 
733  //Sort out the bottom of the element
734  if(i!=(nup+ndown))
735  {
736  for(unsigned n=1;n<np;n++)
737  {
738  finite_element_pt(right_col_offset+1)->node_pt(n)
739  = finite_element_pt(right_col_offset)->node_pt((np-1)*np + n);
740 
741  //Remove the nodes in the element from the temporary node list
742  delete Tmp_node_pt[(right_col_offset+1)*np*np + n];
743  Tmp_node_pt[(right_col_offset+1)*np*np + n] = 0;
744  }
745  }
746 
747  ++right_col_offset; ++left_col_offset;
748  //Add another offset if the first column
749  if(first_col==true)
750  {
751  if((i==nup-1) || (i==nup)) {++left_col_offset;}
752  }
753  }
754  if(j==1) {first_col=false;}
755  }
756 
757 
758  //Now set the actual true nodes
759  for(unsigned long n=0;n<node_count;n++)
760  {
761  if(Tmp_node_pt[n]!=0) {Node_pt.push_back(Tmp_node_pt[n]);}
762  }
763 
764  //Finally set the nodes on the boundaries
765  set_nboundary(5);
766 
767  //Find the offset for the right hand side
768  unsigned rhs_offset=0;
769  if(ncolumn > 1) {rhs_offset = nup+ndown+3 + (ncolumn-2)*(nup+ndown+1);}
770 
771  for(unsigned n=0;n<np;n++)
772  {
773  //First part of left hand side
774  Node* nod_pt=finite_element_pt(0)->node_pt(n*np);
775  convert_to_boundary_node(nod_pt);
776  add_boundary_node(3,nod_pt);
777 
778  //Part of LHS immediately after hole
779  nod_pt=finite_element_pt(nup+2)->node_pt(n*np);
780  convert_to_boundary_node(nod_pt);
781  add_boundary_node(3,nod_pt);
782 
783  //First part of right hand side
784  nod_pt=finite_element_pt(rhs_offset)->node_pt(n*np + np-1);
785  convert_to_boundary_node(nod_pt);
786  add_boundary_node(1,nod_pt);
787 
788  //First part of lower boundary
789  nod_pt=finite_element_pt(0)->node_pt(n);
790  convert_to_boundary_node(nod_pt);
791  add_boundary_node(0,nod_pt);
792 
793  //First part of upper boundary
794  nod_pt=finite_element_pt(nup+ndown+2)->node_pt(np*(np-1)+n);
795  convert_to_boundary_node(nod_pt);
796  add_boundary_node(2,nod_pt);
797 
798  //First part of hole boundary
799  nod_pt=finite_element_pt(nup)->node_pt(np*(np-1)+n);
800  convert_to_boundary_node(nod_pt);
801  add_boundary_node(4,nod_pt);
802  }
803 
804  //Upstream section
805  for(unsigned n=1;n<np;n++)
806  {
807  for(unsigned m=1;m<nup;m++)
808  {
809  //Next part of left hand side
810  Node* nod_pt=finite_element_pt(m)->node_pt(n*np);
811  convert_to_boundary_node(nod_pt);
812  add_boundary_node(3,nod_pt);
813 
814  //Next part of right hand side
815  nod_pt=finite_element_pt(rhs_offset + m)->node_pt(n*np + np-1);
816  convert_to_boundary_node(nod_pt);
817  add_boundary_node(1,nod_pt);
818  }
819 
820  //Next part of hole
821  Node* nod_pt=finite_element_pt(nup+1)->node_pt(n*np);
822  convert_to_boundary_node(nod_pt);
823  add_boundary_node(4,nod_pt);
824  }
825 
826  //Need to take care with the region around the hole in the special
827  //case of a single column
828  unsigned rhs_extra_offset=1;
829  if(ncolumn>1) {rhs_extra_offset=0;}
830  for(unsigned n=1;n<np;n++)
831  {
832  //Next two parts of left boundary
833  Node* nod_pt=finite_element_pt(nup)->node_pt(n*np);
834  convert_to_boundary_node(nod_pt);
835  add_boundary_node(3,nod_pt);
836 
837  // Next part of right boundary
838  nod_pt=finite_element_pt(rhs_offset + rhs_extra_offset + nup)
839  ->node_pt(n*np + np-1);
840  convert_to_boundary_node(nod_pt);
841  add_boundary_node(1,nod_pt);
842 
843  //Final part of hole boundary
844  nod_pt=finite_element_pt(nup+2)->node_pt(np-1-n);
845  convert_to_boundary_node(nod_pt);
846  add_boundary_node(4,nod_pt);
847  }
848 
849  //Downstream section
850  for(unsigned n=1;n<np;n++)
851  {
852  for(unsigned m=nup+3;m<(nup+ndown+3);m++)
853  {
854  //Next part of left hand side
855  Node* nod_pt=finite_element_pt(m)->node_pt(n*np);
856  convert_to_boundary_node(nod_pt);
857  add_boundary_node(3,nod_pt);
858 
859  //Next part of right hand side
860  if(rhs_offset==0)
861  {
862  nod_pt=finite_element_pt(m)->node_pt(n*np + np-1);
863  convert_to_boundary_node(nod_pt);
864  add_boundary_node(1,nod_pt);
865  }
866  }
867  if(rhs_offset!=0)
868  {
869  for(unsigned m=nup+1;m<(nup+ndown+1);m++)
870  {
871  Node* nod_pt=finite_element_pt(rhs_offset + m)->node_pt(n*np + np-1);
872  convert_to_boundary_node(nod_pt);
873  add_boundary_node(1,nod_pt);
874  }
875  }
876  }
877 
878  //Upper and Lower boundaries
879  unsigned lower_index = nup + ndown + 3;
880  for(unsigned j=1;j<ncolumn;j++)
881  {
882  for(unsigned n=1;n<np;n++)
883  {
884  Node* nod_pt = finite_element_pt(lower_index)->node_pt(n);
885  convert_to_boundary_node(nod_pt);
886  add_boundary_node(0,nod_pt);
887 
888  nod_pt =
889  finite_element_pt(lower_index+nup+ndown)->node_pt(np*(np-1) + n);
890  convert_to_boundary_node(nod_pt);
891  add_boundary_node(2,nod_pt);
892  }
893  lower_index += nup+ndown+1;
894  }
895 
896 
897  //Setup the info
898  this->setup_boundary_element_info();
899 
900  }
901 
903  HalfRectangleWithHoleDomain* domain_pt() {return Domain_pt;}
904 
905 protected:
906 
908  HalfRectangleWithHoleDomain* Domain_pt;
909 
910 };
911 
912 
916 
917 
918 //===================================================================
922 //===================================================================
923 template<class ELEMENT>
924 class RefineableHalfRectangleWithHoleMesh :
925  public HalfRectangleWithHoleMesh<ELEMENT>, public RefineableQuadMesh<ELEMENT>
926 {
927 public:
928 
936  const double &radius,
937  const double &length,
938  const double &up_length,
939  const unsigned &nup,
940  const double &down_length,
941  const unsigned &ndown,
942  const double &width_near_cylinder,
943  const unsigned &ncolumn,
944  TimeStepper* time_stepper_pt=
946  HalfRectangleWithHoleMesh<ELEMENT>(cylinder_pt,radius,length,up_length,nup,
947  down_length,ndown,
948  width_near_cylinder,
949  ncolumn,time_stepper_pt)
950  {
951 
952  // Nodal positions etc. were created in constructor for
953  // Cylinder...<...>. Need to setup adaptive information.
954 
955  // Loop over all elements and set macro element pointer
956  for (unsigned e=0;e<(ndown+nup+3);e++)
957  {
958  dynamic_cast<ELEMENT*>(this->element_pt(e))->
959  set_macro_elem_pt(this->Domain_pt->macro_element_pt(e));
960  }
961 
962  // Setup quadtree forest for mesh refinement
963  this->setup_quadtree_forest();
964 
965  // Do one round of uniform refinement to avoid problems
966  // with automatic application of boundary conditions
967  // in subsequent refinements
968  this->refine_uniformly();
969 
970  // Automatically setup the boundary element lookup scheme
971  this->setup_boundary_element_info();
972  }
973 
974 
977 
978 };
979 
980 }
981 #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 simulation can be subdivided into Domain's used in parallel code.
Definition: Domain.h:42
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: geom_objects.h:101
double & b()
Access to z-half axis.
Definition: b_convection_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: b_convection_sphere/half_rectangle_with_hole_mesh.h:54
HalfEllipse(const double &centre_z, const double &a, const double &b)
Constructor.
Definition: b_convection_sphere/half_rectangle_with_hole_mesh.h:45
~HalfEllipse()
Destructor (empty)
Definition: b_convection_sphere/half_rectangle_with_hole_mesh.h:51
double & centre_z()
Access to z-coordinate of centre.
Definition: b_convection_sphere/half_rectangle_with_hole_mesh.h:62
double & a()
Access to r-half axis.
Definition: b_convection_sphere/half_rectangle_with_hole_mesh.h:65
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: b_convection_sphere/half_rectangle_with_hole_mesh.h:213
~HalfRectangleWithHoleDomain()
Destructor: Empty; cleanup done in base class.
Definition: b_convection_sphere/half_rectangle_with_hole_mesh.h:195
void linear_interpolate(Vector< double > left, Vector< double > right, const double &s, Vector< double > &f)
Definition: b_convection_sphere/half_rectangle_with_hole_mesh.h:199
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: b_convection_sphere/half_rectangle_with_hole_mesh.h:106
Domain-based mesh for rectangular mesh with circular hole.
Definition: axisym_heat_sphere/half_rectangle_with_hole_mesh.h:573
HalfRectangleWithHoleDomain * domain_pt()
Access function to the domain.
Definition: b_convection_sphere/half_rectangle_with_hole_mesh.h:903
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: b_convection_sphere/half_rectangle_with_hole_mesh.h:583
Definition: matrices.h:74
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
virtual ~RefineableHalfRectangleWithHoleMesh()
Destructor: Empty.
Definition: b_convection_sphere/half_rectangle_with_hole_mesh.h:976
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: b_convection_sphere/half_rectangle_with_hole_mesh.h:935
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