navier_stokes_elements_with_singularity.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 //Header file for Navier Stokes elements with singularity
27 #ifndef OOMPH_NAVIER_STOKES_ELEMENTS_WITH_SINGULARITY_HEADER
28 #define OOMPH_NAVIER_STOKES_ELEMENTS_WITH_SINGULARITY_HEADER
29 
30 
34 
35 namespace oomph
36 {
37 
38 //==================CLASS FOR THE ADDITIONAL UNKNOWN==================
61 //=====================================================================
62 template<class WRAPPED_NAVIER_STOKES_ELEMENT>
64 {
65 
66  public:
67 
70  (const Vector<double>& x);
71 
73  typedef Vector<Vector<double> > (*NavierStokesGradVelocitySingularFctPt)
74  (const Vector<double>& x);
75 
78  (const Vector<double>& x);
79 
82  (const Vector<double>& x);
83 
86  {
87  // Initialise Function pointer to velocity singular function to NULL
89 
90  // Initialise Function pointer to gradient of velocity singular
91  // function to NULL
93 
94  // Initialise Function pointer to pressure singular function to NULL
96 
97  // Initialise Function pointer to gradient of pressure singular
98  // function to NULL
100 
101  // Initalise pointer to the wrapped Navier-Stokes element which will be
102  // used to compute the residual and which includes the point O
104 
105  // Initialise the pointer to the direction of the derivative used
106  // for the residual of this element
107  Direction_pt=0;
108 
109  // Safe assumption: Singular fct does not satisfy Stokes eqn
111 
112  // Create a single item of internal Data, storing one unknown which
113  // represents the unknown C.
114  add_internal_data(new Data(1));
115  }
116 
120  {
122  }
123 
125  double c() const
126  {
127  return internal_data_pt(0)->value(0);
128  }
129 
130 
132  void set_c(const double& value)
133  {
135  }
136 
138  void pin_c()
139  {
140  return internal_data_pt(0)->pin(0);
141  }
142 
144  void unpin_c()
145  {
146  return internal_data_pt(0)->unpin(0);
147  }
148 
155  (WRAPPED_NAVIER_STOKES_ELEMENT* wrapped_navier_stokes_el_pt,
156  const Vector<double>& s,
157  unsigned* direction_pt)
158  {
159  // Assign the pointer to the variable Wrapped_navier_stokes_el_pt
160  Wrapped_navier_stokes_el_pt = wrapped_navier_stokes_el_pt;
161 
162  // Find number of nodes in the element
163  unsigned nnod=wrapped_navier_stokes_el_pt->nnode();
164 
165  // Loop over the nodes of the element
166  for (unsigned j=0;j<nnod;j++)
167  {
168  // Add the node as external data in the
169  // SingularNavierStokesSolutionElement class. Note that this
170  // assumes that the pressure is stored at the nodes (Taylor Hood type
171  // NSt elements, which is assumed elsewhere too...)
173  }
174 
175  // Assign the pointer to the local coordinate at which the residual
176  // will be computed
178 
179  // Assign the pointer to the direction at which the derivative used
180  // in the residual will be computed
181  Direction_pt = direction_pt;
182  }
183 
186  {return Velocity_singular_fct_pt;}
187 
191 
194  {return Pressure_singular_fct_pt;}
195 
199 
202  {
203 #ifdef PARANOID
205  {
206  std::stringstream error_stream;
207  error_stream
208  << "Pointer to velocity singular function hasn't been defined!"
209  << std::endl;
210  throw OomphLibError(
211  error_stream.str(),
214  }
215 #endif
216 
217  // Evaluate velocity singular function
218  return (*Velocity_singular_fct_pt)(x);
219  }
220 
224  const Vector<double>& x) const
225  {
226 #ifdef PARANOID
228  {
229  std::stringstream error_stream;
230  error_stream
231  << "Pointer to gradient of velocity singular function "
232  << "hasn't been defined!"
233  << std::endl;
234  throw OomphLibError(
235  error_stream.str(),
238  }
239 #endif
240 
241  // Evaluate gradient of velocity singular function
242  return (*Grad_velocity_singular_fct_pt)(x);
243  }
244 
247  {
248 #ifdef PARANOID
250  {
251  std::stringstream error_stream;
252  error_stream
253  << "Pointer to pressure singular function hasn't been defined!"
254  << std::endl;
255  throw OomphLibError(
256  error_stream.str(),
259  }
260 #endif
261 
262  // Evaluate pressure singular function
263  return (*Pressure_singular_fct_pt)(x);
264  }
265 
268  {
269 #ifdef PARANOID
271  {
272  std::stringstream error_stream;
273  error_stream
274  << "Pointer to gradient of pressure singular function "
275  << "hasn't been defined!"
276  << std::endl;
277  throw OomphLibError(
278  error_stream.str(),
281  }
282 #endif
283 
284  // Evaluate gradient of pressure singular function
285  return (*Grad_pressure_singular_fct_pt)(x);
286  }
287 
291  {
292  // Find the value of C
293  double c=internal_data_pt(0)->value(0);
294 
295  // Initialise the velocity vector
297 
298  // Find the dimension of the problem
299  unsigned cached_dim=Wrapped_navier_stokes_el_pt->dim();
300 
301  // Multiply the components of the velocity vector by the unknown C
302  for (unsigned d=0;d<cached_dim;d++)
303  {
304  u[d] *= c;
305  }
306 
307  // Value of u_bar at the position x
308  return u;
309  }
310 
316  {
317  // Find the value of C
318  double c=internal_data_pt(0)->value(0);
319 
320  // Initialise the gradient of velocity vector
322 
323  // Find the dimension of the problem
324  unsigned cached_dim=Wrapped_navier_stokes_el_pt->dim();
325 
326  // Multiply the components of the gradient of velocity by the unknown C
327  for (unsigned d=0;d<cached_dim;d++)
328  {
329  for (unsigned i=0;i<cached_dim;i++)
330  {
331  grad_u[d][i] *= c;
332  }
333  }
334 
335  // Value of grad_u_bar at the position x
336  return grad_u;
337  }
338 
341  double p_bar(const Vector<double>& x)
342  {
343  // Find the value of C
344  double c=internal_data_pt(0)->value(0);
345 
346  // Value of p_bar at the position x
348  }
349 
354  {
355  // Find the value of C
356  double c=internal_data_pt(0)->value(0);
357 
358  // Initialise the gradient of pressure
360 
361  // Find the dimension of the problem
362  unsigned cached_dim=Wrapped_navier_stokes_el_pt->dim();
363 
364  // Multiply the components of the gradient of pressure by the unknown C
365  for (unsigned d=0;d<cached_dim;d++)
366  {
367  grad_p[d] *= c;
368  }
369 
370  // Value of grad_p_bar at the position x
371  return grad_p;
372  }
373 
376  {
379  }
380 
381  // Compute local residual and jacobian
383  DenseMatrix<double> &jacobian)
384  {
385  fill_in_generic_contribution_to_residuals(residual,jacobian,1);
386  }
387 
388  private:
389 
392  DenseMatrix<double> &jacobian,
393  const unsigned& flag)
394  {
395  // Get the local eqn number of our one-and-only
396  // unknown
398  if (eqn_number>=0)
399  {
400  residual[eqn_number] = Wrapped_navier_stokes_el_pt->dpdx_fe_only
402 
403  // Do we want the Jacobian too?
404  if (flag)
405  {
406  // Find the number of pressure dofs in the wrapped Navier-Stokes
407  // element pointed by
408  // the SingularNavierStokesSolutionElement class
409  unsigned n_pres = Wrapped_navier_stokes_el_pt->npres_nst();
410 
411  // Find the dimension of the problem
412  unsigned cached_dim=Wrapped_navier_stokes_el_pt->dim();
413 
414  // Set up memory for the pressure shape functions and their derivatives
415  Shape psip(n_pres), testp(n_pres);
416  DShape dpsipdx(n_pres,cached_dim), dtestpdx(n_pres,cached_dim);
417 
418  // Compute the pressure shape functions and their derivatives
419  // at the local coordinate S_in_wrapped_navier_stokes_element
420  // (Test fcts not really needed but nobody's got around to writing
421  // a fct that only picks out the basis fcts.
422  Wrapped_navier_stokes_el_pt->dpshape_and_dptest_eulerian_nst
423  (S_in_wrapped_navier_stokes_element,psip,dpsipdx,testp,dtestpdx);
424 
425  // Derivs
426  for (unsigned j=0;j<n_pres;j++)
427  {
428  // Unknown
429  int local_unknown = Wrapped_navier_stokes_el_pt->p_local_eqn(j);
430 
431  // If not pinned
432  if (local_unknown >= 0)
433  {
434  // Add the contribution of the node to the local jacobian
435  jacobian(eqn_number,local_unknown) = dpsipdx(j,*Direction_pt);
436  }
437  }
438  }
439  }
440  }
441 
443  WRAPPED_NAVIER_STOKES_ELEMENT* Wrapped_navier_stokes_el_pt;
444 
447 
451 
454 
457 
460 
462  unsigned* Direction_pt;
463 
464 // Does singular fct satisfy Stokes eqn?
466 
467 }; // End of SingularNavierStokesSolutionElement class
468 
469 
473 
474 
475 //=======================================================================
487 //=======================================================================
488 template<class BASIC_NAVIER_STOKES_ELEMENT>
490 public virtual BASIC_NAVIER_STOKES_ELEMENT
491 {
492 
493  public:
494 
497  {
498 
499  // Find the number of nodes in the element
500  unsigned n_node = this->nnode();
501 
502  // Find the dimension of the problem
503  unsigned cached_dim = this->dim();
504 
505  // Initialise the vector indicating which node is subject to velocity
506  // Dirichlet BCs. The size of the vector is equal to the number of nodes
507  // in the element. Each component of the vector is a vector of booleans
508  // indicating if the velocity components at the corresponding node are
509  // subject to Dirichlet BC. By default, no node is subject to Dirichlet BC,
510  // so the vector is full of false.
512  for (unsigned j=0;j<n_node;j++)
513  {
514  Node_is_subject_to_velocity_dirichlet_bcs[j].resize(cached_dim);
515  for (unsigned d=0;d<cached_dim;d++)
516  {
518  }
519  }
520 
521  // Initialise the vector of imposed velocity values on the nodes
522  // subject to Dirichlet BC. The size of the vector is equal to the
523  // number of nodes in the element. Each component of the vector is
524  // a vector of length the dimension of the problem. This vector contains
525  // the imposed values of the velocity vector at the corresponding node.
526  // If a node is not subject to Dirichlet BC, its imposed values are zero.
527  // By default, no node is subject to Dirichlet BC so the vector is full
528  // of zeros
529  Imposed_velocity_values_at_node.resize(n_node);
530  for (unsigned j=0;j<n_node;j++)
531  {
532  Imposed_velocity_values_at_node[j].resize(cached_dim);
533  for (unsigned d=0;d<cached_dim;d++)
534  {
536  }
537  }
538 
539  // Find the number of pressure dofs
540  unsigned n_pres = this->npres_nst();
541 
542  // Initialise the vector indicating which pressure dof is subject to
543  // Dirichlet BCs. The size of the vector is equal to the number of pressure
544  // dofs in the element. Each component of the vector is a boolean
545  // indicating if the corresponding pressure unknown is subject to Dirichlet
546  // BC. By default, no pressure dof is subject to Dirichlet BC, so the vector
547  // is full of false.
549  for (unsigned l=0;l<n_pres;l++)
550  {
552  }
553 
554  // Initialise the vector of imposed values on the pressure dofs
555  // subject to Dirichlet BC. The size of the vector is equal to the
556  // number of pressure dofs in the element. Each component of
557  // the vector contains the imposed value at the corresponding pressure dof.
558  // If a pressure dof is not subject to Dirichlet BC, its imposed value
559  // is zero. By default, no pressure dof is subject to Dirichlet BC
560  // so the vector is full of zeros
561  Imposed_value_at_pressure_dof.resize(n_node);
562  for (unsigned l=0;l<n_pres;l++)
563  {
565  }
566 
567  } // End of constructor
568 
569 
570 
573  void impose_velocity_dirichlet_bc_on_node(const unsigned& j, const unsigned& d)
574  {
576  }
577 
580  void undo_velocity_dirichlet_bc_on_node(const unsigned& j, const unsigned& d)
581  {
583  }
584 
588  const unsigned& d,
589  const double& value)
590  {
592  }
593 
594 
597  {
599  }
600 
602  void undo_dirichlet_bc_on_pressure_dof(const unsigned& j)
603  {
605  }
606 
609  const double& value)
610  {
612  }
613 
617  {return C_equation_elements_pt;}
618 
626  <BASIC_NAVIER_STOKES_ELEMENT> >* c_pt)
627  {
628  // Add the element
629  C_equation_elements_pt.push_back(c_pt);
630 
631  // Add the additional unknown of this object as external data in the
632  // Navier-Stokes element
633  this->add_external_data(c_pt->internal_data_pt(0));
634  }
635 
636 
638  double dpdx_fe_only(Vector<double> s, const unsigned* direction_pt)
639  {
640  // Find the number of pressure dofs in the wrapped Navier-Stokes
641  // element pointed by
642  // the SingularNavierStokesSolutionElement class
643  unsigned n_pres = this->npres_nst();
644 
645  // Find the dimension of the problem
646  unsigned cached_dim=this->dim();
647 
648  // Set up memory for the pressure shape functions and their derivatives
649  Shape psip(n_pres), testp(n_pres);
650  DShape dpsipdx(n_pres,cached_dim), dtestpdx(n_pres,cached_dim);
651 
652  // Compute the pressure shape functions and their derivatives
653  // at the local coordinate S_in_wrapped_navier_stokes_element
654  // (Test fcts not really needed but nobody's got around to writing
655  // a fct that only picks out the basis fcts.
656  this->dpshape_and_dptest_eulerian_nst
657  (s,psip,dpsipdx,testp,dtestpdx);
658 
659  // Initialise the derivative used for the residual
660  double interpolated_dpdx_fe_only=0.0;
661 
662  // Compute the derivative used for the residual. The direction of the
663  // derivative is given by *Direction_pt
664  for (unsigned j=0;j<n_pres;j++)
665  {
666  interpolated_dpdx_fe_only +=
667  this->p_nst(j)*dpsipdx(j,*direction_pt);
668  }
669 
670  return interpolated_dpdx_fe_only;
671  }
672 
673 
676  {
677  // Call the generic residuals function with flag set to 0
678  // using a dummy matrix argument
680  residuals,
682  0);
683  }
684 
688  DenseMatrix<double> &jacobian)
689  {
690  // Call the generic routine with the flag set to 1 and dummy mass matrix
691  DenseMatrix<double> mass_matrix;
693  jacobian,
694  1);
695 
696  /* // FD version if you want to mess around with anything...*/
697  /* FiniteElement::fill_in_contribution_to_jacobian(residuals,jacobian); */
698  }
699 
702  // u_sing, v_sing, [w_sing], p_sing
703  void output(std::ostream &outfile,const unsigned &nplot)
704  {
705  // Find the dimension of the problem
706  unsigned cached_dim = this->dim();
707 
708  //Vector of local coordinates
709  Vector<double> s(cached_dim);
710 
711  // Tecplot header info
712  outfile << this->tecplot_zone_string(nplot);
713 
714  // Loop over plot points
715  unsigned num_plot_points=this->nplot_points(nplot);
716  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
717  {
718  // Get local coordinates of plot point
719  this->get_s_plot(iplot,nplot,s);
720 
721  Vector<double> x(cached_dim);
722  for(unsigned i=0;i<cached_dim;i++)
723  {
724  outfile << this->interpolated_x(s,i) << " ";
725  x[i] = this->interpolated_x(s,i);
726  }
727 
729  Vector<double> velocity_fe_only = interpolated_u_nst_fe_only(s);
730  for (unsigned i=0;i<cached_dim;i++)
731  {
732  outfile << velocity[i] << " ";
733  }
734  outfile << this->interpolated_p_nst(s) << " ";
735  for (unsigned i=0;i<cached_dim;i++)
736  {
737  outfile << velocity_fe_only[i] << " ";
738  }
739  outfile << this->interpolated_p_nst_fe_only(s) << " ";
740  for (unsigned i=0;i<cached_dim;i++)
741  {
742  outfile << velocity[i] - velocity_fe_only[i] << " ";
743  }
744  outfile
745  << this->interpolated_p_nst(s)-
747  << " " << std::endl;
748 
749  }
750 
751  // Write tecplot footer (e.g. FE connectivity lists)
752  this->write_tecplot_zone_footer(outfile,nplot);
753 
754  }
755 
756 
758 void compute_error(std::ostream &outfile,
760  const bool& include_pressure,
761  double& error, double& norm)
762 {
763 
764  unsigned cached_dim=this->dim();
765 
766  error=0.0;
767  norm=0.0;
768 
769  //Vector of local coordinates
770  Vector<double> s(cached_dim);
771 
772  // Vector for coordintes
773  Vector<double> x(cached_dim);
774 
775  //Set the value of n_intpt
776  unsigned n_intpt = this->integral_pt()->nweight();
777 
778 
779  outfile << "ZONE" << std::endl;
780 
781  // Exact solution Vector (u,v,[w],p)
782  Vector<double> exact_soln(cached_dim+1);
783  Vector<double> computed_soln(cached_dim+1);
784 
785  //Loop over the integration points
786  for(unsigned ipt=0;ipt<n_intpt;ipt++)
787  {
788 
789  //Assign values of s
790  for(unsigned i=0;i<cached_dim;i++)
791  {
792  s[i] = this->integral_pt()->knot(ipt,i);
793  }
794 
795  //Get the integral weight
796  double w = this->integral_pt()->weight(ipt);
797 
798  // Get jacobian of mapping
799  double J=this->J_eulerian(s);
800 
801  //Premultiply the weights and the Jacobian
802  double W = w*J;
803 
804  // Get x position as Vector
805  this->interpolated_x(s,x);
806 
807  // Get exact solution at this point
808  (*exact_soln_pt)(x,exact_soln);
810  for(unsigned i=0;i<cached_dim;i++)
811  {
812  computed_soln[i]=u_comp[i];
813  }
814  unsigned hi_limit=cached_dim;
815  if (include_pressure)
816  {
817  computed_soln[cached_dim]=interpolated_p_nst(s);
818  hi_limit=cached_dim+1;
819  }
820 
821 
822  // Velocity error
823  for(unsigned i=0;i<hi_limit;i++)
824  {
825  norm+=exact_soln[i]*exact_soln[i]*W;
826  error+=(exact_soln[i]-computed_soln[i])*
827  (exact_soln[i]-computed_soln[i])*W;
828  }
829 
830  //Output x,y,...,u_exact,...]
831  for(unsigned i=0;i<cached_dim;i++)
832  {
833  outfile << x[i] << " ";
834  }
835 
836  //Output x,y,[z],u_error,v_error,[w_error], [p_error]
837  for(unsigned i=0;i<hi_limit;i++)
838  {
839  outfile << exact_soln[i]-computed_soln[i] << " ";
840  }
841  outfile << std::endl;
842  }
843 }
844 
845 
849  const
850  {
851  // Find the dimension of the problem
852  unsigned cached_dim=this->dim();
853 
854  //Find number of nodes
855  const unsigned n_node = this->nnode();
856 
857  //Initialise value of u
858  Vector<double> interpolated_u(cached_dim,0.0);
859 
860  // Calculate the global coordinate associated with s
861  Vector<double> x(cached_dim,0.0);
862 
863  //Local shape function
864  Shape psif(n_node);
865 
866  //Find values of shape function
867  this->shape(s,psif);
868 
869  //Loop over the spatial directions
870  for (unsigned d=0;d<cached_dim;d++)
871  {
872  //Get the index at which the unknown is stored
873  const unsigned u_nodal_index = this->u_index_nst(d);
874 
875  //Loop over the local nodes and sum
876  for(unsigned j=0;j<n_node;j++)
877  {
878  interpolated_u[d] += this->nodal_value(j,u_nodal_index)*psif[j];
879  x[d]+=this->raw_nodal_position(j,d)*psif(j);
880  }
881  }
882 
883  // Add the contribution of the singularities (all of them, summed)
884  Vector<double> u_bar_local=u_bar(x);
885  for (unsigned d=0;d<cached_dim;d++)
886  {
887  interpolated_u[d] += u_bar_local[d];
888  }
889  return(interpolated_u);
890  }
891 
893  inline double interpolated_p_nst(const Vector<double>& s) const
894  {
895  // Initialise pressure value with fe part
896  double interpolated_p = interpolated_p_nst_fe_only(s);
897 
898  // Calculate the global coordinate associated with s
899  unsigned cached_dim = this->dim();
900  Vector<double> x(cached_dim,0.0);
901 
902  //Find number of nodes
903  const unsigned n_node = this->nnode();
904 
905  //Local shape function
906  Shape psif(n_node);
907 
908  //Find values of shape function
909  this->shape(s,psif);
910 
911  //Loop over the local nodes and sum
912  for(unsigned j=0;j<n_node;j++)
913  {
914  for (unsigned d=0;d<cached_dim;d++)
915  {
916  x[d]+=this->raw_nodal_position(j,d)*psif(j);
917  }
918  }
919 
920  // Add the singularities contribution (all of them, summed)
921  interpolated_p+=p_bar(x);
922 
923  return interpolated_p;
924 }
925 
926 
927  private:
928 
931  Vector<double> u_bar(const unsigned& i,const Vector<double>& x) const
932  {
933  return C_equation_elements_pt[i]->u_bar(x);
934  }
935 
939  {
940  // Find the number of singularities
941  unsigned n_sing = C_equation_elements_pt.size();
942 
943  // Find the dimension of the problem
944  unsigned cached_dim=this->dim();
945  Vector<double> sum(cached_dim,0.0);
946  for (unsigned s=0;s<n_sing;s++)
947  {
948  Vector<double> u_bar_local=
949  C_equation_elements_pt[s]->u_bar(x);
950  for (unsigned i=0;i<cached_dim;i++)
951  {
952  sum[i]+=u_bar_local[i];
953  }
954  }
955  return sum;
956  }
957 
961  Vector<Vector<double> > grad_u_bar(const unsigned& i,
962  const Vector<double>& x) const
963  {
964  return C_equation_elements_pt[i]->grad_u_bar(x);
965  }
966 
970  {
971  // Find the number of singularities
972  unsigned n_sing = C_equation_elements_pt.size();
973 
974  // Find the dimension of the problem
975  unsigned cached_dim=this->dim();
976  Vector<Vector<double> > sum(cached_dim);
977  for (unsigned i=0;i<cached_dim;i++)
978  {
979  sum[i].resize(cached_dim,0.0);
980  }
981  for (unsigned s=0;s<n_sing;s++)
982  {
983  Vector<Vector<double> > grad_u_bar_local=
984  C_equation_elements_pt[s]->grad_u_bar(x);
985  for (unsigned i=0;i<cached_dim;i++)
986  {
987  for (unsigned j=0;j<cached_dim;j++)
988  {
989  sum[i][j]+=grad_u_bar_local[i][j];
990  }
991  }
992  }
993  return sum;
994  }
995 
996 
999  const Vector<double>& x) const
1000  {
1001  return C_equation_elements_pt[i]->velocity_singular_function(x);
1002  }
1003 
1004 
1008  const Vector<double>& x) const
1009  {
1010  return C_equation_elements_pt[i]->grad_velocity_singular_function(x);
1011  }
1012 
1015  double pressure_singular_function(const unsigned& i,
1016  const Vector<double>& x) const
1017  {
1018  return C_equation_elements_pt[i]->pressure_singular_function(x);
1019  }
1020 
1021 
1024  double p_bar(const unsigned& i,const Vector<double>& x) const
1025  {
1026  return C_equation_elements_pt[i]->p_bar(x);
1027  }
1028 
1031  double p_bar(const Vector<double>& x) const
1032  {
1033  // Find the number of singularities
1034  unsigned n_sing = C_equation_elements_pt.size();
1035 
1036  double sum=0.0;
1037  for (unsigned i=0;i<n_sing;i++)
1038  {
1039  sum+=C_equation_elements_pt[i]->p_bar(x);
1040  }
1041  return sum;
1042  }
1043 
1047  (const Vector<double> &s) const
1048  {
1049  // Find number of nodes
1050  const unsigned n_node = this->nnode();
1051 
1052  // Find the dimension of the problem
1053  unsigned cached_dim = this->dim();
1054 
1055  //Initialise value of u
1056  Vector<double> interpolated_u(cached_dim,0.0);
1057 
1058  //Local shape function
1059  Shape psif(n_node);
1060 
1061  //Find values of shape function
1062  this->shape(s,psif);
1063 
1064  //Loop over the velocity components
1065  for (unsigned d=0;d<cached_dim;d++)
1066  {
1067  //Get the index at which the unknown is stored
1068  const unsigned u_nodal_index = this->u_index_nst(d);
1069 
1070  // Add the contribution of u_FE
1071  //Loop over the local nodes and sum
1072  for(unsigned j=0;j<n_node;j++)
1073  {
1074  interpolated_u[d] += this->nodal_value(j,u_nodal_index)*psif[j];
1075  }
1076  }
1077 
1078  return interpolated_u;
1079  }
1080 
1081 
1085  {
1086  // Find number of pressure degrees of freedom
1087  unsigned n_pres = this->npres_nst();
1088 
1089  // Set up memory for pressure shape and test functions
1090  Shape psip(n_pres), testp(n_pres);
1091 
1092  // Compute the values of the pressure shape and test functions at the
1093  // local coordinate s
1094  this->pshape_nst(s,psip,testp);
1095 
1096  // Initialise pressure value
1097  double interpolated_p = 0.0;
1098 
1099  // Add the contribution of p_FE
1100  // Loop over the pressure dof and sum
1101  for (unsigned l=0;l<n_pres;l++)
1102  {
1103  interpolated_p += this->p_nst(l)*psip[l];
1104  }
1105 
1106  return interpolated_p;
1107  }
1108 
1109 
1112  Vector<double> &residuals,
1113  DenseMatrix<double> &jacobian,
1114  const unsigned& flag)
1115 {
1116  // Get the contribution from the underlying wrapped element first
1117  BASIC_NAVIER_STOKES_ELEMENT::fill_in_generic_residual_contribution_nst
1118  (residuals,jacobian,GeneralisedElement::Dummy_matrix,flag);
1119 
1120  // Find the dimension of the problem
1121  unsigned cached_dim = this->dim();
1122 
1123  // Do all the singular functions satisfy the Stokes eqn?
1124  bool all_singular_functions_satisfy_stokes_equation=true;
1125 
1126  // Find the number of singularities
1127  unsigned n_sing = C_equation_elements_pt.size();
1128 
1129  // Find the local equation number of the additional unknowns
1130  Vector<int> local_equation_number_C(n_sing);
1131  for (unsigned i=0;i<n_sing;i++)
1132  {
1133  local_equation_number_C[i] = this->external_local_eqn(i,0);
1134  if (!(C_equation_elements_pt[i]->
1135  singular_function_satisfies_stokes_equation()))
1136  {
1137  all_singular_functions_satisfy_stokes_equation=false;
1138  }
1139  }
1140 
1141  // Find out how many nodes there are
1142  unsigned n_node = this->nnode();
1143 
1144  // Find out how many pressure dofs there are
1145  unsigned n_pres = this->npres_nst();
1146 
1147  // Find the indices at which the local velocities are stored
1148  Vector<unsigned> u_nodal_index(cached_dim);
1149  for (unsigned d=0;d<cached_dim;d++)
1150  {
1151  u_nodal_index[d] = this->u_index_nst(d);
1152  }
1153 
1154  // integer to store the local equations
1155  int local_eqn=0, local_unknown=0;
1156 
1157  // Check that there's no time-dependence
1158  for (unsigned j=0;j<n_node;j++)
1159  {
1160  if (!(this->node_pt(j)->time_stepper_pt()->is_steady()))
1161  {
1162  std::stringstream error_stream;
1163  error_stream
1164  << "Currently, the NavierStokesElementWithSingularity elements\n"
1165  << "only work for steady problems, but we have detected a\n"
1166  << "non-steady time-stepper for node " << j << ".\n"
1167  << "If your problem is time-dependent you're welcome to \n"
1168  << "volunteer and implement the required functionality in \n\n"
1169  << " NavierStokesElementWithSingularity::fill_in_generic_residual_contribution_wrapped_nst()\n\n"
1170  << std::endl;
1171  throw OomphLibError(
1172  error_stream.str(),
1175  }
1176  }
1177 
1178 
1179 
1180  // Check that ALE is disabled
1181  if (!this->ALE_is_disabled)
1182  {
1183  std::stringstream error_stream;
1184  error_stream
1185  << "Currently, the NavierStokesElementWithSingularity elements\n"
1186  << "only work on fixed meshes, and to check this we require\n"
1187  << "that you assert that this is the case by calling \n\n"
1188  << " NavierStokesElementWithSingularity::disable_ALE()"
1189  << "\n\n\n"
1190  << "for all bulk Navier-Stokes elements.\n"
1191  << "If your mesh is moving you're welcome to volunteer and implement\n"
1192  << "the required functionality in \n\n"
1193  << " NavierStokesElementWithSingularity::fill_in_generic_residual_contribution_wrapped_nst()\n\n"
1194  << std::endl;
1195  throw OomphLibError(
1196  error_stream.str(),
1199  }
1200 
1201 
1202  // Throw an error for now...
1203  if ((!all_singular_functions_satisfy_stokes_equation)&&(flag==1))
1204  {
1205  std::stringstream error_stream;
1206  error_stream
1207  << "Currently, the analytical computation of the Jacobian for the\n"
1208  << "NavierStokesElementWithSingularity elements\n"
1209  << "only work with singular solutions that satisfy the Stokes eqns.\n"
1210  << "Of course, there's no way of checking this, so you'll have to\n"
1211  << "assert that this is the case by calling \n\n"
1212  << " SingularNavierStokesSolutionElement::singular_function_satisfies_stokes_equation()"
1213  << "\n\n\n"
1214  << "for the SingularNavierStokesSolutionElement that specifies the singular functions.\n"
1215  << "If your singular functions do not satisfy the Stokes equations\n"
1216  << "you're welcome to volunteer and implement the required \n"
1217  << "functionality in \n\n"
1218  << " NavierStokesElementWithSingularity::fill_in_generic_residual_contribution_wrapped_nst()\n\n"
1219  << "Fragments of code are already there...\n"
1220  << "Alternatively, use FD-based setup of Jacobian (still there, commented out, in code).\n"
1221  << "The reason this never got implemented is because this case typically only arises\n"
1222  << "when trying to \"blend\" solutions (to give them finite support) and this didn't\n"
1223  << "seem to work too well and was sort of abandoned. Next person to look at this\n"
1224  << "should consider only adding the non-integrated by parts (source-fct-like) terms\n"
1225  << "arising from the singular functions...\n"
1226  << std::endl;
1227  throw OomphLibError(
1228  error_stream.str(),
1231  }
1232 
1233  // Get Physical Variables from Element
1234  // Reynolds number must be multiplied by the density ratio
1235  double scaled_re = this->re()*this->density_ratio();
1236 
1237  // Do we need extra bulk terms?
1238  if ((scaled_re>0.0)||(!all_singular_functions_satisfy_stokes_equation))
1239  {
1240 
1241  // Set up memory for the velocity shape and test functions
1242  Shape psif(n_node), testf(n_node);
1243  DShape dpsifdx(n_node,cached_dim), dtestfdx(n_node,cached_dim);
1244 
1245  // Set up memory for pressure shape and test functions
1246  Shape psip(n_pres), testp(n_pres);
1247 
1248  // Number of integration points
1249  unsigned n_intpt = this->integral_pt()->nweight();
1250 
1251  // Set the vector to hold local coordinates
1252  Vector<double> s(cached_dim);
1253 
1254  // Cachec viscosity ratio
1255  double visc_ratio = this->viscosity_ratio();
1256 
1257  // Loop over the integration points
1258  for (unsigned ipt=0;ipt<n_intpt;ipt++)
1259  {
1260  // Assign values of s
1261  for (unsigned d=0;d<cached_dim;d++)
1262  {
1263  s[d] = this->integral_pt()->knot(ipt,d);
1264  }
1265 
1266  // Get the integral weight
1267  double w = this->integral_pt()->weight(ipt);
1268 
1269  // Call the derivatives of the velocity shape and test functions
1270  double J =
1271  this->dshape_and_dtest_eulerian_at_knot_nst(ipt,psif,dpsifdx,
1272  testf,dtestfdx);
1273 
1274  // Call the pressure shape and test functions
1275  this->pshape_nst(s,psip,testp);
1276 
1277  // Premultiply the weights and the Jacobian
1278  double W = w*J;
1279 
1280  // Initialise the global coordinate and velocity
1281  Vector<double> interpolated_x(cached_dim,0.0);
1282  Vector<double> interpolated_u(cached_dim,0.0);
1283  DenseMatrix<double> interpolated_dudx(cached_dim,cached_dim,0.0);
1284 
1285  // Calculate the global coordinate associated with s
1286  // Loop over nodes
1287  for (unsigned l=0;l<n_node;l++)
1288  {
1289  // Loop over directions
1290  for (unsigned i=0;i<cached_dim;i++)
1291  {
1292  double u_value = this->raw_nodal_value(l,u_nodal_index[i]);
1293  interpolated_u[i] += u_value*psif[l];
1294  interpolated_x[i] += this->raw_nodal_position(l,i)*psif(l);
1295  for(unsigned j=0;j<cached_dim;j++)
1296  {
1297  interpolated_dudx(i,j) += u_value*dpsifdx(l,j);
1298  }
1299  }
1300  }
1301 
1302  // Get sum of singular functions
1303  Vector<double> u_bar_local=this->u_bar(interpolated_x);
1304  Vector<Vector<double> > grad_u_bar_local=this->grad_u_bar(interpolated_x);
1305  double p_bar_local=this->p_bar(interpolated_x);
1306 
1307  // Singular functions
1308  Vector<Vector<double> > u_hat_local(n_sing);
1309  for (unsigned s=0;s<n_sing;s++)
1310  {
1311  u_hat_local[s]=this->velocity_singular_function(s,interpolated_x);
1312  }
1313  Vector<Vector<Vector<double> > > grad_u_hat_local(n_sing);
1314  for (unsigned s=0;s<n_sing;s++)
1315  {
1316  grad_u_hat_local[s]=
1317  this->grad_velocity_singular_function(s,interpolated_x);
1318  }
1319 
1320  // MOMENTUM EQUATIONS
1321  //-------------------
1322 
1323  // Loop over the velocity test functions
1324  for (unsigned l=0;l<n_node;l++)
1325  {
1326  // Loop over the velocity components
1327  for (unsigned i=0;i<cached_dim;i++)
1328  {
1329  // Find its local equation number
1330  local_eqn = this->nodal_local_eqn(l,u_nodal_index[i]);
1331 
1332  // If it is not pinned
1333  if (local_eqn >= 0)
1334  {
1335  // If it is not a Dirichlet BC
1337  {
1338 
1339 
1340  // Linear terms only needed if singular solution doesn't satisfy
1341  //--------------------------------------------------------------
1342  // Stokes eqn
1343  //-----------
1344  if (!all_singular_functions_satisfy_stokes_equation)
1345  {
1346  residuals[local_eqn]+=p_bar_local*dtestfdx(l,i)*W;
1347  for (unsigned k=0;k<cached_dim;k++)
1348  {
1349  residuals[local_eqn] -= visc_ratio*
1350  (grad_u_bar_local[i][k]+this->Gamma[i]*grad_u_bar_local[k][i])
1351  *dtestfdx(l,k)*W;
1352  }
1353  }
1354 
1355 
1356  // Nonlinear term. Always add (unless Re=0)
1357  //-----------------------------------------
1358  if (scaled_re>0.0)
1359  {
1360  // Add singular convective terms
1361  double sum = 0.0;
1362  for (unsigned k=0;k<cached_dim;k++)
1363  {
1364  sum+=u_bar_local[k]*(grad_u_bar_local[i][k]+interpolated_dudx(i,k))
1365  +interpolated_u[k]*grad_u_bar_local[i][k];
1366  }
1367  residuals[local_eqn] -= scaled_re*sum*testf[l]*W;
1368 
1369  }
1370 
1371  // Calculate the jacobian
1372  //-----------------------
1373  if(flag)
1374  {
1375 
1376  if (scaled_re>0.0)
1377  {
1378  // Loop over the singularities and add the
1379  // contributions of the additional
1380  // unknowns associated with them to the
1381  // jacobian if they are not pinned
1382  for (unsigned ss=0;ss<n_sing;ss++)
1383  {
1384  local_unknown=local_equation_number_C[ss];
1385  if (local_unknown>=0)
1386  {
1387  double sum=0.0;
1388  for (unsigned k=0;k<cached_dim;k++)
1389  {
1390  sum+=u_hat_local[ss][k]*(grad_u_bar_local[i][k]+
1391  interpolated_dudx(i,k))+
1392  grad_u_hat_local[ss][i][k]*
1393  (u_bar_local[k]+interpolated_u[k]);
1394  }
1395  jacobian(local_eqn,local_unknown)-=scaled_re*sum*testf[l]*W;
1396  }
1397  }
1398 
1399 
1400  //Loop over the velocity shape functions again
1401  for(unsigned l2=0;l2<n_node;l2++)
1402  {
1403  //Loop over the velocity components again
1404  for(unsigned i2=0;i2<cached_dim;i2++)
1405  {
1406  //If at a non-zero degree of freedom add in the entry
1407  local_unknown = this->nodal_local_eqn(l2,u_nodal_index[i2]);
1408  if(local_unknown >= 0)
1409  {
1410  double sum=0.0;
1411  if (i==i2)
1412  {
1413  for (unsigned k=0;k<cached_dim;k++)
1414  {
1415  sum+=u_bar_local[k]*dpsifdx(l2,k);
1416  }
1417  }
1418  sum+=psif(l2)*grad_u_bar_local[i][i2];
1419 
1420  //Add contribution to Elemental Matrix
1421  jacobian(local_eqn,local_unknown) -=
1422  scaled_re*sum*testf[l]*W;
1423  }
1424  }
1425  }
1426  }
1427  }
1428  } // End of check of the Dirichlet status
1429  } // End of check of the pin status
1430  } // End of loop over velocity components
1431  } // End of loop over test functions
1432 
1433 
1434 
1435  // Linear terms only needed if singular solution doesn't satisfy
1436  //--------------------------------------------------------------
1437  // Stokes eqn
1438  //-----------
1439  if (!all_singular_functions_satisfy_stokes_equation)
1440  {
1441  // Loop over the pressure test functions
1442  for (unsigned l=0;l<n_pres;l++)
1443  {
1444  local_eqn = this->p_local_eqn(l);
1445 
1446  // If not pinned
1447  if (local_eqn >= 0)
1448  {
1449  // If not subject to Dirichlet BC
1451  {
1452  double aux = 0.0;
1453  // Loop over velocity components
1454  for (unsigned k=0;k<cached_dim;k++)
1455  {
1456  aux += grad_u_bar_local[k][k];
1457  }
1458  residuals[local_eqn] += aux*testp[l]*W;
1459  }
1460  }
1461  }
1462  }
1463 
1464  } // End of loop over integration points
1465 
1466 
1467  }
1468 
1469  // VELOCITY DIRICHLET BCS
1470  //-----------------------
1471  Vector<double> u_bar_at_node(cached_dim);
1472  Vector<Vector<double> > u_hat_at_node(n_sing);
1473  for (unsigned i=0;i<n_sing;i++)
1474  {
1475  u_hat_at_node[i].resize(cached_dim);
1476  }
1477 
1478  // Loop over the nodes
1479  for (unsigned l=0;l<n_node;l++)
1480  {
1481  // Find the global coordinate of the node
1482  Vector<double> global_coordinate(cached_dim);
1483  for (unsigned d=0;d<cached_dim;d++)
1484  {
1485  global_coordinate[d] = this->raw_nodal_position(l,d);
1486  }
1487 
1488  // Get singular velocity at node
1489  u_bar_at_node=this->u_bar(global_coordinate);
1490  for (unsigned i=0;i<n_sing;i++)
1491  {
1492  u_hat_at_node[i]=velocity_singular_function(i,global_coordinate);
1493  }
1494 
1495  // Loop over the velocity components
1496  for (unsigned d=0;d<cached_dim;d++)
1497  {
1498  // Find its local equation number
1499  local_eqn = this->nodal_local_eqn(l,u_nodal_index[d]);
1500 
1501  // If it is not pinned
1502  if (local_eqn >= 0)
1503  {
1504  // If it is a Dirichlet boundary condition
1506  {
1507  // Initialise the residual
1508  residuals[local_eqn] = 0.0;
1509 
1510  // Add the contribution of the nodal value
1511  residuals[local_eqn] += this->raw_nodal_value(l,u_nodal_index[d]);
1512 
1513  // Add the contribution of the singularities (all of them, summed)
1514  residuals[local_eqn] += u_bar_at_node[d];
1515 
1516  // Substract the imposed Dirichlet value
1517  residuals[local_eqn] -= Imposed_velocity_values_at_node[l][d];
1518 
1519  if (flag)
1520  {
1521 
1522  // Wipe the existing entries
1523  unsigned n_dof=this->ndof();
1524  for (unsigned j=0;j<n_dof;j++)
1525  {
1526  jacobian(local_eqn,j)=0.0;
1527  }
1528 
1529  // Add diagonal entry
1530  jacobian(local_eqn,local_eqn) += 1.0;
1531 
1532 
1533  // Add derivative w.r.t. the Cs
1534  for (unsigned i=0;i<n_sing;i++)
1535  {
1536  // Find the contribution of the additional unknowns to
1537  // the jacobian
1538  local_unknown=local_equation_number_C[i];
1539  if (local_unknown>=0)
1540  {
1541  jacobian(local_eqn,local_unknown) +=
1542  u_hat_at_node[i][d];
1543  }
1544  }
1545 
1546  }
1547  }
1548  }
1549  }
1550  }
1551 
1552 
1553  // PRESSURE DIRICHLET BCS
1554  //-----------------------
1555 
1556  // Loop over the pressure dofs
1557  for (unsigned l=0;l<n_pres;l++)
1558  {
1559  // Find its local equation number
1560  local_eqn = this->p_local_eqn(l);
1561 
1562  // If it is not pinned
1563  if (local_eqn >= 0)
1564  {
1565  // If it is subject to a Dirichlet BC
1567  {
1568  // Find its global coordinate
1569  // This conversionly works for Taylor Hood type elements
1570  // but there's not much point assigning pressure dofs
1571  Node* p_nod_pt=this->node_pt(this->Pconv[l]);
1572 
1573  oomph_info << "Constrained pressure node: "
1574  << this->Pconv[l] << " at: ";
1575 
1576  Vector<double> global_coordinate(cached_dim,0.0);
1577  for (unsigned d=0;d<cached_dim;d++)
1578  {
1579  global_coordinate[d] = p_nod_pt->x(d);
1580  oomph_info << global_coordinate[d] << " ";
1581  }
1582  oomph_info << std::endl;
1583 
1584  // Initialise its residual component
1585  residuals[local_eqn] = 0.0;
1586 
1587  // Add the contribution of the pressure unknown
1588  residuals[local_eqn] += this->p_nst(l);
1589 
1590  // Add singular contributions
1591  residuals[local_eqn] += p_bar(global_coordinate);
1592 
1593  // Substract the imposed pressure value
1594  residuals[local_eqn] -= Imposed_value_at_pressure_dof[l];
1595 
1596  if (flag)
1597  {
1598 
1599  // Wipe the existing entries
1600  unsigned n_dof=this->ndof();
1601  for (unsigned j=0;j<n_dof;j++)
1602  {
1603  jacobian(local_eqn,j)=0.0;
1604  }
1605 
1606  // Add diagonal entry
1607  jacobian(local_eqn,local_eqn) += 1.0;
1608 
1609  // Add derivative w.r.t. the Cs
1610  for (unsigned i=0;i<n_sing;i++)
1611  {
1612  // Find the contribution of the additional unknowns to
1613  // the jacobian
1614  local_unknown=local_equation_number_C[i];
1615  if (local_unknown>=0)
1616  {
1617  jacobian(local_eqn,local_unknown) +=
1618  pressure_singular_function(i,global_coordinate);
1619  }
1620  }
1621  }
1622  }
1623  }
1624  }
1625 
1626 
1627  } // End of function
1628 
1629 
1630 
1634 
1639 
1644 
1648 
1653 
1654 }; // End of NavierStokesElementWithSingularity class
1655 
1656 }
1657 
1658 #endif
int i
Definition: BiCGSTAB_step_by_step.cpp:9
JacobiRotation< float > J
Definition: Jacobi_makeJacobi.cpp:3
RowVector3d w
Definition: Matrix_resize_int.cpp:3
Definition: shape.h:278
Definition: nodes.h:86
void pin(const unsigned &i)
Pin the i-th stored variable.
Definition: nodes.h:385
void unpin(const unsigned &i)
Unpin the i-th stored variable.
Definition: nodes.h:391
void set_value(const unsigned &i, const double &value_)
Definition: nodes.h:271
double value(const unsigned &i) const
Definition: nodes.h:293
void(* SteadyExactSolutionFctPt)(const Vector< double > &, Vector< double > &)
Definition: elements.h:1759
Definition: elements.h:73
unsigned long eqn_number(const unsigned &ieqn_local) const
Definition: elements.h:704
Data *& internal_data_pt(const unsigned &i)
Return a pointer to i-th internal data object.
Definition: elements.h:622
unsigned add_external_data(Data *const &data_pt, const bool &fd=true)
Definition: elements.cc:307
int internal_local_eqn(const unsigned &i, const unsigned &j) const
Definition: elements.h:267
static DenseMatrix< double > Dummy_matrix
Definition: elements.h:227
unsigned add_internal_data(Data *const &data_pt, const bool &fd=true)
Definition: elements.cc:62
Definition: navier_stokes_elements_with_singularity.h:491
Vector< double > interpolated_u_nst_fe_only(const Vector< double > &s) const
Definition: navier_stokes_elements_with_singularity.h:1047
void undo_dirichlet_bc_on_pressure_dof(const unsigned &j)
Undo Dirichlet BC at the j-th pressure dof.
Definition: navier_stokes_elements_with_singularity.h:602
void add_c_equation_element_pt(SingularNavierStokesSolutionElement< NavierStokesElementWithSingularity< BASIC_NAVIER_STOKES_ELEMENT > > *c_pt)
Definition: navier_stokes_elements_with_singularity.h:624
double pressure_singular_function(const unsigned &i, const Vector< double > &x) const
Definition: navier_stokes_elements_with_singularity.h:1015
void set_dirichlet_value_on_pressure_dof(const unsigned &j, const double &value)
Specify Dirichlet boundary value for the j-th pressure dof.
Definition: navier_stokes_elements_with_singularity.h:608
Vector< Vector< double > > Imposed_velocity_values_at_node
Definition: navier_stokes_elements_with_singularity.h:1643
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Add the element's contribution to its residual vector (wrapper)
Definition: navier_stokes_elements_with_singularity.h:675
Vector< Vector< double > > grad_velocity_singular_function(const unsigned &i, const Vector< double > &x) const
Definition: navier_stokes_elements_with_singularity.h:1007
Vector< double > Imposed_value_at_pressure_dof
Definition: navier_stokes_elements_with_singularity.h:1652
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Definition: navier_stokes_elements_with_singularity.h:687
double p_bar(const Vector< double > &x) const
Definition: navier_stokes_elements_with_singularity.h:1031
double interpolated_p_nst_fe_only(const Vector< double > &s) const
Definition: navier_stokes_elements_with_singularity.h:1084
Vector< SingularNavierStokesSolutionElement< NavierStokesElementWithSingularity< BASIC_NAVIER_STOKES_ELEMENT > > * > c_equation_elements_pt()
Access function to vector of pointers to SingularNavierStokesSolutionElements.
Definition: navier_stokes_elements_with_singularity.h:616
double interpolated_p_nst(const Vector< double > &s) const
Version of interpolated pressure including the singular contributions.
Definition: navier_stokes_elements_with_singularity.h:893
std::vector< bool > Pressure_dof_is_subject_to_dirichlet_bc
Definition: navier_stokes_elements_with_singularity.h:1647
void set_velocity_dirichlet_value_on_node(const unsigned &j, const unsigned &d, const double &value)
Definition: navier_stokes_elements_with_singularity.h:587
double p_bar(const unsigned &i, const Vector< double > &x) const
Definition: navier_stokes_elements_with_singularity.h:1024
void fill_in_generic_residual_contribution_wrapped_nst(Vector< double > &residuals, DenseMatrix< double > &jacobian, const unsigned &flag)
Overloaded fill-in function.
Definition: navier_stokes_elements_with_singularity.h:1111
Vector< double > u_bar(const Vector< double > &x) const
Definition: navier_stokes_elements_with_singularity.h:938
void impose_dirichlet_bc_on_pressure_dof(const unsigned &j)
Impose Dirichlet BC at the j-th pressure dof.
Definition: navier_stokes_elements_with_singularity.h:596
void output(std::ostream &outfile, const unsigned &nplot)
Definition: navier_stokes_elements_with_singularity.h:703
Vector< Vector< double > > grad_u_bar(const Vector< double > &x) const
Definition: navier_stokes_elements_with_singularity.h:969
Vector< Vector< double > > grad_u_bar(const unsigned &i, const Vector< double > &x) const
Definition: navier_stokes_elements_with_singularity.h:961
void undo_velocity_dirichlet_bc_on_node(const unsigned &j, const unsigned &d)
Definition: navier_stokes_elements_with_singularity.h:580
Vector< double > interpolated_u_nst(const Vector< double > &s) const
Definition: navier_stokes_elements_with_singularity.h:848
void compute_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, const bool &include_pressure, double &error, double &norm)
Overloaded compute error function; uses FE+singular parts.
Definition: navier_stokes_elements_with_singularity.h:758
double dpdx_fe_only(Vector< double > s, const unsigned *direction_pt)
Derivative of pressure in direction indicated by pointer to unsigned.
Definition: navier_stokes_elements_with_singularity.h:638
Vector< double > velocity_singular_function(const unsigned &i, const Vector< double > &x) const
Evaluate i-th "raw" velocity singular function at Eulerian position x.
Definition: navier_stokes_elements_with_singularity.h:998
Vector< std::vector< bool > > Node_is_subject_to_velocity_dirichlet_bcs
Definition: navier_stokes_elements_with_singularity.h:1638
void impose_velocity_dirichlet_bc_on_node(const unsigned &j, const unsigned &d)
Definition: navier_stokes_elements_with_singularity.h:573
NavierStokesElementWithSingularity()
Constructor.
Definition: navier_stokes_elements_with_singularity.h:496
Vector< SingularNavierStokesSolutionElement< NavierStokesElementWithSingularity< BASIC_NAVIER_STOKES_ELEMENT > > * > C_equation_elements_pt
Vector of pointers to SingularNavierStokesSolutionElement objects.
Definition: navier_stokes_elements_with_singularity.h:1633
Vector< double > u_bar(const unsigned &i, const Vector< double > &x) const
Definition: navier_stokes_elements_with_singularity.h:931
Definition: nodes.h:906
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:1060
Definition: oomph_definitions.h:222
Definition: shape.h:76
Definition: navier_stokes_elements_with_singularity.h:64
bool & singular_function_satisfies_stokes_equation()
Definition: navier_stokes_elements_with_singularity.h:119
NavierStokesPressureSingularFctPt Pressure_singular_fct_pt
Pointer to pressure singular function.
Definition: navier_stokes_elements_with_singularity.h:453
double pressure_singular_function(const Vector< double > &x) const
Evaluate pressure singular function at Eulerian position x.
Definition: navier_stokes_elements_with_singularity.h:246
void fill_in_contribution_to_jacobian(Vector< double > &residual, DenseMatrix< double > &jacobian)
Definition: navier_stokes_elements_with_singularity.h:382
Vector< Vector< double > > grad_u_bar(const Vector< double > &x)
Definition: navier_stokes_elements_with_singularity.h:315
NavierStokesVelocitySingularFctPt & velocity_singular_fct_pt()
Access function to pointer to velocity singular function.
Definition: navier_stokes_elements_with_singularity.h:185
unsigned * Direction_pt
Direction of the derivative used for the residual of the element.
Definition: navier_stokes_elements_with_singularity.h:462
Vector< double > S_in_wrapped_navier_stokes_element
Local coordinates of singulariity in wrapped Navier-Stokes element.
Definition: navier_stokes_elements_with_singularity.h:459
NavierStokesGradVelocitySingularFctPt & grad_velocity_singular_fct_pt()
Access function to pointer to gradient of velocity singular function.
Definition: navier_stokes_elements_with_singularity.h:189
double(* NavierStokesPressureSingularFctPt)(const Vector< double > &x)
Function pointer to the pressure singular function:
Definition: navier_stokes_elements_with_singularity.h:78
Vector< Vector< double > > grad_velocity_singular_function(const Vector< double > &x) const
Definition: navier_stokes_elements_with_singularity.h:223
void fill_in_generic_contribution_to_residuals(Vector< double > &residual, DenseMatrix< double > &jacobian, const unsigned &flag)
Compute local residual, and, if flag=1, local jacobian matrix.
Definition: navier_stokes_elements_with_singularity.h:391
Vector< double > grad_p_bar(const Vector< double > &x)
Definition: navier_stokes_elements_with_singularity.h:353
void set_wrapped_navier_stokes_element_pt(WRAPPED_NAVIER_STOKES_ELEMENT *wrapped_navier_stokes_el_pt, const Vector< double > &s, unsigned *direction_pt)
Definition: navier_stokes_elements_with_singularity.h:155
void set_c(const double &value)
Find the value of the unknown amplitude C.
Definition: navier_stokes_elements_with_singularity.h:132
NavierStokesGradPressureSingularFctPt Grad_pressure_singular_fct_pt
Pointer to gradient of pressure singular function.
Definition: navier_stokes_elements_with_singularity.h:456
NavierStokesGradPressureSingularFctPt & grad_pressure_singular_fct_pt()
Access function to pointer to gradient of pressure singular function.
Definition: navier_stokes_elements_with_singularity.h:197
Vector< double > velocity_singular_function(const Vector< double > &x) const
Evaluate velocity singular function at Eulerian position x.
Definition: navier_stokes_elements_with_singularity.h:201
NavierStokesVelocitySingularFctPt Velocity_singular_fct_pt
Pointer to velocity singular function.
Definition: navier_stokes_elements_with_singularity.h:446
void pin_c()
Pin the value of the unknown amplitude C.
Definition: navier_stokes_elements_with_singularity.h:138
Vector< double > u_bar(const Vector< double > &x)
Definition: navier_stokes_elements_with_singularity.h:290
Vector< double >(* NavierStokesVelocitySingularFctPt)(const Vector< double > &x)
Function pointer to the velocity singular function:
Definition: navier_stokes_elements_with_singularity.h:70
Vector< double > grad_pressure_singular_function(const Vector< double > &x) const
Evaluate gradient of pressure singular function at Eulerian position x.
Definition: navier_stokes_elements_with_singularity.h:267
NavierStokesGradVelocitySingularFctPt Grad_velocity_singular_fct_pt
Definition: navier_stokes_elements_with_singularity.h:450
double c() const
Find the value of the unknown amplitude C.
Definition: navier_stokes_elements_with_singularity.h:125
void fill_in_contribution_to_residuals(Vector< double > &residual)
Compute residual.
Definition: navier_stokes_elements_with_singularity.h:375
Vector< double >(* NavierStokesGradPressureSingularFctPt)(const Vector< double > &x)
Function pointer to the gradient of the pressure singular function:
Definition: navier_stokes_elements_with_singularity.h:82
bool Singular_function_satisfies_stokes_equation
Definition: navier_stokes_elements_with_singularity.h:465
void unpin_c()
Unpin the value of the unknown amplitude C.
Definition: navier_stokes_elements_with_singularity.h:144
SingularNavierStokesSolutionElement()
Constructor.
Definition: navier_stokes_elements_with_singularity.h:85
WRAPPED_NAVIER_STOKES_ELEMENT * Wrapped_navier_stokes_el_pt
Pointer to wrapped Navier-Stokes element.
Definition: navier_stokes_elements_with_singularity.h:443
double p_bar(const Vector< double > &x)
Definition: navier_stokes_elements_with_singularity.h:341
NavierStokesPressureSingularFctPt & pressure_singular_fct_pt()
Access function to pointer to pressure singular function.
Definition: navier_stokes_elements_with_singularity.h:193
Vector< Vector< double > >(* NavierStokesGradVelocitySingularFctPt)(const Vector< double > &x)
Function pointer to the gradient of the velocity singular function:
Definition: navier_stokes_elements_with_singularity.h:74
RealScalar s
Definition: level1_cplx_impl.h:130
char char char int int * k
Definition: level2_impl.h:374
squared absolute value
Definition: GlobalFunctions.h:87
double Gamma
Aspect ratio (cylinder height / cylinder radius)
Definition: axisym_navier_stokes/counter_rotating_disks/counter_rotating_disks.cc:70
double velocity(const double &t)
Angular velocity as function of time t.
Definition: jeffery_orbit.cc:107
void exact_soln(const double &time, const Vector< double > &x, Vector< double > &soln)
Definition: unstructured_two_d_curved.cc:301
int error
Definition: calibrate.py:297
void shape(const double &s, double *Psi)
Definition: shape.h:564
@ W
Definition: quadtree.h:63
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
bool ALE_is_disabled
Definition: gen_axisym_advection_diffusion_elements.h:638
OomphInfo oomph_info
Definition: oomph_definitions.cc:319
list x
Definition: plotDoE.py:28
#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