vorticity_smoother.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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 //Header file for Navier Stokes elements
31 
32 #ifndef OOMPH_VORTICITY_SMOOTHER_HEADER
33 #define OOMPH_VORTICITY_SMOOTHER_HEADER
34 
35 // Config header generated by autoconfig
36 #ifdef HAVE_CONFIG_H
37 #include <oomph-lib-config.h>
38 #endif
39 
40 
41 //===============================================================
42 // WARNING: THIS IS WORK IN PROGRESS -- ONLY USED IN 2D SO FAR
43 //===============================================================
44 
45 
46 
47 
48 //===========================================================================
49 /// Namespace with helper functions for (2D) vorticity (and derivatives)
50 /// recovery
51 //===========================================================================
53 {
54 
55  //========================================================================
56  /// \short Class to indicate which derivatives of the vorticity/
57  /// velocity we want to recover. We choose to immediately instantiate
58  /// an object of this class by dropping the semi-colon after the class
59  /// description.
60  //========================================================================
62  {
63  public:
64  /// Constructor
66  {
67  // Set the default (max) order of vorticity derivative to recover
69 
70  // Set the default (max) order of velocity derivative to recover
72  }
73 
74  /// The maximum order of derivatives calculated in the vorticity recovery
76  {
77  // Return the appropriate value
79  } // End of get_maximum_order_of_vorticity_derivative
80 
81  /// The maximum order of derivatives calculated in the velocity recovery
83  {
84  // Return the appropriate value
86  } // End of get_maximum_order_of_velocity_derivative
87 
88  /// The maximum order of derivatives calculated in the vorticity recovery
89  void set_maximum_order_of_vorticity_derivative(const int& max_deriv)
90  {
91  // Make sure the user has supplied a valid input value
92  if ((max_deriv<-1)||(max_deriv>3))
93  {
94  // Throw an error
95  throw OomphLibError("Invalid input value! Should be between -1 and 3!",
96  OOMPH_CURRENT_FUNCTION,
97  OOMPH_EXCEPTION_LOCATION);
98  }
99 
100  // Return the appropriate value
102 
103  // Calculate the value of Number_of_values_per_field with the updated
104  // value of Maximum_order_of_vorticity_derivative
106  } // End of set_maximum_order_of_vorticity_derivative
107 
108  /// The maximum order of derivatives calculated in the velocity recovery
109  void set_maximum_order_of_velocity_derivative(const int& max_deriv)
110  {
111  // Make sure the user has supplied a valid input value. Note, unlike the
112  // vorticity, we always output the zeroth derivative of the velocity
113  // so we don't use -1 as an input
114  if ((max_deriv<0)||(max_deriv>1))
115  {
116  // Throw an error
117  throw OomphLibError("Invalid input value! Should be between 0 and 3!",
118  OOMPH_CURRENT_FUNCTION,
119  OOMPH_EXCEPTION_LOCATION);
120  }
121 
122  // Return the appropriate value
124 
125  // Calculate the value of Number_of_values_per_field with the updated
126  // value of Maximum_order_of_velocity_derivative
128  } // End of set_maximum_order_of_vorticity_derivative
129 
130  /// \short Calculates the number of values per field given the number of
131  /// vorticity and velocity derivatives to recover (stored as private data)
133  {
134  // Output: u,v,p
136 
137  // Loop over the vorticity derivatives
138  for (unsigned i=0;i<unsigned(Maximum_order_of_vorticity_derivative+1);i++)
139  {
140  // Update the number of values per field
142  }
143 
144  // Loop over the velocity derivatives
145  for (unsigned i=1;i<unsigned(Maximum_order_of_velocity_derivative+1);i++)
146  {
147  // Update the number of values per field
149  }
150  } // End of calculate_number_of_values_per_field
151 
152  /// \short Helper function that determines the number of n-th order partial
153  /// derivatives in d-dimensions. Specifically there are (n+d-1)(choose)(d-1)
154  /// possible n-th order partial derivatives in d-dimensions. Implementation
155  /// makes use of the code found at:
156  /// www.geeksforgeeks.org/space-and-time-efficient-binomial-coefficient/
157  unsigned npartial_derivative(const unsigned& n) const
158  {
159  // This will only work in 2D so n_dim is always 2
160  unsigned n_dim=2;
161 
162  // Calculate m
163  unsigned n_bins=n+n_dim-1;
164 
165  // Calculate k
166  unsigned k=n_dim-1;
167 
168  // Initialise the result
169  unsigned value=1;
170 
171  // Since C(n_bins,k)=C(n_bins,n_bins-k)
172  if (k>n_bins-k)
173  {
174  // Replace k
175  k=n_bins-k;
176  }
177 
178  // Calculate [n_bins*(n_bins-1)*...*(n_bins-k+1)]/[k*(k-1)*...*1]
179  for (unsigned i=0;i<k;++i)
180  {
181  // First update
182  value*=(n_bins-i);
183 
184  // Second update
185  value/=(i+1);
186  }
187 
188  // Return the result
189  return value;
190  } // End of npartial_derivative
191 
192  /// Number of continuously interpolated values:
193  unsigned ncont_interpolated_values() const
194  {
195  // Return the number of values used per field
197  } // End of ncont_interpolated_values
198 
199  private:
200 
201  /// \short Number of values per field; how many of the following do we want:
202  /// u,v,p,omega,d/dx,d/dy,
203  /// d^2/dx^2,d^2/dxdy,d^2/dy^2,
204  /// d^3/dx^3,d^3/dx^2dy,d^3/dxdy^2,d^3/dy^3,
205  /// du/dx,du/dy,dv/dx,dv/dy
207 
208  /// \short Maximum number of derivatives to retain in the vorticity
209  /// recovery. Note, the value -1 means we ONLY output u,v[,w],p.
211 
212  /// \short Maximum number of derivatives to retain in the velocity
213  /// recovery. Note, the value 0 means we don't calculate the
214  /// derivatives of the velocity
216  } Recovery_helper;
217 
218 
219 } // End of VorticityRecoveryHelpers
220 
221 
222 // namespace extension
223 namespace oomph
224 {
225  //===============================================
226  /// Overloaded element that allows projection of
227  /// vorticity.
228  //===============================================
229  template<class ELEMENT>
230  class VorticitySmootherElement : public virtual ELEMENT
231  {
232  public:
233 
234  /// Constructor
236  {
237  // Only done for 2D (3D is far more difficult -- recovering a vector field
238  // instead of a scalar field)
239  N_dim=2;
240 
241  // Index of smoothed vorticity ([0]:u, [1]:v, [2]:p ==> [3]:w)
242  Smoothed_vorticity_index=3;
243 
244  // The current maximum order of vorticity derivatives we can recover. This
245  // is currently 10 as we can recover from the zeroth to third derivative
246  Maximum_order_of_recoverable_vorticity_derivatives=3;
247 
248  // The current maximum order of velocity derivatives we can recover.
249  // Currently this is 4 as we only recover first derivatives.
250  Maximum_order_of_recoverable_velocity_derivatives=1;
251 
252  // Recover as many
256 
257  // The default is to recover the velocity derivatives
261 
262  // Set the number of values per field
266 
267  // Pointer to fct that specifies exact vorticity and
268  // derivs (for validation).
269  Exact_vorticity_fct_pt=0;
270  }
271 
272  /// Typedef for pointer to function that specifies the exact vorticity
273  /// and derivatives (for validation)
274  typedef void (*ExactVorticityFctPt)(const Vector<double>& x,
275  Vector<Vector<double> >& vort_and_derivs);
276 
277  /// \short Helper function to create a container for the vorticity and
278  /// its partial derivatives. If the user wishes to output everything then
279  /// this also creates space for the velocity derivatives too. This function
280  /// has been written to allow for generalisation of the storage without
281  /// (hopefully!) affecting too much
283  {
284  // Maximum number of vorticity derivatives
285  unsigned n_vort_deriv=Maximum_order_of_vorticity_derivative;
286 
287  // Maximum number of velocity derivatives
288  unsigned n_veloc_deriv=Maximum_order_of_velocity_derivative;
289 
290  // The number of vectors in the output
291  unsigned n_vector=n_vort_deriv+n_veloc_deriv+1;
292 
293  // Container for the vorticity and its derivatives
294  Vector<Vector<double> > vort_and_derivs(n_vector);
295 
296  // Loop over the entries of the vector
297  for (unsigned i=0;i<n_vort_deriv+1;i++)
298  {
299  // Get the number of partial derivatives of the vorticity
300  vort_and_derivs[i].resize(npartial_derivative(i),0.0);
301  }
302 
303  // Loop over the entries of the vector
304  for (unsigned i=n_vort_deriv+1;i<n_vort_deriv+n_veloc_deriv+1;i++)
305  {
306  // Resize the container and initialise all entries to zero
307  vort_and_derivs[i].resize(2*npartial_derivative(i-n_vort_deriv),0.0);
308  }
309 
310  // Return the container
311  return vort_and_derivs;
312  } // End of create_container_for_vorticity_and_derivatives
313 
314  /// \short Helper function that, given the local dof number of the i-th
315  /// vorticity or velocity derivative, returns the index in the container
316  /// that stores the corresponding value.
317  /// Note 1: this function goes hand-in-hand with
318  /// create_container_for_vorticity_and_derivatives()
319  /// Note 2: i=0: vorticity itself;
320  /// i>0: vorticity derivatives
321  std::pair<unsigned,unsigned>
322  vorticity_dof_to_container_id(const unsigned& i) const
323  {
324  // Maximum number of vorticity derivatives (that we actually want)
325  unsigned n_vort_deriv=Maximum_order_of_vorticity_derivative;
326 
327  // Maximum number of velocity derivatives (that we actually want)
328  unsigned n_veloc_deriv=Maximum_order_of_velocity_derivative;
329 
330 #ifdef PARANOID
331  // We cannot calculate this if we're not recovering anything
332  if (n_vort_deriv+n_veloc_deriv+1==0)
333  {
334  // Throw an error
335  throw OomphLibError("Not recovering anything so this shouldn't be called.",
336  OOMPH_CURRENT_FUNCTION,
337  OOMPH_EXCEPTION_LOCATION);
338  }
339 #endif
340 
341  // Maximum order of vorticity derivative (that can be recovered)
342  unsigned max_vort_order=Maximum_order_of_recoverable_vorticity_derivatives;
343 
344  // Maximum order of velocity derivative (that can be recovered)
345  unsigned max_veloc_order=Maximum_order_of_recoverable_velocity_derivatives;
346 
347  // Maximum number of recoverable vorticity terms
348  unsigned max_vort_recov=0;
349 
350  // Maximum number of recoverable velocity terms
351  unsigned max_veloc_recov=0;
352 
353  // Loop over the entries of the vector
354  for (unsigned j=0;j<max_vort_order+1;j++)
355  {
356  // Get the number of partial derivatives of the vorticity
357  max_vort_recov+=npartial_derivative(j);
358  }
359 
360  // Loop over the entries of the vector
361  for (unsigned j=1;j<max_veloc_order+1;j++)
362  {
363  // Get the number of partial derivatives of the vorticity
364  max_veloc_recov+=2*npartial_derivative(j);
365  }
366 
367  // Create a pair to store the output
368  std::pair<unsigned,unsigned> container_id;
369 
370  // Store the number of derivatives we've gone over
371  unsigned nprev_deriv=0;
372 
373  // The number of derivatives available of a given order
374  unsigned n_deriv=0;
375 
376  // If the dof number i is associated with a vorticity derivative
377  if (i<max_vort_recov)
378  {
379  // Loop over the vorticity vectors
380  for (unsigned jj=0;jj<n_vort_deriv+1;jj++)
381  {
382  // Number of derivatives of order jj
383  n_deriv=npartial_derivative(jj);
384 
385  // Update nprev_derivs
386  nprev_deriv+=n_deriv;
387 
388  // If this is true then we need the jj-th vector
389  if (i<nprev_deriv)
390  {
391  // Assign the first index
392  container_id.first=jj;
393 
394  // Index of the entry
395  container_id.second=i-(nprev_deriv-n_deriv);
396 
397  // We're done
398  return container_id;
399  }
400  } // for (unsigned jj=0;jj<n_vort_deriv+1;jj++)
401  }
402  // If the dof number i is associated with a velocity derivative
403  else if (i<max_vort_recov+max_veloc_recov)
404  {
405  // Initialise the value of nprev_deriv (depending on how many
406  // vorticity derivatives we can recover)
407  nprev_deriv=max_vort_recov;
408 
409  // Loop over the velocity vectors
410  for (unsigned jj=n_vort_deriv+1;jj<n_vort_deriv+n_veloc_deriv+1;jj++)
411  {
412  // Number of velocity derivatives
413  n_deriv=2*npartial_derivative(jj-n_vort_deriv);
414 
415  // Update nprev_derivs
416  nprev_deriv+=n_deriv;
417 
418  // If this is true then we need the jj-th vector
419  if (i<nprev_deriv)
420  {
421  // Assign the first index
422  container_id.first=jj;
423 
424  // Index of the entry
425  container_id.second=i-(nprev_deriv-n_deriv);
426 
427  // We're done
428  return container_id;
429  }
430  } // for (unsigned jj=n_vort_deriv+1;jj<n_veloc_deriv;jj++)
431  }
432  else
433  {
434  // Create an ostringstream object to create an error message
435  std::ostringstream error_message_stream;
436 
437  // Create an error message
438  error_message_stream << "Dof number " << i << " not associated "
439  << "with a vorticity or velocity derivative!"
440  << std::endl;
441 
442  // Throw an error
443  throw OomphLibError(error_message_stream.str(),
444  OOMPH_CURRENT_FUNCTION,
445  OOMPH_EXCEPTION_LOCATION);
446  } // if (i<max_vort_recov)
447 
448  // We'll never get here but need to return something
449  return container_id;
450  } // End of vorticity_dof_to_container_id
451 
452 
453  /// \short Helper function that, given the local dof number of the i-th
454  /// vorticity or velocity derivative, returns the index in the container
455  /// that stores the corresponding value.
456  /// Note 1: this function goes hand-in-hand with
457  /// create_container_for_vorticity_and_derivatives()
458  /// Note 2: The input to this function is the i associated with the STORED
459  /// nodal dof value. For example, if we're only recovering the
460  /// velocity derivatives then i=0 is associated with du/dx
461  std::pair<unsigned,unsigned>
462  recovered_dof_to_container_id(const unsigned& i) const
463  {
464  // Create a pair to store the output
465  std::pair<unsigned,unsigned> container_id;
466 
467  // Find which derivative to calculate
468  unsigned derivative_index=i;
469 
470  // Variable to store the index of the vector (initialise the value to -1
471  // so we know whether or not the value has been set)
472  int vector_index=-1;
473 
474  // Get the number of vorticity derivatives to recover
475  unsigned n_vort_derivs=Maximum_order_of_vorticity_derivative;
476 
477  // Get the number of vorticity derivatives to recover
478  unsigned n_veloc_derivs=Maximum_order_of_velocity_derivative;
479 
480  // Loop over the entries of the vector
481  for (unsigned i=0;i<n_vort_derivs+1;i++)
482  {
483  // Get the number of partial derivatives of the vorticity
484  if (derivative_index<npartial_derivative(i))
485  {
486  // We're on the i-th vector
487  vector_index=i;
488 
489  // We're done
490  break;
491  }
492  else
493  {
494  // Decrease the value of derivative_index
495  derivative_index-=npartial_derivative(i);
496  }
497  } // for (unsigned i=0;i<n_vort_derivs+1;i++)
498 
499  // If the vector_index variable value hasn't been found yet
500  if (vector_index==-1)
501  {
502  // Loop over the entries of the vector
503  for (unsigned i=1;i<n_veloc_derivs+1;i++)
504  {
505  // Get the number of partial derivatives of the vorticity
506  if (derivative_index<2*npartial_derivative(i))
507  {
508  // We're on the i-th vector
509  vector_index=n_vort_derivs+i;
510 
511  // We're done
512  break;
513  }
514  else
515  {
516  // Decrease the value of derivative_index
517  derivative_index-=2*npartial_derivative(i);
518  }
519  } // for (unsigned i=1;i<n_veloc_derivs+1;i++)
520  } // if (vector_index==-1)
521 
522 #ifdef PARANOID
523  // Sanity check: if the value hasn't been set yet, something's wrong
524  if (vector_index==-1)
525  {
526  // Create an ostringstream object to create an error message
527  std::ostringstream error_message_stream;
528 
529  // Create an error message
530  error_message_stream << "Value of vector_index has not been set. "
531  << "Something's wrong!";
532 
533  // Throw an error
534  throw OomphLibError(error_message_stream.str(),
535  OOMPH_CURRENT_FUNCTION,
536  OOMPH_EXCEPTION_LOCATION);
537  }
538 #endif
539 
540  // Assign the first entry of container_id
541  container_id.first=vector_index;
542 
543  // Assign the second entry of container_id
544  container_id.second=derivative_index;
545 
546  // We'll never get here but need to return something
547  return container_id;
548  } // End of recovered_dof_to_container_id
549 
550  /// \short Given the STORED dof number, this function returns the global
551  /// recovered number. For example, if we only want to recover the velocity
552  /// derivatives then the stored dof number of du/dy is 1 (as 0 is associated
553  /// with du/dx). The global recovered number is 11 (as there are currently
554  /// 10 vorticity derivatives that can be recovered and du/dy is the second
555  /// velocity derivative we can recover).
556  unsigned stored_dof_to_recoverable_dof(const unsigned& i) const
557  {
558  // Get the ID in the storage associated with i-th recovered dof
559  std::pair<unsigned,unsigned> id=recovered_dof_to_container_id(i-N_dim-1);
560 
561  // Vector entry index
562  unsigned vector_index=id.first;
563 
564  // Derivative index
565  unsigned deriv_index=id.second;
566 
567  // The index we want
568  unsigned index=0;
569 
570  // Maximum possible order of vorticity derivatives that can be recovered
571  unsigned max_vort_recov=Maximum_order_of_recoverable_vorticity_derivatives;
572 
573  // If we're dealing with a vorticity derivative
574  if (vector_index<max_vort_recov+1)
575  {
576  // Holds the number of derivatives of lower order
577  unsigned n_prev_deriv=0;
578 
579  // Loop over the derivative orders
580  for (unsigned j=0;j<vector_index;j++)
581  {
582  // Increment n_prev_deriv
583  n_prev_deriv+=npartial_derivative(j);
584  }
585 
586  // Update the value of index
587  index+=n_prev_deriv+deriv_index;
588  }
589  // We're dealing with derivatives of the velocity
590  else
591  {
592  // Holds the number of vorticity derivatives
593  unsigned n_prev_deriv=0;
594 
595  // Loop over the derivative orders
596  for (unsigned j=0;j<max_vort_recov+1;j++)
597  {
598  // Increment n_prev_deriv
599  n_prev_deriv+=npartial_derivative(j);
600  }
601 
602  // What is the user-chosen maximum vorticity derivative to recover?
603  unsigned n_vort_deriv=Maximum_order_of_vorticity_derivative;
604 
605  // Loop over the derivative orders
606  for (unsigned j=1;j<vector_index-n_vort_deriv;j++)
607  {
608  // Increment n_prev_deriv
609  n_prev_deriv+=2*npartial_derivative(j);
610  }
611 
612  // Update the value of index
613  index+=n_prev_deriv+deriv_index;
614  } // if (vector_index<max_vort_recov)
615 
616  // Return the value of index
617  return index;
618  } // End of stored_dof_to_recoverable_dof
619 
620  /// \short The maximum order of vorticity derivative that can be recovered.
621  /// This is set in the constructor and should NOT be changed during the
622  /// running of the code. As such, a set...() function is not provided.
623  /// DRAIG: Leave get_ prefix?
625  {
626  // Return the appropriate value
627  return Maximum_order_of_recoverable_vorticity_derivatives;
628  } // End of get_maximum_order_of_recoverable_vorticity_derivative
629 
630  /// \short The maximum order of velocity derivative that can be recovered.
631  /// This is set in the constructor and should NOT be changed during the
632  /// running of the code. As such, a set...() function is not provided.
633  /// DRAIG: Leave get_ prefix?
635  {
636  // Return the appropriate value
637  return Maximum_order_of_recoverable_velocity_derivatives;
638  } // End of get_maximum_order_of_recoverable_velocity_derivative
639 
640  /// \short The maximum order of derivatives calculated in the vorticity
641  /// recovery. Note, this value can only be set through the namespace
642  /// VorticityRecoveryHelpers.
643  /// DRAIG: Leave get_ prefix?
645  {
646  // Return the appropriate value
648  } // End of get_maximum_order_of_vorticity_derivative
649 
650  /// \short The maximum order of derivatives calculated in the velocity
651  /// recovery. Note, this value can only be set through the namespace
652  /// VorticityRecoveryHelpers.
653  /// DRAIG: Leave get_ prefix?
655  {
656  // Return the appropriate value
658  } // End of get_maximum_order_of_velocity_derivative
659 
660  /// \short The number of terms calculated in the vorticity recovery. Also
661  /// includes the zeroth derivative, i.e. the vorticity itself
663  {
664  // The number of terms recovered
665  unsigned n_terms=0;
666 
667  // Loop over the derivatives
668  for (unsigned i=0;i<unsigned(Maximum_order_of_vorticity_derivative+1);i++)
669  {
670  // Update n_terms
671  n_terms+=npartial_derivative(i);
672  }
673 
674  // Return the appropriate value
675  return n_terms;
676  } // End of nvorticity_derivatives_to_recover
677 
678  /// The number of derivatives calculated in the velocity recovery. This does
679  /// NOT include the zeroth derivatives as they are not "recovered"
681  {
682  // The number of terms recovered
683  unsigned n_terms=0;
684 
685  // Loop over the derivatives
686  for (unsigned i=1;i<unsigned(Maximum_order_of_velocity_derivative+1);i++)
687  {
688  // Update n_terms
689  n_terms+=2*npartial_derivative(i);
690  }
691 
692  // Return the appropriate value
693  return n_terms;
694  } // End of nvelocity_derivatives_to_recover
695 
696  /// Call the function written in VorticityRecoveryHelpers
697  unsigned npartial_derivative(const unsigned& n) const
698  {
699  // Return the result
701  } // End of npartial_derivative
702 
703  /// \short Access function: Pointer to function that specifies exact vorticity
704  /// and derivatives (for validation).
705  ExactVorticityFctPt& exact_vorticity_fct_pt()
706  {
707  // Return the address of the function pointer
708  return Exact_vorticity_fct_pt;
709  } // End of exact_vorticity_fct_pt
710 
711  /// \short Access function: Pointer to function that specifies exact vorticity
712  /// and derivatives (for validation) -- const version
713  ExactVorticityFctPt exact_vorticity_fct_pt() const
714  {
715  // Return the address of the function pointer
716  return Exact_vorticity_fct_pt;
717  } // End of exact_vorticity_fct_pt
718 
719  /// Index of smoothed vorticity -- followed by derivatives
720  unsigned smoothed_vorticity_index() const
721  {
722  // Return the value of the Smoothed_vorticity_index
723  return Smoothed_vorticity_index;
724  } // End of smoothed_vorticity_index
725 
726  /// \short Number of values required at local node n. In order to simplify
727  /// matters, we allocate storage for pressure variables at all the nodes
728  /// and then pin those that are not used.
729  unsigned required_nvalue(const unsigned& n) const
730  {
731  // Return the number of values used per field
733  } // End of required_nvalue
734 
735  /// \short Number of continuously interpolated values:
736  unsigned ncont_interpolated_values() const
737  {
738  // Return the number of values used per field
740  } // End of ncont_interpolated_values
741 
742  /// \short Get the function value u in Vector.
743  /// Note: Given the generality of the interface (this function is usually
744  /// called from black-box documentation or interpolation routines), the
745  /// values Vector sets its own size in here.
747  {
748  // Get the value at the current time
749  unsigned t=0;
750 
751  // Get the interpolated values
752  get_interpolated_values(t,s,values);
753  } // End of get_interpolated_values
754 
755  /// \short Get the function value u in Vector.
756  /// Note: Given the generality of the interface (this function is usually
757  /// called from black-box documentation or interpolation routines), the
758  /// values Vector sets its own size in here.
759  void get_interpolated_values(const unsigned& t,
760  const Vector<double>& s,
761  Vector<double>& values)
762  {
763  // Set size of vector and initialise all entries to zero
764  values.resize(Number_of_values_per_field,0.0);
765 
766  // Find out how many nodes there are
767  unsigned n_node=this->nnode();
768 
769  // Shape functions
770  Shape psif(n_node);
771 
772  // Get the value of the shape function at the local coordinate s
773  this->shape(s,psif);
774 
775  // Calculate velocities: values[0],...
776  for (unsigned i=0;i<N_dim;i++)
777  {
778  // Get the index at which the i-th velocity is stored
779  unsigned u_nodal_index=this->u_index_nst(i);
780 
781  // Loop over the nodes
782  for (unsigned l=0;l<n_node;l++)
783  {
784  // Update the i-th entry of the value vector
785  values[i]+=this->nodal_value(t,l,u_nodal_index)*psif[l];
786  }
787  } // for (unsigned i=0;i<N_dim;i++)
788 
789  // Calculate pressure: values[N_dim] (no history is carried in the pressure)
790  values[N_dim]=this->interpolated_p_nst(s);
791  } // End of get_interpolated_values
792 
793  /// Pin all smoothed vorticity quantities
795  {
796  // Get the number of nodes in the element
797  unsigned nnod=this->nnode();
798 
799  // Loop over the nodes
800  for (unsigned j=0;j<nnod;j++)
801  {
802  // Make a pointer to the j-th node in the element
803  Node* nod_pt=this->node_pt(j);
804 
805  // Loop over the fields
806  for (unsigned i=Smoothed_vorticity_index;i<Number_of_values_per_field;i++)
807  {
808  // Pin the i-th field at this node
809  nod_pt->pin(i);
810  }
811  } // for (unsigned j=0;j<nnod;j++)
812  } // End of pin_smoothed_vorticity
813 
814  /// \short Output exact velocity, vorticity, derivatives and indicator
815  /// based on functions specified by two function pointers
816  void output_analytical_veloc_and_vorticity(std::ostream& outfile,
817  const unsigned& nplot)
818  {
819  // Vector of local coordinates
820  Vector<double> s(N_dim,0.0);
821 
822  // Global coordinates container
823  Vector<double> x(N_dim);
824 
825  // Get the number of nodes in this element
826  unsigned n_node=this->nnode();
827 
828  // Shape functions
829  Shape psif(n_node);
830 
831  // Tecplot header info
832  outfile << this->tecplot_zone_string(nplot);
833 
834  // Get the number of plot points
835  unsigned num_plot_points=this->nplot_points(nplot);
836 
837  // Create a container for the vorticity and its derivatives
838  Vector<Vector<double> > vort_and_derivs=
839  create_container_for_vorticity_and_derivatives();
840 
841  // Loop over plot points
842  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
843  {
844  // Get local coordinates of plot point
845  this->get_s_plot(iplot,nplot,s);
846 
847  // Loop over the coordinates
848  for (unsigned i=0;i<N_dim;i++)
849  {
850  // Get the interpolated coordinate value at this local coordinate
851  x[i]=this->interpolated_x(s,i);
852 
853  // Output the i-th coordinate value to file
854  outfile << x[i] << " ";
855  }
856 
857  // Fake velocity and pressure
858  outfile << "0.0 0.0 0.0 ";
859 
860  // Get the vorticity and its derivatives (and the derivatives of the
861  // velocity if required)
862  Exact_vorticity_fct_pt(x,vort_and_derivs);
863 
864  // Number of vectors
865  unsigned n_vector=vort_and_derivs.size();
866 
867  // Loop over the number of vectors we're outputting from
868  for (unsigned i=0;i<n_vector;i++)
869  {
870  // The number of entries in the vector
871  unsigned i_entries=vort_and_derivs[i].size();
872 
873  // Loop over the entries in the vector
874  for (unsigned j=0;j<i_entries;j++)
875  {
876  // Output the smoothed vorticity to file
877  outfile << (vort_and_derivs[i])[j] << " ";
878  }
879  } // for (unsigned i=0;i<n_vector;i++)
880 
881  // Finish the line
882  outfile << std::endl;
883  } // for (unsigned iplot=0;iplot<num_plot_points;iplot++)
884 
885  // Write tecplot footer (e.g. FE connectivity lists)
886  this->write_tecplot_zone_footer(outfile,nplot);
887  } // End of output_analytical_veloc_and_vorticity
888 
889  /// \short Output the velocity, smoothed vorticity and derivatives
890  void output_smoothed_vorticity(std::ostream &outfile,const unsigned &nplot)
891  {
892  // Vector of local coordinates
893  Vector<double> s(N_dim,0.0);
894 
895  // Vector of global coordinates
896  Vector<double> x(N_dim,0.0);
897 
898  // Get the number of nodes in the element
899  unsigned n_node=this->nnode();
900 
901  // Shape functions
902  Shape psif(n_node);
903 
904  // Tecplot header info
905  outfile << this->tecplot_zone_string(nplot);
906 
907  // Create a container for the vorticity and its derivatives
908  Vector<Vector<double> > vort_and_derivs=
909  create_container_for_vorticity_and_derivatives();
910 
911  // Vector of velocities
912  Vector<double> velocity(N_dim,0.0);
913 
914  // Get the number of plot points
915  unsigned num_plot_points=this->nplot_points(nplot);
916 
917  // Loop over plot points
918  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
919  {
920  // Get local coordinates of plot point
921  this->get_s_plot(iplot,nplot,s);
922 
923  // Get vorticity and its derivatives (reconstructed)
924  vorticity_and_its_derivs(s,vort_and_derivs);
925 
926  // Loop over the coordinates
927  for (unsigned i=0;i<N_dim;i++)
928  {
929  // Get the i-th interpolated coordinate at a given local coordinate
930  x[i]=this->interpolated_x(s,i);
931 
932  // Output the interpolated coordinate to file
933  outfile << x[i] << " ";
934  }
935 
936  // Loop over the coordinates
937  for (unsigned i=0;i<N_dim;i++)
938  {
939  // Output the i-th velocity component
940  outfile << this->interpolated_u_nst(s,i) << " ";
941  }
942 
943  // Pressure
944  outfile << this->interpolated_p_nst(s) << " ";
945 
946  // Output the smoothed vorticity derivatives
947  // (d/dx, d/dy, d^2/dx^2, d^2/dxdy, d^2/dy^2
948  // d^3/dx^3, d^3/dx^2dy, d^3/dxdy^2, d^3/dy^3
949  // du/dx, du/dy, dv/dx, dv/dy):
950 
951  // Number of vectors
952  unsigned n_vector=vort_and_derivs.size();
953 
954  // Loop over the number of vectors we're outputting from
955  for (unsigned i=0;i<n_vector;i++)
956  {
957  // The number of entries in the vector
958  unsigned i_entries=vort_and_derivs[i].size();
959 
960  // Loop over the entries in the vector
961  for (unsigned j=0;j<i_entries;j++)
962  {
963  // Output the smoothed vorticity to file
964  outfile << (vort_and_derivs[i])[j] << " ";
965  }
966  } // for (unsigned i=0;i<n_vector;i++)
967 
968  // End the line
969  outfile << std::endl;
970  } // for (unsigned iplot=0;iplot<num_plot_points;iplot++)
971 
972  // Write tecplot footer (e.g. FE connectivity lists)
973  this->write_tecplot_zone_footer(outfile,nplot);
974  } // End of output_smoothed_vorticity
975 
976  /// \short Number of scalars/fields output by this element. Re-implements
977  /// broken virtual function in base class.
978  unsigned nscalar_paraview() const
979  {
980  // Return the number of continuously interpolated values
981  return ncont_interpolated_values();
982  } // End of nscalar_paraview
983 
984  /// \short Write values of the i-th scalar field at the plot points. Needs
985  /// to be implemented for each new specific element type.
986  void scalar_value_paraview(std::ofstream& file_out,
987  const unsigned& i,
988  const unsigned& nplot) const
989  {
990  // Vector of local coordinates
991  Vector<double> s(N_dim,0.0);
992 
993  // Get the number of plot points
994  unsigned num_plot_points=this->nplot_points_paraview(nplot);
995 
996  // Create a container for the vorticity and its derivatives
997  Vector<Vector<double> > vort_and_derivs=
998  create_container_for_vorticity_and_derivatives();
999 
1000  // Loop over plot points
1001  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
1002  {
1003  // Get local coordinates of plot point
1004  this->get_s_plot(iplot,nplot,s);
1005 
1006  // Velocities
1007  if (i<N_dim)
1008  {
1009  // Output the interpolated velocity component
1010  file_out << this->interpolated_u_nst(s,i) << std::endl;
1011  }
1012  // Pressure
1013  else if (i==N_dim)
1014  {
1015  // Output the interpolated pressure value
1016  file_out << this->interpolated_p_nst(s) << std::endl;
1017  }
1018  // Output the vorticity and required derivatives
1019  else if (i<nscalar_paraview())
1020  {
1021  // Get vorticity and its derivatives (reconstructed)
1022  vorticity_and_its_derivs(s,vort_and_derivs);
1023 
1024  // Get the ID in the storage associated with i-th recovered dof
1025  std::pair<unsigned,unsigned> id=recovered_dof_to_container_id(i-N_dim-1);
1026 
1027  // Output the appropriate value
1028  file_out << (vort_and_derivs[id.first])[id.second] << std::endl;
1029  }
1030  // Never get here
1031  else
1032  {
1033 #ifdef PARANOID
1034  // Using a std::stringstream object to create a string
1035  std::stringstream error_stream;
1036 
1037  // Create the error message
1038  error_stream << "These VorticitySmoother elements only store "
1039  << ncont_interpolated_values() << " fields, "
1040  << "but i is currently: " << i << std::endl;
1041 
1042  // Throw an error
1043  throw OomphLibError(error_stream.str(),
1044  OOMPH_CURRENT_FUNCTION,
1045  OOMPH_EXCEPTION_LOCATION);
1046 #endif
1047  }
1048  } // for (unsigned iplot=0;iplot<num_plot_points;iplot++)
1049  } // End of scalar_value_paraview
1050 
1051  /// \short Name of the i-th scalar field. Default implementation
1052  /// returns V1 for the first one, V2 for the second etc. Can (should!) be
1053  /// overloaded with more meaningful names in specific elements.
1054  std::string scalar_name_paraview(const unsigned& i) const
1055  {
1056  // Velocities
1057  if (i<N_dim)
1058  {
1059  // Return the velocity name
1060  return "Velocity "+StringConversion::to_string(i);
1061  }
1062  // Pressure
1063  else if (i==N_dim)
1064  {
1065  // Return the appropriate string
1066  return "Pressure";
1067  }
1068  // Vorticity or its derivatives
1069  else if (i<nscalar_paraview())
1070  {
1071  // Calculate the appropriate value of index
1072  unsigned index=Smoothed_vorticity_index+stored_dof_to_recoverable_dof(i);
1073 
1074  // Switch statement is the easiest way to output smoothed vorticity
1075  // and velocity derivatives:
1076  // (d/dx, d/dy,
1077  // d^2/dx^2, d^2/dxdy, d^2/dy^2
1078  // d^3/dx^3, d^3/dx^2dy, d^3/dxdy^2, d^3/dy^3
1079  // du/dx, du/dy, dv/dx, dv/dy)
1080  switch (index)
1081  {
1082  case 3:
1083  return "w";
1084  break;
1085  case 4:
1086  return "dw/dx";
1087  break;
1088  case 5:
1089  return "dw/dy";
1090  break;
1091  case 6:
1092  return "d^2w/dx^2";
1093  break;
1094  case 7:
1095  return "d^2w/dxdy";
1096  break;
1097  case 8:
1098  return "d^2w/dy^2";
1099  break;
1100  case 9:
1101  return "d^3/dx^3";
1102  break;
1103  case 10:
1104  return "d^3/dx^2dy";
1105  break;
1106  case 11:
1107  return "d^3/dxdy^2";
1108  break;
1109  case 12:
1110  return "d^3/dy^3";
1111  break;
1112  case 13:
1113  return "du/dx";
1114  break;
1115  case 14:
1116  return "du/dy";
1117  break;
1118  case 15:
1119  return "dv/dx";
1120  break;
1121  case 16:
1122  return "dv/dy";
1123  break;
1124  default:
1125  oomph_info << "Never get here" << std::endl;
1126  abort();
1127  break;
1128  }
1129  }
1130  // Never get here
1131  else
1132  {
1133  std::stringstream error_stream;
1134  error_stream << "These Navier Stokes elements only store "
1135  << nscalar_paraview() << " fields,\n"
1136  << "but i is currently: " << i << std::endl;
1137 
1138  // Throw the error
1139  throw OomphLibError(error_stream.str(),
1140  OOMPH_CURRENT_FUNCTION,
1141  OOMPH_EXCEPTION_LOCATION);
1142  // Dummy return
1143  return " ";
1144  }
1145  } // End of scalar_name_paraview
1146 
1147  /// \short Overloaded output function: Output velocity, pressure and the
1148  /// smoothed vorticity
1149  void output(std::ostream &outfile, const unsigned &nplot)
1150  {
1151  // Vector of local coordinates
1152  Vector<double> s(N_dim,0.0);
1153 
1154  // Global coordinates container
1155  Vector<double> x(N_dim,0.0);
1156 
1157  // Get the number of nodes in this element
1158  unsigned n_node=this->nnode();
1159 
1160  // Shape functions
1161  Shape psif(n_node);
1162 
1163  // Tecplot header info
1164  outfile << this->tecplot_zone_string(nplot);
1165 
1166  // Get the number of plot points
1167  unsigned num_plot_points=this->nplot_points(nplot);
1168 
1169  // Create a container for the vorticity and its derivatives
1170  Vector<Vector<double> > vort_and_derivs=
1171  create_container_for_vorticity_and_derivatives();
1172 
1173  // Loop over plot points
1174  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
1175  {
1176  // Get local coordinates of plot point
1177  this->get_s_plot(iplot,nplot,s);
1178 
1179  // Get shape fct
1180  this->shape(s,psif);
1181 
1182  // Loop over the coordinates
1183  for (unsigned i=0;i<N_dim;i++)
1184  {
1185  // Get the interpolated coordinate value at this local coordinate
1186  x[i]=this->interpolated_x(s,i);
1187 
1188  // Output the i-th coordinate value to file
1189  outfile << x[i] << " ";
1190  }
1191 
1192  // Loop over the coordinates
1193  for (unsigned i=0;i<N_dim;i++)
1194  {
1195  // Output the i-th velocity component
1196  outfile << this->interpolated_u_nst(s,i) << " ";
1197  }
1198 
1199  // Pressure
1200  outfile << this->interpolated_p_nst(s) << " ";
1201 
1202  // Get vorticity and its derivatives (reconstructed)
1203  vorticity_and_its_derivs(s,vort_and_derivs);
1204 
1205  // Number of vectors
1206  unsigned n_vector=vort_and_derivs.size();
1207 
1208  // Loop over the number of vectors we're outputting from
1209  for (unsigned i=0;i<n_vector;i++)
1210  {
1211  // The number of entries in the vector
1212  unsigned i_entries=vort_and_derivs[i].size();
1213 
1214  // Loop over the entries in the vector
1215  for (unsigned j=0;j<i_entries;j++)
1216  {
1217  // Output the smoothed vorticity to file
1218  outfile << (vort_and_derivs[i])[j] << " ";
1219  }
1220  } // for (unsigned i=0;i<n_vector;i++)
1221 
1222  // Finish the line off
1223  outfile << std::endl;
1224  }
1225 
1226  // Write tecplot footer (e.g. FE connectivity lists)
1227  this->write_tecplot_zone_footer(outfile,nplot);
1228  } // End of output
1229 
1230 
1231  /// Get raw derivative of velocity
1233  Vector<double>& dveloc_dx) const
1234  {
1235  // Find out how many nodes there are
1236  unsigned n_node=this->nnode();
1237 
1238  // Set up memory for the shape functions
1239  Shape psif(n_node);
1240 
1241  // Set up memory for the shape function derivatives
1242  DShape dpsifdx(n_node,2);
1243 
1244  // Call the derivatives of the shape and test functions
1245  this->dshape_eulerian(s,psif,dpsifdx);
1246 
1247  // Initialise all entries to zero
1248  dveloc_dx.initialise(0.0);
1249 
1250  // Loop over nodes
1251  for (unsigned l=0;l<n_node;l++)
1252  {
1253  // Loop over derivative directions
1254  for (unsigned j=0;j<2;j++)
1255  {
1256  // Derivatives of the first velocity component
1257  dveloc_dx[j]+=this->nodal_value(l,0)*dpsifdx(l,j);
1258 
1259  // Derivatives of the second velocity component
1260  dveloc_dx[j+2]+=this->nodal_value(l,1)*dpsifdx(l,j);
1261  }
1262  } // for (unsigned l=0;l<n_node;l++)
1263  } // End of get_raw_velocity_deriv
1264 
1265  /// Get raw derivative of velocity
1267  double& dveloc_dx,
1268  const unsigned& index) const
1269  {
1270  // Find out how many nodes there are
1271  unsigned n_node=this->nnode();
1272 
1273  // Set up memory for the shape functions
1274  Shape psif(n_node);
1275 
1276  // Set up memory for the shape function derivatives
1277  DShape dpsifdx(n_node,2);
1278 
1279  // Call the derivatives of the shape and test functions
1280  this->dshape_eulerian(s,psif,dpsifdx);
1281 
1282  // Initialise value to zero
1283  dveloc_dx=0.0;
1284 
1285  // Use a switch statement
1286  switch (index)
1287  {
1288  case 0:
1289  // Loop over the nodes
1290  for (unsigned l=0;l<n_node;l++)
1291  {
1292  // Derivatives of the first velocity component
1293  dveloc_dx+=this->nodal_value(l,0)*dpsifdx(l,0);
1294  }
1295  break;
1296  case 1:
1297  // Loop over the nodes
1298  for (unsigned l=0;l<n_node;l++)
1299  {
1300  // Derivatives of the first velocity component
1301  dveloc_dx+=this->nodal_value(l,0)*dpsifdx(l,1);
1302  }
1303  break;
1304  case 2:
1305  // Loop over the nodes
1306  for (unsigned l=0;l<n_node;l++)
1307  {
1308  // Derivatives of the second velocity component
1309  dveloc_dx+=this->nodal_value(l,1)*dpsifdx(l,0);
1310  }
1311  break;
1312  case 3:
1313  // Loop over the nodes
1314  for (unsigned l=0;l<n_node;l++)
1315  {
1316  // Derivatives of the second velocity component
1317  dveloc_dx+=this->nodal_value(l,1)*dpsifdx(l,1);
1318  }
1319  break;
1320  default:
1321  oomph_info << "Never get here!" << std::endl;
1322  abort();
1323  }
1324  } // End of get_raw_velocity_deriv
1325 
1326  /// Get raw derivative of smoothed vorticity
1328  Vector<double>& dvorticity_dx) const
1329  {
1330  // Find out how many nodes there are
1331  unsigned n_node=this->nnode();
1332 
1333  // Set up memory for the shape functions
1334  Shape psif(n_node);
1335 
1336  // Set up memory for the shape function derivatives
1337  DShape dpsifdx(n_node,2);
1338 
1339  // Call the derivatives of the shape and test functions
1340  this->dshape_eulerian(s,psif,dpsifdx);
1341 
1342  // Initialise all entries to zero
1343  dvorticity_dx.initialise(0.0);
1344 
1345  // Loop over nodes
1346  for (unsigned l=0;l<n_node;l++)
1347  {
1348  // Loop over derivative directions
1349  for (unsigned j=0;j<2;j++)
1350  {
1351  // Calculate the x and y derivative
1352  dvorticity_dx[j]+=this->nodal_value(l,Smoothed_vorticity_index)*
1353  dpsifdx(l,j);
1354  }
1355  } // for (unsigned l=0;l<n_node;l++)
1356  } // End of get_raw_vorticity_deriv
1357 
1358  /// Get raw derivative of smoothed vorticity
1360  double& dvorticity_dx,
1361  const unsigned& index) const
1362  {
1363  // Find out how many nodes there are
1364  unsigned n_node=this->nnode();
1365 
1366  // Set up memory for the shape functions
1367  Shape psif(n_node);
1368 
1369  // Set up memory for the shape function derivatives
1370  DShape dpsifdx(n_node,2);
1371 
1372  // Call the derivatives of the shape and test functions
1373  this->dshape_eulerian(s,psif,dpsifdx);
1374 
1375  // Initialise value to zero
1376  dvorticity_dx=0.0;
1377 
1378  // Use a switch statement
1379  switch (index)
1380  {
1381  case 0:
1382  // Loop over the nodes
1383  for (unsigned l=0;l<n_node;l++)
1384  {
1385  // Calculate the x derivative
1386  dvorticity_dx+=this->nodal_value(l,Smoothed_vorticity_index)*dpsifdx(l,0);
1387  }
1388  break;
1389  case 1:
1390  // Loop over the nodes
1391  for (unsigned l=0;l<n_node;l++)
1392  {
1393  // Calculate the y derivative
1394  dvorticity_dx+=this->nodal_value(l,Smoothed_vorticity_index)*dpsifdx(l,1);
1395  }
1396  break;
1397  default:
1398  oomph_info << "Never get here!" << std::endl;
1399  abort();
1400  }
1401  } // End of get_raw_vorticity_deriv
1402 
1403  /// Get raw derivative of smoothed derivative vorticity
1405  Vector<double>& dvorticity_dxdy) const
1406  {
1407  // Find out how many nodes there are
1408  unsigned n_node=this->nnode();
1409 
1410  // Set up memory for the shape functions
1411  Shape psif(n_node);
1412 
1413  // Set up memory for the shape function derivatives
1414  DShape dpsifdx(n_node,2);
1415 
1416  // Call the derivatives of the shape and test functions
1417  this->dshape_eulerian(s,psif,dpsifdx);
1418 
1419  // Initialise all entries to zero
1420  dvorticity_dxdy.initialise(0.0);
1421 
1422  // Loop over nodes
1423  for (unsigned l=0;l<n_node;l++)
1424  {
1425  // Loop over derivative directions to obtain xx and xy derivatives
1426  for (unsigned j=0;j<2;j++)
1427  {
1428  // Calculate xx and xy derivative
1429  dvorticity_dxdy[j]+=this->nodal_value(l,Smoothed_vorticity_index+1)*
1430  dpsifdx(l,j);
1431  }
1432 
1433  // Calculate the yy derivative
1434  dvorticity_dxdy[2]+=this->nodal_value(l,Smoothed_vorticity_index+2)*
1435  dpsifdx(l,1);
1436  } // for (unsigned l=0;l<n_node;l++)
1437  } // End of get_raw_vorticity_second_deriv
1438 
1439 
1440  /// Get raw derivative of smoothed derivative vorticity
1441  /// [0]: d^2/dx^2, [1]: d^2/dxdy, [2]: d^2/dy^2
1443  double& dvorticity_dxdy,
1444  const unsigned& index) const
1445  {
1446  // Find out how many nodes there are
1447  unsigned n_node=this->nnode();
1448 
1449  // Set up memory for the shape functions
1450  Shape psif(n_node);
1451 
1452  // Set up memory for the shape function derivatives
1453  DShape dpsifdx(n_node,2);
1454 
1455  // Call the derivatives of the shape and test functions
1456  this->dshape_eulerian(s,psif,dpsifdx);
1457 
1458  // Initialise value to zero
1459  dvorticity_dxdy=0.0;
1460 
1461  // Use a switch statement
1462  switch (index)
1463  {
1464  case 0:
1465  // Loop over the nodes
1466  for (unsigned l=0;l<n_node;l++)
1467  {
1468  // Calculate xx derivative
1469  dvorticity_dxdy+=this->nodal_value(l,Smoothed_vorticity_index+1)*
1470  dpsifdx(l,0);
1471  }
1472  break;
1473  case 1:
1474  // Loop over the nodes
1475  for (unsigned l=0;l<n_node;l++)
1476  {
1477  // Calculate xy derivative
1478  dvorticity_dxdy+=this->nodal_value(l,Smoothed_vorticity_index+1)*
1479  dpsifdx(l,1);
1480  }
1481  break;
1482  case 2:
1483  // Loop over the nodes
1484  for (unsigned l=0;l<n_node;l++)
1485  {
1486  // Calculate the yy derivative
1487  dvorticity_dxdy+=this->nodal_value(l,Smoothed_vorticity_index+2)*
1488  dpsifdx(l,1);
1489  }
1490  break;
1491  default:
1492  oomph_info << "Never get here!" << std::endl;
1493  abort();
1494  }
1495  } // End of get_raw_vorticity_second_deriv
1496 
1497  /// Get raw derivative of smoothed derivative vorticity
1498  /// [0]: d^3/dx^3, [1]: d^3/dx^2dy, [2]: d^3/dxdy^2, [3]: d^3/dy^3
1500  Vector<double>& dvorticity_dxdxdy) const
1501  {
1502  // Find out how many nodes there are
1503  unsigned n_node=this->nnode();
1504 
1505  // Set up memory for the shape functions
1506  Shape psif(n_node);
1507 
1508  // Set up memory for the shape function derivatives
1509  DShape dpsifdx(n_node,2);
1510 
1511  // Call the derivatives of the shape and test functions
1512  this->dshape_eulerian(s,psif,dpsifdx);
1513 
1514  // Initialise all entries to zero
1515  dvorticity_dxdxdy.initialise(0.0);
1516 
1517  // Loop over the nodes
1518  for (unsigned l=0;l<n_node;l++)
1519  {
1520  // d^3/dx^3 = d/dx \overline{d^2/dx^2}
1521  dvorticity_dxdxdy[0]+=this->nodal_value(l,Smoothed_vorticity_index+3)*
1522  dpsifdx(l,0);
1523 
1524  // d^3/dx^2dy = d/dx \overline{d^2/dxdy}
1525  dvorticity_dxdxdy[1]+=this->nodal_value(l,Smoothed_vorticity_index+4)*
1526  dpsifdx(l,0);
1527 
1528  // d^3/dxdy^2 = d/dy \overline{d^2/dxdy}
1529  dvorticity_dxdxdy[2]+=this->nodal_value(l,Smoothed_vorticity_index+4)*
1530  dpsifdx(l,1);
1531 
1532  // d^3/dy^3 = d/dy \overline{d^2/dy^2}
1533  dvorticity_dxdxdy[3]+=this->nodal_value(l,Smoothed_vorticity_index+5)*
1534  dpsifdx(l,1);
1535  }
1536  } // End of get_raw_vorticity_third_deriv
1537 
1538 
1539  /// Get raw derivative of smoothed derivative vorticity
1540  /// [0]: d^3/dx^3, [1]: d^3/dx^2dy, [2]: d^3/dxdy^2, [3]: d^3/dy^3,
1542  double& dvorticity_dxdxdy,
1543  const unsigned& index) const
1544  {
1545  // Find out how many nodes there are
1546  unsigned n_node=this->nnode();
1547 
1548  // Set up memory for the shape functions
1549  Shape psif(n_node);
1550 
1551  // Set up memory for the shape function derivatives
1552  DShape dpsifdx(n_node,2);
1553 
1554  // Call the derivatives of the shape and test functions
1555  this->dshape_eulerian(s,psif,dpsifdx);
1556 
1557  // Initialise value to zero
1558  dvorticity_dxdxdy=0.0;
1559 
1560  // Use a switch statement
1561  switch (index)
1562  {
1563  case 0:
1564  // Loop over the nodes
1565  for (unsigned l=0;l<n_node;l++)
1566  {
1567  // d^3/dx^3 = d/dx \overline{d^2/dx^2}
1568  dvorticity_dxdxdy+=this->nodal_value(l,Smoothed_vorticity_index+3)*
1569  dpsifdx(l,0);
1570  }
1571  break;
1572  case 1:
1573  // Loop over the nodes
1574  for (unsigned l=0;l<n_node;l++)
1575  {
1576  // d^3/dx^2dy = d/dx \overline{d^2/dxdy}
1577  dvorticity_dxdxdy+=this->nodal_value(l,Smoothed_vorticity_index+4)*
1578  dpsifdx(l,0);
1579  }
1580  break;
1581  case 2:
1582  // Loop over the nodes
1583  for (unsigned l=0;l<n_node;l++)
1584  {
1585  // d^3/dxdy^2 = d/dy \overline{d^2/dxdy}
1586  dvorticity_dxdxdy+=this->nodal_value(l,Smoothed_vorticity_index+4)*
1587  dpsifdx(l,1);
1588  }
1589  break;
1590  case 3:
1591  // Loop over the nodes
1592  for (unsigned l=0;l<n_node;l++)
1593  {
1594  // d^3/dy^3 = d/dy \overline{d^2/dy^2}
1595  dvorticity_dxdxdy+=this->nodal_value(l,Smoothed_vorticity_index+5)*
1596  dpsifdx(l,1);
1597  }
1598  break;
1599  default:
1600  oomph_info << "Never get here!" << std::endl;
1601  abort();
1602  }
1603  } // End of get_raw_vorticity_third_deriv
1604 
1605  /// \short Compute the element's contribution to the (squared) L2 norm
1606  /// of the difference between exact and smoothed vorticity. The input
1607  /// i corresponds to the i-th dof stored at each node (excluding the
1608  /// velocities and pressure).
1609  double vorticity_error_squared(const unsigned& i)
1610  {
1611 #ifdef PARANOID
1612  // Number of derivatives to be recovered
1613  unsigned n_recovered_derivs=(nvorticity_derivatives_to_recover()+
1614  nvelocity_derivatives_to_recover());
1615 
1616  // We cannot calculate this if we're not recovering the data
1617  if ((n_recovered_derivs==0)||(i>=n_recovered_derivs))
1618  {
1619  // Throw an error
1620  throw OomphLibError("Can't calculate this; not recovering enough data.",
1621  OOMPH_CURRENT_FUNCTION,
1622  OOMPH_EXCEPTION_LOCATION);
1623  }
1624 #endif
1625 
1626  // Create a container for the synthetic quantities
1627  Vector<Vector<double> > synth_vort_and_derivs=
1628  create_container_for_vorticity_and_derivatives();
1629 
1630  // Get the appropriate indices associated with the i-th recovered dof
1631  std::pair<unsigned,unsigned> indices=recovered_dof_to_container_id(i);
1632 
1633  // Find out how much information we need to calculate
1634  unsigned n_vector=synth_vort_and_derivs.size();
1635 
1636  // Initialise the norm squared value
1637  double norm_squared=0.0;
1638 
1639  // Find out how many nodes there are in the element
1640  unsigned n_node=this->nnode();
1641 
1642  // Set up memory for the shape functions
1643  Shape psif(n_node);
1644 
1645  // Set up memory for the shape function derivatives
1646  DShape dpsifdx(n_node,2);
1647 
1648  // Number of integration points
1649  unsigned n_intpt=this->integral_pt()->nweight();
1650 
1651  // Create the vector to hold local coordinates
1652  Vector<double> s(N_dim,0.0);
1653 
1654  // Create the vector to hold the global coordinates
1655  Vector<double> x(N_dim,0.0);
1656 
1657  // Loop over the integration points
1658  for (unsigned ipt=0;ipt<n_intpt;ipt++)
1659  {
1660  // Loop over the coordinates
1661  for (unsigned ii=0;ii<N_dim;ii++)
1662  {
1663  // Get the local coordinate value
1664  s[ii]=this->integral_pt()->knot(ipt,ii);
1665  }
1666 
1667  // Calculate the corresponding global coordinate
1668  this->interpolated_x(s,x);
1669 
1670  // Get the integral weight
1671  double w=this->integral_pt()->weight(ipt);
1672 
1673  // Call the derivatives of the shape and test functions
1674  double J=this->dshape_eulerian(s,psif,dpsifdx);
1675 
1676  // Pre-multiply the weights and the Jacobian
1677  double W=w*J;
1678 
1679  // Initialise the smoothed vorticity value
1680  double smoothed_vort=0.0;
1681 
1682  // Smoothed vorticity
1683  for (unsigned l=0;l<n_node;l++)
1684  {
1685  // Update the smoothed vorticity value
1686  smoothed_vort+=this->nodal_value(l,Smoothed_vorticity_index+i)*psif[l];
1687  }
1688 
1689  // Initialise the entries of the storage for the vorticity and derivatives
1690  for (unsigned jj=0;jj<n_vector;jj++)
1691  {
1692  // Initialise the entries to zero
1693  synth_vort_and_derivs[jj].initialise(0.0);
1694  }
1695 
1696  // If pointer isn't null
1697  if (0!=Exact_vorticity_fct_pt)
1698  {
1699  // Use the function pointer to calculate the appropriate quantities
1700  Exact_vorticity_fct_pt(x,synth_vort_and_derivs);
1701  }
1702 
1703  // Initialise the synthetic quantity
1704  double synth_quantity=0.0;
1705 
1706  // Calculate the synthetic quantity
1707  synth_quantity=(synth_vort_and_derivs[indices.first])[indices.second];
1708 
1709  // Add the squared difference
1710  norm_squared+=pow(smoothed_vort-synth_quantity,2)*W;
1711  } // for (unsigned ipt=0;ipt<n_intpt;ipt++)
1712 
1713  // Return the norm squared value
1714  return norm_squared;
1715  } // End of vorticity_error_squared
1716 
1717 
1718  /// \short Compute smoothed vorticity and its derivatives
1720  Vector<Vector<double> >& vort_and_derivs) const
1721  {
1722  // Get the number of nodes in this element
1723  unsigned n_node=this->nnode();
1724 
1725  // Shape functions
1726  Shape psif(n_node);
1727 
1728  // Get the shape function value at the given local coordinate
1729  this->shape(s,psif);
1730 
1731  // Find out how much information we need to calculate
1732  unsigned n_vector=vort_and_derivs.size();
1733 
1734  // Initialise a counter (holds the dof number)
1735  unsigned i_dof=0;
1736 
1737  // Loop over the vectors
1738  for (unsigned i=0;i<n_vector;i++)
1739  {
1740  // Initialise entries to zero
1741  vort_and_derivs[i].initialise(0.0);
1742 
1743  // Find out how many entries there are in the i-th vector
1744  unsigned num_entries=vort_and_derivs[i].size();
1745 
1746  // Loop over the entries
1747  for (unsigned j=0;j<num_entries;j++)
1748  {
1749  // Loop over the nodes
1750  for (unsigned l=0;l<n_node;l++)
1751  {
1752  // Get the contribution to the smoothed derivative from the l-th node
1753  (vort_and_derivs[i])[j]+=
1754  this->nodal_value(l,Smoothed_vorticity_index+i_dof)*psif[l];
1755  }
1756 
1757  // Increment the counter
1758  i_dof++;
1759  } // for (unsigned j=0;j<num_entries;j++)
1760  } // for (unsigned i=0;i<n_vector;i++)
1761  } // End of vorticity_and_its_derivs
1762 
1763  private:
1764 
1765  /// Number of dimensions in the element
1766  unsigned N_dim;
1767 
1768  /// \short Index of smoothed vorticity -- followed by derivatives;
1769  /// in 2D this has value 3
1771 
1772  /// \short The current maximum order of vorticity derivatives that can be
1773  /// recovered. Currently, we can recover up to the third derivative:
1774  /// omega,d/dx,d/dy,
1775  /// d^2/dx^2,d^2/dxdy,d^2/dy^2,
1776  /// d^3/dx^3,d^3/dx^2dy,d^3/dxdy^2,d^3/dy^3
1778 
1779  /// \short The current maximum order of velocity derivatives that can be
1780  /// recovered. Currently, we can recover the first derivatives:
1781  /// du/dx,du/dy,dv/dx,dv/dy
1783 
1784  /// \short Number of values per field; how many of the following do we want:
1785  /// u,v,p,omega,d/dx,d/dy,
1786  /// d^2/dx^2,d^2/dxdy,d^2/dy^2,
1787  /// d^3/dx^3,d^3/dx^2dy,d^3/dxdy^2,d^3/dy^3,
1788  /// du/dx,du/dy,dv/dx,dv/dy
1790 
1791  /// \short Maximum number of derivatives to retain in the vorticity
1792  /// recovery. Note, the value -1 means we ONLY output u,v[,w],p.
1794 
1795  /// \short Maximum number of derivatives to retain in the velocity
1796  /// recovery. Note, the value 0 means we don't calculate the derivatives
1797  /// of the velocity
1799 
1800  /// \short Pointer to function that specifies exact vorticity and
1801  /// derivs (for validation).
1802  ExactVorticityFctPt Exact_vorticity_fct_pt;
1803  };
1804 } // End of namespace oomph
1805 
1806 
1807 //////////////////////////////////////////////////////////////////////
1808 //////////////////////////////////////////////////////////////////////
1809 //////////////////////////////////////////////////////////////////////
1810 
1811 
1812 //========================================================
1813 /// Smoother for vorticity in 2D
1814 //========================================================
1815 template<class ELEMENT>
1817 {
1818 public:
1819 
1820  /// Constructor: Set order of recovery shape functions
1821  VorticitySmoother(const unsigned& recovery_order) :
1822  Recovery_order(recovery_order)
1823  {}
1824 
1825  /// Broken copy constructor
1827  {
1828  BrokenCopy::broken_copy("VorticitySmoother");
1829  }
1830 
1831  /// Broken assignment operator
1833  {
1834  BrokenCopy::broken_assign("VorticitySmoother");
1835  }
1836 
1837  /// Empty virtual destructor
1839 
1840  /// Access function for order of recovery polynomials
1841  unsigned& recovery_order()
1842  {
1843  // Return the order of recovery
1844  return Recovery_order;
1845  }
1846 
1847  /// \short Recovery shape functions as functions of the global, Eulerian
1848  /// coordinate x of dimension dim. The recovery shape functions are complete
1849  /// polynomials of the order specified by Recovery_order.
1850  void shape_rec(const Vector<double>& x,Vector<double>& psi_r)
1851  {
1852  // Create an ostringstream object to create a string
1853  std::ostringstream error_stream;
1854 
1855  // Find order of recovery shape functions
1856  switch(recovery_order())
1857  {
1858  case 1:
1859  // Complete linear polynomial in 2D:
1860  psi_r[0]=1.0;
1861  psi_r[1]=x[0];
1862  psi_r[2]=x[1];
1863  break;
1864 
1865  case 2:
1866  // Complete quadratic polynomial in 2D:
1867  psi_r[0]=1.0;
1868  psi_r[1]=x[0];
1869  psi_r[2]=x[1];
1870  psi_r[3]=x[0]*x[0];
1871  psi_r[4]=x[0]*x[1];
1872  psi_r[5]=x[1]*x[1];
1873  break;
1874 
1875  case 3:
1876  // Complete cubic polynomial in 2D:
1877  psi_r[0]=1.0;
1878  psi_r[1]=x[0];
1879  psi_r[2]=x[1];
1880  psi_r[3]=x[0]*x[0];
1881  psi_r[4]=x[0]*x[1];
1882  psi_r[5]=x[1]*x[1];
1883  psi_r[6]=x[0]*x[0]*x[0];
1884  psi_r[7]=x[0]*x[0]*x[1];
1885  psi_r[8]=x[0]*x[1]*x[1];
1886  psi_r[9]=x[1]*x[1]*x[1];
1887  break;
1888 
1889  default:
1890  // Create an error message for this case
1891  error_stream << "Recovery shape functions for recovery order "
1892  << recovery_order() << " haven't yet been implemented for 2D"
1893  << std::endl;
1894 
1895  // Throw an error
1896  throw OomphLibError(error_stream.str(),
1897  OOMPH_CURRENT_FUNCTION,
1898  OOMPH_EXCEPTION_LOCATION);
1899  }
1900  } // End of shape_rec
1901 
1902 
1903 
1904  /// Integation scheme associated with the recovery shape functions
1905  /// must be of sufficiently high order to integrate the mass matrix
1906  /// associated with the recovery shape functions. The argument is the
1907  /// dimension of the elements.
1908  /// The integration is performed locally over the elements, so the
1909  /// integration scheme does depend on the geometry of the element.
1910  /// The type of element is specified by the boolean which is
1911  /// true if elements in the patch are QElements and false if they are
1912  /// TElements (will need change if we ever have other element types)
1913  Integral* integral_rec(const bool& is_q_mesh)
1914  {
1915  // Create an ostringstream object to create a string
1916  std::ostringstream error_stream;
1917 
1918  //----
1919  // 2D:
1920  //----
1921  /// Find order of recovery shape functions
1922  switch(recovery_order())
1923  {
1924  case 1:
1925  // Complete linear polynomial in 2D:
1926  if (is_q_mesh)
1927  {
1928  // Return the appropriate Gauss integration scheme
1929  return(new Gauss<2,2>);
1930  }
1931  else
1932  {
1933  // Return the appropriate Gauss integration scheme
1934  return(new TGauss<2,2>);
1935  }
1936  break;
1937 
1938  case 2:
1939  // Complete quadratic polynomial in 2D:
1940  if (is_q_mesh)
1941  {
1942  // Return the appropriate Gauss integration scheme
1943  return(new Gauss<2,3>);
1944  }
1945  else
1946  {
1947  // Return the appropriate Gauss integration scheme
1948  return(new TGauss<2,3>);
1949  }
1950  break;
1951 
1952  case 3:
1953  // Complete cubic polynomial in 2D:
1954  if (is_q_mesh)
1955  {
1956  // Return the appropriate Gauss integration scheme
1957  return(new Gauss<2,4>);
1958  }
1959  else
1960  {
1961  // Return the appropriate Gauss integration scheme
1962  return(new TGauss<2,4>);
1963  }
1964  break;
1965 
1966  default:
1967  // Create an error messaage
1968  error_stream << "Recovery shape functions for recovery order "
1969  << recovery_order() << " haven't yet been implemented for 2D"
1970  << std::endl;
1971 
1972  // Throw an error
1973  throw OomphLibError(error_stream.str(),
1974  OOMPH_CURRENT_FUNCTION,
1975  OOMPH_EXCEPTION_LOCATION);
1976  }
1977 
1978  // Dummy return (never get here)
1979  return 0;
1980  } // End of integral_rec
1981 
1982  /// \short Setup patches: For each vertex node pointed to by nod_pt,
1983  /// adjacent_elements_pt[nod_pt] contains the pointer to the vector that
1984  /// contains the pointers to the elements that the node is part of.
1985  /// Also returns a Vector of vertex nodes for use in get_element_errors.
1986  void setup_patches(Mesh*& mesh_pt,
1987  std::map<Node*,Vector<ELEMENT*>*>& adjacent_elements_pt,
1988  Vector<Node*>& vertex_node_pt)
1989  {
1990  // Clear: hierher should we do this in Z2 as well?
1991  adjacent_elements_pt.clear();
1992 
1993  // Auxiliary map that contains element-adjacency for ALL nodes
1994  std::map<Node*,Vector<ELEMENT*>*> aux_adjacent_elements_pt;
1995 
1996 #ifdef PARANOID
1997  // Check if all elements request the same recovery order
1998  unsigned ndisagree=0;
1999 #endif
2000 
2001  // Loop over all elements to setup adjacency for all nodes.
2002  // Need to do this because midside nodes can be corner nodes for
2003  // adjacent smaller elements! Admittedly, the inclusion of interior
2004  // nodes is wasteful...
2005  unsigned nelem=mesh_pt->nelement();
2006  for (unsigned e=0;e<nelem;e++)
2007  {
2008  ELEMENT* el_pt=dynamic_cast<ELEMENT*>(mesh_pt->element_pt(e));
2009 
2010 #ifdef PARANOID
2011  // Check if all elements request the same recovery order
2012  if (el_pt->nrecovery_order()!=Recovery_order){ndisagree++;}
2013 #endif
2014 
2015  // Loop all nodes in element
2016  unsigned nnod=el_pt->nnode();
2017  for (unsigned n=0;n<nnod;n++)
2018  {
2019  // Make a pointer to the n-th node
2020  Node* nod_pt=el_pt->node_pt(n);
2021 
2022  // Has this node been considered before?
2023  if (aux_adjacent_elements_pt[nod_pt]==0)
2024  {
2025  // Create Vector of pointers to its adjacent elements
2026  aux_adjacent_elements_pt[nod_pt]=new Vector<ELEMENT*>;
2027  }
2028 
2029  // Add pointer to adjacent element
2030  (*aux_adjacent_elements_pt[nod_pt]).push_back(el_pt);
2031  }
2032  } // end element loop
2033 
2034 #ifdef PARANOID
2035  // Check if all elements request the same recovery order
2036  if (ndisagree!=0)
2037  {
2038  oomph_info << "\n\n======================================================\n"
2039  << "WARNING:\n"
2040  << ndisagree << " out of " << mesh_pt->nelement() << " elements"
2041  << "\nhave different preferences for the order of the recovery"
2042  << "\nshape functions. We are using: Recovery_order="
2043  << Recovery_order << std::endl;
2044  oomph_info << "======================================================\n\n";
2045  }
2046 #endif
2047 
2048  // Loop over all elements, extract adjacency for corner nodes only
2049  nelem=mesh_pt->nelement();
2050  for (unsigned e=0;e<nelem;e++)
2051  {
2052  ELEMENT* el_pt=dynamic_cast<ELEMENT*>(mesh_pt->element_pt(e));
2053 
2054  // Loop over corner nodes
2055  unsigned n_node=el_pt->nvertex_node();
2056  for (unsigned n=0;n<n_node;n++)
2057  {
2058  Node* nod_pt=el_pt->vertex_node_pt(n);
2059 
2060  // Has this node been considered before?
2061  if (adjacent_elements_pt[nod_pt]==0)
2062  {
2063  // Add the node pointer to the vertex node container
2064  vertex_node_pt.push_back(nod_pt);
2065 
2066  // Create Vector of pointers to its adjacent elements
2067  adjacent_elements_pt[nod_pt]=new Vector<ELEMENT*>;
2068 
2069  // Copy across:
2070  unsigned nel=(*aux_adjacent_elements_pt[nod_pt]).size();
2071  for (unsigned e=0;e<nel;e++)
2072  {
2073  (*adjacent_elements_pt[nod_pt]).push_back(
2074  (*aux_adjacent_elements_pt[nod_pt])[e]);
2075  }
2076  }
2077  }
2078  } // End of loop over elements
2079 
2080  // Cleanup
2081  for (typename std::map<Node*,Vector<ELEMENT*>*>::iterator it=
2082  aux_adjacent_elements_pt.begin();
2083  it!=aux_adjacent_elements_pt.end();it++)
2084  {
2085  delete it->second;
2086  }
2087  } // End of setup_patches
2088 
2089  /// \short Given the vector of elements that make up a patch, compute
2090  /// the vector of recovered vorticity coefficients and return a pointer
2091  /// to it. n_deriv indicates which derivative of the vorticity is
2092  /// supposed to be smoothed: 0: zeroth (i.e. the vorticity itself)
2093  /// 1: d/dx; 2: d/dy; 3: d^2/dx^2; 4: d^2/dxdy 5: d^2/dy^2
2094  /// 6: d^3/dx^3, 7: d^3/dx^2dy, 8: d^3/dxdy^2, 9: d^3/dy^3,
2095  /// 10: du/dx, 11: du/dy, 12: dv/dx, 13: dv/dy
2097  const Vector<ELEMENT*>& patch_el_pt,
2098  const unsigned& num_recovery_terms,
2099  Vector<double>*& recovered_vorticity_coefficient_pt,
2100  unsigned& n_deriv)
2101  {
2102  // Find the number of elements in the patch
2103  unsigned nelem=patch_el_pt.size();
2104 
2105  // Get a pointer to any element
2106  ELEMENT* el_pt=patch_el_pt[0];
2107 
2108 #ifdef PARANOID
2109  // If there's at least one element
2110  if (nelem>0)
2111  {
2112  // Get the number of vorticity derivatives to recover
2113  int n_vort_derivs=el_pt->get_maximum_order_of_vorticity_derivative();
2114 
2115  // Get the number of vorticity derivatives to recover
2116  int n_veloc_derivs=el_pt->get_maximum_order_of_velocity_derivative();
2117 
2118  // If we're not recovering anything, we shouldn't be here
2119  if (n_vort_derivs+n_veloc_derivs==-1)
2120  {
2121  // Create an ostringstream object to create an error message
2122  std::ostringstream error_stream;
2123 
2124  // Create the error message
2125  error_stream << "Not recovering anything. Change the maximum number "
2126  << "of derivatives to recover.";
2127 
2128  // Throw an error
2129  throw OomphLibError(error_stream.str(),
2130  OOMPH_CURRENT_FUNCTION,
2131  OOMPH_EXCEPTION_LOCATION);
2132  }
2133  } // if (nelem>0)
2134 #endif
2135 
2136  // Find the container indices associated with n_deriv
2137  std::pair<unsigned,unsigned> container_id=
2138  el_pt->vorticity_dof_to_container_id(n_deriv);
2139 
2140  // Maximum vorticity derivative order we can recover
2141  unsigned max_recoverable_vort_order=el_pt->
2142  get_maximum_order_of_recoverable_vorticity_derivative();
2143 
2144  // Maximum velocity derivative order we can recover
2145  unsigned max_recoverable_veloc_order=el_pt->
2146  get_maximum_order_of_recoverable_velocity_derivative();
2147 
2148  // Make a counter
2149  unsigned counter=0;
2150 
2151  // Calculate the case value (initialise to -1 so we know if it's set later)
2152  int case_value=-1;
2153 
2154  // Loop over the derivatives
2155  for (unsigned i=0;i<max_recoverable_vort_order+1;i++)
2156  {
2157  // Increment by the number of partial derivatives of order i
2158  counter+=el_pt->npartial_derivative(i);
2159 
2160  // If we've exceeded the value of n_deriv then we know which vorticity
2161  // derivative to recover
2162  if (n_deriv<counter)
2163  {
2164  // We need to recover the i-th order of derivative of the vorticity
2165  case_value=i;
2166 
2167  // We're done here
2168  break;
2169  }
2170  } // for (unsigned i=0;i<max_recoverable_order+1;i++)
2171 
2172  // If we haven't set the case value yet then we must be recovering a
2173  // velocity derivative
2174  if (case_value==-1)
2175  {
2176  // Loop over the velocity order
2177  for (unsigned i=1;i<max_recoverable_veloc_order+1;i++)
2178  {
2179  // Increment by the number of velocity partial derivatives of order i
2180  counter+=2*el_pt->npartial_derivative(i);
2181 
2182  // If we've exceeded the value of n_deriv then we know which vorticity
2183  // derivative to recover
2184  if (n_deriv<counter)
2185  {
2186  // We need to recover the i-th order of derivative of the vorticity
2187  case_value=max_recoverable_vort_order+i;
2188 
2189  // We're done here
2190  break;
2191  }
2192  } // for (unsigned i=1;i<max_recoverable_veloc_order+1;i++)
2193  } // if (case_value==-1)
2194 
2195 #ifdef PARANOID
2196  // Sanity check: if the case value hasn't been set then something's wrong
2197  if (case_value==-1)
2198  {
2199  // Create a ostringstream object to create an error message
2200  std::ostringstream error_message_stream;
2201 
2202  // Create an error message
2203  error_message_stream << "Case order has not been set. Something's wrong!";
2204 
2205  // Throw an error
2206  throw OomphLibError(error_message_stream.str(),
2207  OOMPH_CURRENT_FUNCTION,
2208  OOMPH_EXCEPTION_LOCATION);
2209  }
2210 #endif
2211 
2212  // Create space for the recovered quantity
2213  double recovered_quantity=0.0;
2214 
2215  // Create/initialise matrix for linear system
2216  DenseDoubleMatrix recovery_mat(num_recovery_terms,num_recovery_terms,0.0);
2217 
2218  // Create/initialise vector for RHS
2219  Vector<double> rhs(num_recovery_terms,0.0);
2220 
2221  // Create a new integration scheme based on the recovery order
2222  // in the elements. Need to find the type of the element, default
2223  // is to assume a quad
2224  bool is_q_mesh=true;
2225 
2226  // If we can dynamic cast to the TElementBase, then it's a triangle/tet
2227  // Note that I'm assuming that all elements are of the same geometry, but
2228  // if they weren't we could adapt...
2229  if (dynamic_cast<TElementBase*>(patch_el_pt[0]))
2230  {
2231  // We're dealing with a triangle-based mesh so change the bool value
2232  is_q_mesh=false;
2233  }
2234 
2235  // Get a pointer to the appropriate integration type
2236  Integral* const integ_pt=this->integral_rec(is_q_mesh);
2237 
2238  // Loop over all elements in patch to assemble linear system
2239  for (unsigned e=0;e<nelem;e++)
2240  {
2241  // Get pointer to element
2242  ELEMENT* const el_pt=patch_el_pt[e];
2243 
2244  // Create storage for the recovery shape function values
2245  Vector<double> psi_r(num_recovery_terms);
2246 
2247  // Create vector to hold local coordinates
2248  Vector<double> s(2,0.0);
2249 
2250  // Find the number of integration points
2251  unsigned n_intpt=integ_pt->nweight();
2252 
2253  // Loop over the integration points
2254  for (unsigned ipt=0;ipt<n_intpt;ipt++)
2255  {
2256  // Assign values of s, the local coordinate
2257  for (unsigned i=0;i<2;i++)
2258  {
2259  // Get the i-th entry of the local coordinate
2260  s[i]=integ_pt->knot(ipt,i);
2261  }
2262 
2263  // Get the integral weight
2264  double w=integ_pt->weight(ipt);
2265 
2266  // Jacobian of mapping
2267  double J=el_pt->J_eulerian(s);
2268 
2269  // Allocate space for the global coordinates
2270  Vector<double> x(2,0.0);
2271 
2272  // Interpolate the global (Eulerian) coordinate
2273  el_pt->interpolated_x(s,x);
2274 
2275  // Premultiply the weights and the Jacobian and the geometric
2276  // Jacobian weight (used in axisymmetric and spherical coordinate
2277  // systems) -- hierher really fct of x? probably yes, actually).
2278  double W=w*J*(el_pt->geometric_jacobian(x));
2279 
2280  // Recovery shape functions at global (Eulerian) coordinate
2281  shape_rec(x,psi_r);
2282 
2283  // Use a switch statement to decide on which function to call
2284  switch (case_value)
2285  {
2286  case 0:
2287  {
2288  Vector<double> vorticity(1,0.0);
2289  el_pt->get_vorticity(s,vorticity);
2290  recovered_quantity=vorticity[0];
2291  break;
2292  }
2293  case 1:
2294  {
2295  el_pt->get_raw_vorticity_deriv(s,recovered_quantity,
2296  container_id.second);
2297  break;
2298  }
2299  case 2:
2300  {
2301  el_pt->get_raw_vorticity_second_deriv(s,recovered_quantity,
2302  container_id.second);
2303  break;
2304  }
2305  case 3:
2306  {
2307  el_pt->get_raw_vorticity_third_deriv(s,recovered_quantity,
2308  container_id.second);
2309  break;
2310  }
2311  case 4:
2312  {
2313  el_pt->get_raw_velocity_deriv(s,recovered_quantity,
2314  container_id.second);
2315  break;
2316  }
2317  default:
2318  {
2319  oomph_info << "Never get here." << std::endl;
2320  abort();
2321  }
2322  }
2323 
2324  // Add elemental RHSs and recovery matrix to global versions
2325  //----------------------------------------------------------
2326  // RHS: Loop over the nodes for the test functions
2327  for (unsigned l=0;l<num_recovery_terms;l++)
2328  {
2329  // Update the RHS entry ()
2330  rhs[l]+=recovered_quantity*psi_r[l]*W;
2331  }
2332 
2333  // Loop over the nodes for the test functions
2334  for (unsigned l=0;l<num_recovery_terms;l++)
2335  {
2336  // Loop over the nodes for the variables
2337  for (unsigned l2=0;l2<num_recovery_terms;l2++)
2338  {
2339  // Add contribution to recovery matrix
2340  recovery_mat(l,l2)+=psi_r[l]*psi_r[l2]*W;
2341  }
2342  } // for (unsigned l=0;l<num_recovery_terms;l++)
2343  } // for (unsigned ipt=0;ipt<n_intpt;ipt++)
2344  } // End of loop over elements that make up patch.
2345 
2346  // Delete the integration scheme
2347  delete integ_pt;
2348 
2349  // Linear system is now assembled: Solve recovery system
2350  //------------------------------------------------------
2351  // LU decompose the recovery matrix
2352  recovery_mat.ludecompose();
2353 
2354  // Back-substitute
2355  recovery_mat.lubksub(rhs);
2356 
2357  // Now create a matrix to store the vorticity recovery coefficients.
2358  // Pointer to this matrix will be returned.
2359  recovered_vorticity_coefficient_pt=new Vector<double>(num_recovery_terms);
2360 
2361  // Loop over the number of recovered terms
2362  for (unsigned icoeff=0;icoeff<num_recovery_terms;icoeff++)
2363  {
2364  // Copy the RHS value over
2365  (*recovered_vorticity_coefficient_pt)[icoeff]=rhs[icoeff];
2366  }
2367  } // End of get_recovered_vorticity_in_patch
2368 
2369  /// Get the recovery order
2370  unsigned nrecovery_order() const
2371  {
2372  // Use a switch statement
2373  switch(Recovery_order)
2374  {
2375  case 1:
2376  // Linear recovery shape functions
2377  //--------------------------------
2378  return 3; // 1, x, y
2379  break;
2380 
2381  case 2:
2382  // Quadratic recovery shape functions
2383  //-----------------------------------
2384  return 6; // 1, x, y, x^2, xy, y^2
2385  break;
2386 
2387  case 3:
2388  // Cubic recovery shape functions
2389  //--------------------------------
2390  return 10; // 1, x, y, x^2, xy, y^2, x^3, x^2 y, x y^2, y^3
2391  break;
2392 
2393  default:
2394  // Any other recovery order?
2395  //--------------------------
2396  // Use an ostringstream object to create an error message
2397  std::ostringstream error_stream;
2398 
2399  // Create an error message
2400  error_stream << "Wrong Recovery_order " << Recovery_order << std::endl;
2401 
2402  // Throw an error
2403  throw OomphLibError(error_stream.str(),
2404  OOMPH_CURRENT_FUNCTION,
2405  OOMPH_EXCEPTION_LOCATION);
2406  }
2407  } // End of nrecovery_order
2408 
2409  /// Recover vorticity from patches
2410  void recover_vorticity(Mesh* mesh_pt)
2411  {
2412  // Create a DocInfo object (used as a dummy argument)
2413  DocInfo doc_info;
2414 
2415  // Disable any documentation
2416  doc_info.disable_doc();
2417 
2418  // Recover the vorticity
2419  recover_vorticity(mesh_pt,doc_info);
2420  }
2421 
2422  /// \short Recover vorticity from patches -- output intermediate steps
2423  /// to directory specified by DocInfo object
2424  void recover_vorticity(Mesh* mesh_pt,DocInfo& doc_info)
2425  {
2426  // Start the timer
2427  double t_start=TimingHelpers::timer();
2428 
2429  // Allocate space for the local coordinates
2430  Vector<double> s(2,0.0);
2431 
2432  // Allocate space for the global coordinates
2433  Vector<double> x(2,0.0);
2434 
2435  // Make patches
2436  //-------------
2437  // Allocate space for the mapping from nodes to elements
2438  std::map<Node*,Vector<ELEMENT*>*> adjacent_elements_pt;
2439 
2440  // Allocate space for the vertex nodes
2441  Vector<Node*> vertex_node_pt;
2442 
2443  // Set up the patches information
2444  setup_patches(mesh_pt,adjacent_elements_pt,vertex_node_pt);
2445 
2446  // Grab any element (this shouldn't be a null pointer)
2447  ELEMENT* const el_pt=dynamic_cast<ELEMENT*>(mesh_pt->element_pt(0));
2448 
2449  // Get the index of the vorticity
2450  unsigned smoothed_vorticity_index=el_pt->smoothed_vorticity_index();
2451 
2452  // Maximum order of vorticity derivative (that can be recovered)
2453  unsigned max_vort_order=el_pt->
2454  get_maximum_order_of_recoverable_vorticity_derivative();
2455 
2456  // Maximum order of velocity derivative (that can be recovered)
2457  unsigned max_veloc_order=el_pt->
2458  get_maximum_order_of_recoverable_velocity_derivative();
2459 
2460  // Maximum number of recoverable vorticity terms
2461  unsigned max_vort_recov=0;
2462 
2463  // Maximum number of recoverable velocity terms
2464  unsigned max_veloc_recov=0;
2465 
2466  // Loop over the entries of the vector
2467  for (unsigned i=0;i<max_vort_order+1;i++)
2468  {
2469  // Get the number of partial derivatives of the vorticity
2470  max_vort_recov+=el_pt->npartial_derivative(i);
2471  }
2472 
2473  // Loop over the entries of the vector
2474  for (unsigned i=1;i<max_veloc_order+1;i++)
2475  {
2476  // Get the number of partial derivatives of the vorticity
2477  max_veloc_recov+=2*el_pt->npartial_derivative(i);
2478  }
2479 
2480  // Number of recovered vorticity derivatives
2481  unsigned n_recovered_vort_derivs=el_pt->nvorticity_derivatives_to_recover();
2482 
2483  // Number of recovered velocity derivatives
2484  unsigned n_recovered_veloc_derivs=el_pt->nvelocity_derivatives_to_recover();
2485 
2486  // Determine number of coefficients for expansion of recovered vorticity.
2487  // Use complete polynomial of given order for recovery
2488  unsigned num_recovery_terms=nrecovery_order();
2489 
2490  // Counter for averaging of recovered vorticity and its derivatives
2491  std::map<Node*,unsigned> count;
2492 
2493  // Counter for which nodal value we're assigning
2494  unsigned nodal_dof=0;
2495 
2496  // Loop over derivatives
2497  for (unsigned deriv=0;deriv<max_vort_recov+max_veloc_recov;deriv++)
2498  {
2499  // If we're not recovering this vorticity derivative. Note, we cast
2500  // to an int because n_recovered_vort_derivs can be zero (so subtracting
2501  // any positive integer can cause trouble)
2502  if ((int(deriv)>int(n_recovered_vort_derivs-1))&&(deriv<max_vort_recov))
2503  {
2504  // We're done here
2505  continue;
2506  }
2507  // If we're not recovering any of the velocity derivatives and we're
2508  // finished with the vorticity derivatives
2509  else if ((n_recovered_veloc_derivs==0)&&(deriv>=max_vort_recov))
2510  {
2511  // We're done here
2512  continue;
2513  }
2514 
2515  // Storage for accumulated nodal vorticity (used to compute nodal averages)
2516  std::map<Node*,double> averaged_recovered_vort;
2517 
2518  // Calculation of vorticity
2519  //-------------------------
2520  // Do patch recovery
2521  // unsigned counter=0;
2522  for (typename std::map<Node*,Vector<ELEMENT*>*>::iterator it=
2523  adjacent_elements_pt.begin();it!=adjacent_elements_pt.end();it++)
2524  {
2525  // Pointer to the recovered vorticity coefficients
2526  Vector<double>* recovered_vorticity_coefficient_pt;
2527 
2528  // Setup smoothed vorticity field for patches
2529  get_recovered_vorticity_in_patch(*(it->second),
2530  num_recovery_terms,
2531  recovered_vorticity_coefficient_pt,
2532  deriv);
2533 
2534  // Now get the nodal average of the recovered vorticity (nodes are
2535  // generally part of multiple patches):
2536 
2537  // Get the number of elements in adjacent_elements_pt
2538  unsigned nelem=(*(it->second)).size();
2539 
2540  // Loop over all elements to get recovered vorticity
2541  for (unsigned e=0;e<nelem;e++)
2542  {
2543  // Get pointer to element
2544  ELEMENT* const el_pt=(*(it->second))[e];
2545 
2546  // Get the number of nodes by element
2547  unsigned nnode_el=el_pt->nnode();
2548 
2549  // Loop over the nodes in the element
2550  for (unsigned j=0;j<nnode_el;j++)
2551  {
2552  // Get a pointer to the j-th node in this element
2553  Node* nod_pt=el_pt->node_pt(j);
2554 
2555  // Get the local coordinates of the node
2556  el_pt->local_coordinate_of_node(j,s);
2557 
2558  // Interpolate the global (Eulerian) coordinate
2559  el_pt->interpolated_x(s,x);
2560 
2561  // Recovery shape functions at global (Eulerian) coordinate
2562  Vector<double> psi_r(num_recovery_terms);
2563 
2564  // Recover the shape function values at the position x
2565  shape_rec(x,psi_r);
2566 
2567  // Initialise the value of the recovered quantity
2568  double recovered_vort=0.0;
2569 
2570  // Loop over the recovery terms
2571  for (unsigned i=0;i<num_recovery_terms;i++)
2572  {
2573  // Assemble recovered vorticity
2574  recovered_vort+=(*recovered_vorticity_coefficient_pt)[i]*psi_r[i];
2575  }
2576 
2577  // Keep adding
2578  averaged_recovered_vort[nod_pt]+=recovered_vort;
2579 
2580  // Increment the counter
2581  count[nod_pt]++;
2582  } // for (unsigned j=0;j<nnode_el;j++)
2583  } // for (unsigned e=0;e<nelem;e++)
2584 
2585  // Delete the recovered coefficient data
2586  delete recovered_vorticity_coefficient_pt;
2587 
2588  // Make it a null pointer
2589  recovered_vorticity_coefficient_pt=0;
2590  } // for (typename std::map<Node*,Vector<ELEMENT*>*>::iterator it=...
2591 
2592  // Find out how many nodes there are in the mesh
2593  unsigned nnod=mesh_pt->nnode();
2594 
2595  // Loop over all nodes to actually work out the average
2596  for (unsigned j=0;j<nnod;j++)
2597  {
2598  // Make a pointer to the j-th node
2599  Node* nod_pt=mesh_pt->node_pt(j);
2600 
2601  // Calculate the values of the smoothed vorticity
2602  averaged_recovered_vort[nod_pt]/=count[nod_pt];
2603 
2604  // Assign smoothed vorticity to nodal values
2605  nod_pt->set_value(smoothed_vorticity_index+nodal_dof,
2606  averaged_recovered_vort[nod_pt]);
2607  }
2608 
2609  // We're done with this dof so increment the counter
2610  nodal_dof++;
2611 
2612  // Start again
2613  count.clear();
2614  } // for (unsigned deriv=0;deriv<max_vort_recov+max_veloc_recov;deriv++)
2615 
2616  // Cleanup
2617  for (typename std::map<Node*,Vector<ELEMENT*>*>::iterator it=
2618  adjacent_elements_pt.begin();it!=adjacent_elements_pt.end();it++)
2619  {
2620  // Delete the vector of element pointers
2621  delete it->second;
2622  }
2623 
2624  // Inform the user
2625  oomph_info << "Time for vorticity recovery [sec]: "
2626  << TimingHelpers::timer()-t_start << std::endl;
2627  } // End of recover_vorticity
2628 
2629 private:
2630 
2631  /// Order of recovery polynomials
2632  unsigned Recovery_order;
2633 };
2634 
2635 #endif
void broken_copy(const std::string &class_name)
Issue error message and terminate execution.
void get_raw_vorticity_second_deriv(const Vector< double > &s, double &dvorticity_dxdy, const unsigned &index) const
double vorticity_error_squared(const unsigned &i)
Compute the element&#39;s contribution to the (squared) L2 norm of the difference between exact and smoot...
int Maximum_order_of_vorticity_derivative
Maximum number of derivatives to retain in the vorticity recovery. Note, the value -1 means we ONLY o...
std::string scalar_name_paraview(const unsigned &i) const
Name of the i-th scalar field. Default implementation returns V1 for the first one, V2 for the second etc. Can (should!) be overloaded with more meaningful names in specific elements.
std::pair< unsigned, unsigned > vorticity_dof_to_container_id(const unsigned &i) const
Helper function that, given the local dof number of the i-th vorticity or velocity derivative...
void get_raw_vorticity_deriv(const Vector< double > &s, Vector< double > &dvorticity_dx) const
Get raw derivative of smoothed vorticity.
void setup_patches(Mesh *&mesh_pt, std::map< Node *, Vector< ELEMENT *> *> &adjacent_elements_pt, Vector< Node *> &vertex_node_pt)
Setup patches: For each vertex node pointed to by nod_pt, adjacent_elements_pt[nod_pt] contains the p...
int get_maximum_order_of_velocity_derivative() const
The maximum order of derivatives calculated in the velocity recovery. Note, this value can only be se...
void get_raw_velocity_deriv(const Vector< double > &s, Vector< double > &dveloc_dx) const
Get raw derivative of velocity.
unsigned get_maximum_order_of_recoverable_vorticity_derivative() const
The maximum order of vorticity derivative that can be recovered. This is set in the constructor and s...
void shape_rec(const Vector< double > &x, Vector< double > &psi_r)
Recovery shape functions as functions of the global, Eulerian coordinate x of dimension dim...
cstr elem_len * i
Definition: cfortran.h:607
void pin_smoothed_vorticity()
Pin all smoothed vorticity quantities.
void set_maximum_order_of_velocity_derivative(const int &max_deriv)
The maximum order of derivatives calculated in the velocity recovery.
int Maximum_order_of_velocity_derivative
Maximum number of derivatives to retain in the velocity recovery. Note, the value 0 means we don&#39;t ca...
unsigned nvorticity_derivatives_to_recover() const
The number of terms calculated in the vorticity recovery. Also includes the zeroth derivative...
ExactVorticityFctPt Exact_vorticity_fct_pt
Pointer to function that specifies exact vorticity and derivs (for validation).
void get_interpolated_values(const unsigned &t, const Vector< double > &s, Vector< double > &values)
Get the function value u in Vector. Note: Given the generality of the interface (this function is usu...
int get_maximum_order_of_vorticity_derivative() const
The maximum order of derivatives calculated in the vorticity recovery. Note, this value can only be s...
char t
Definition: cfortran.h:572
int maximum_order_of_vorticity_derivative() const
The maximum order of derivatives calculated in the vorticity recovery.
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:852
OomphInfo oomph_info
unsigned nscalar_paraview() const
Number of scalars/fields output by this element. Re-implements broken virtual function in base class...
void get_raw_vorticity_third_deriv(const Vector< double > &s, double &dvorticity_dxdxdy, const unsigned &index) const
e
Definition: cfortran.h:575
unsigned ncont_interpolated_values() const
Number of continuously interpolated values:
void pin(const unsigned &i)
Pin the i-th stored variable.
Definition: nodes.h:383
unsigned & recovery_order()
Access function for order of recovery polynomials.
VorticitySmoother(const VorticitySmoother &)
Broken copy constructor.
ExactVorticityFctPt & exact_vorticity_fct_pt()
Access function: Pointer to function that specifies exact vorticity and derivatives (for validation)...
unsigned nvelocity_derivatives_to_recover() const
unsigned npartial_derivative(const unsigned &n) const
Helper function that determines the number of n-th order partial derivatives in d-dimensions. Specifically there are (n+d-1)(choose)(d-1) possible n-th order partial derivatives in d-dimensions. Implementation makes use of the code found at: www.geeksforgeeks.org/space-and-time-efficient-binomial-coefficient/.
unsigned stored_dof_to_recoverable_dof(const unsigned &i) const
Given the STORED dof number, this function returns the global recovered number. For example...
void get_raw_vorticity_third_deriv(const Vector< double > &s, Vector< double > &dvorticity_dxdxdy) const
int maximum_order_of_velocity_derivative() const
The maximum order of derivatives calculated in the velocity recovery.
void get_recovered_vorticity_in_patch(const Vector< ELEMENT *> &patch_el_pt, const unsigned &num_recovery_terms, Vector< double > *&recovered_vorticity_coefficient_pt, unsigned &n_deriv)
Given the vector of elements that make up a patch, compute the vector of recovered vorticity coeffici...
virtual ~VorticitySmoother()
Empty virtual destructor.
unsigned Maximum_order_of_recoverable_vorticity_derivatives
The current maximum order of vorticity derivatives that can be recovered. Currently, we can recover up to the third derivative: omega,d/dx,d/dy, d^2/dx^2,d^2/dxdy,d^2/dy^2, d^3/dx^3,d^3/dx^2dy,d^3/dxdy^2,d^3/dy^3.
void output(std::ostream &outfile, const unsigned &nplot)
Overloaded output function: Output velocity, pressure and the smoothed vorticity. ...
void recover_vorticity(Mesh *mesh_pt)
Recover vorticity from patches.
unsigned npartial_derivative(const unsigned &n) const
Call the function written in VorticityRecoveryHelpers.
unsigned smoothed_vorticity_index() const
Index of smoothed vorticity – followed by derivatives.
Vector< Vector< double > > create_container_for_vorticity_and_derivatives() const
Helper function to create a container for the vorticity and its partial derivatives. If the user wishes to output everything then this also creates space for the velocity derivatives too. This function has been written to allow for generalisation of the storage without (hopefully!) affecting too much.
void recover_vorticity(Mesh *mesh_pt, DocInfo &doc_info)
Recover vorticity from patches – output intermediate steps to directory specified by DocInfo object...
unsigned Maximum_order_of_recoverable_velocity_derivatives
The current maximum order of velocity derivatives that can be recovered. Currently, we can recover the first derivatives: du/dx,du/dy,dv/dx,dv/dy.
static char t char * s
Definition: cfortran.h:572
unsigned Recovery_order
Order of recovery polynomials.
void output_smoothed_vorticity(std::ostream &outfile, const unsigned &nplot)
Output the velocity, smoothed vorticity and derivatives.
int Maximum_order_of_velocity_derivative
Maximum number of derivatives to retain in the velocity recovery. Note, the value 0 means we don&#39;t ca...
int Maximum_order_of_vorticity_derivative
Maximum number of derivatives to retain in the vorticity recovery. Note, the value -1 means we ONLY o...
double timer()
returns the time in seconds after some point in past
unsigned nrecovery_order() const
Get the recovery order.
void shape(const double &s, double *Psi)
Definition for 1D Lagrange shape functions. The value of all the shape functions at the local coordin...
Definition: shape.h:549
void initialise(const _Tp &__value)
Iterate over all values and set to the desired value.
Definition: Vector.h:171
void get_interpolated_values(const Vector< double > &s, Vector< double > &values)
Get the function value u in Vector. Note: Given the generality of the interface (this function is usu...
class VorticityRecoveryHelpers::RecoveryHelper Recovery_helper
void set_maximum_order_of_vorticity_derivative(const int &max_deriv)
The maximum order of derivatives calculated in the vorticity recovery.
void get_raw_velocity_deriv(const Vector< double > &s, double &dveloc_dx, const unsigned &index) const
Get raw derivative of velocity.
void get_raw_vorticity_deriv(const Vector< double > &s, double &dvorticity_dx, const unsigned &index) const
Get raw derivative of smoothed vorticity.
void get_raw_vorticity_second_deriv(const Vector< double > &s, Vector< double > &dvorticity_dxdy) const
Get raw derivative of smoothed derivative vorticity.
unsigned required_nvalue(const unsigned &n) const
Number of values required at local node n. In order to simplify matters, we allocate storage for pres...
void broken_assign(const std::string &class_name)
Issue error message and terminate execution.
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn&#39;t been defined.
void vorticity_and_its_derivs(const Vector< double > &s, Vector< Vector< double > > &vort_and_derivs) const
Compute smoothed vorticity and its derivatives.
std::pair< unsigned, unsigned > recovered_dof_to_container_id(const unsigned &i) const
Helper function that, given the local dof number of the i-th vorticity or velocity derivative...
void scalar_value_paraview(std::ofstream &file_out, const unsigned &i, const unsigned &nplot) const
Write values of the i-th scalar field at the plot points. Needs to be implemented for each new specif...
unsigned get_maximum_order_of_recoverable_velocity_derivative() const
The maximum order of velocity derivative that can be recovered. This is set in the constructor and sh...
ExactVorticityFctPt exact_vorticity_fct_pt() const
Access function: Pointer to function that specifies exact vorticity and derivatives (for validation) ...
VorticitySmoother(const unsigned &recovery_order)
Constructor: Set order of recovery shape functions.
Integral * integral_rec(const bool &is_q_mesh)
unsigned ncont_interpolated_values() const
Number of continuously interpolated values:
unsigned Number_of_values_per_field
Number of values per field; how many of the following do we want: u,v,p,omega,d/dx,d/dy, d^2/dx^2,d^2/dxdy,d^2/dy^2, d^3/dx^3,d^3/dx^2dy,d^3/dxdy^2,d^3/dy^3, du/dx,du/dy,dv/dx,dv/dy.
Class to indicate which derivatives of the vorticity/ velocity we want to recover. We choose to immediately instantiate an object of this class by dropping the semi-colon after the class description.
void output_analytical_veloc_and_vorticity(std::ostream &outfile, const unsigned &nplot)
Output exact velocity, vorticity, derivatives and indicator based on functions specified by two funct...
void operator=(const VorticitySmoother &)
Broken assignment operator.
unsigned Number_of_values_per_field
Number of values per field; how many of the following do we want: u,v,p,omega,d/dx,d/dy, d^2/dx^2,d^2/dxdy,d^2/dy^2, d^3/dx^3,d^3/dx^2dy,d^3/dxdy^2,d^3/dy^3, du/dx,du/dy,dv/dx,dv/dy.
Smoother for vorticity in 2D.
unsigned N_dim
Number of dimensions in the element.
std::string to_string(T object, unsigned float_precision=8)
Conversion function that should work for anything with operator<< defined (at least all basic types)...
unsigned Smoothed_vorticity_index
Index of smoothed vorticity – followed by derivatives; in 2D this has value 3.
void calculate_number_of_values_per_field()
Calculates the number of values per field given the number of vorticity and velocity derivatives to r...