Qelements.cc
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 //Non-inline member functions for Qelements
31 
32 //Include the appropriate headers
33 #include "Qelements.h"
34 
35 namespace oomph
36 {
37 
38 ////////////////////////////////////////////////////////////////
39 // 1D Qelements
40 ////////////////////////////////////////////////////////////////
41 
42 //=======================================================================
43 /// Assign the static Default_integration_scheme
44 //=======================================================================
45 template<unsigned NNODE_1D>
47 
48 
49 //==================================================================
50 /// Return the node at the specified local coordinate
51 //==================================================================
52 template<unsigned NNODE_1D>
55 {
56  //Load the tolerance into a local variable
58  //There is one possible index.
59  Vector<int> index(1);
60 
61  // Determine the index
62  // -------------------
63 
64  // If we are at the lower limit, the index is zero
65  if(std::fabs(s[0] + 1.0) < tol)
66  {
67  index[0] = 0;
68  }
69  // If we are at the upper limit, the index is the number of nodes minus 1
70  else if(std::fabs(s[0] - 1.0) < tol)
71  {
72  index[0] = NNODE_1D-1;
73  }
74  // Otherwise, we have to calculate the index in general
75  else
76  {
77  // For uniformly spaced nodes the node number would be
78  double float_index = 0.5*(1.0 + s[0])*(NNODE_1D-1);
79  // Convert to an integer by taking the floor (rounding down)
80  index[0] = static_cast<int>(std::floor(float_index));
81  // What is the excess. This should be safe because the
82  // we have rounded down
83  double excess = float_index - index[0];
84  // If the excess is bigger than our tolerance there is no node,
85  // return null
86  // Note that we test at both lower and upper ends.
87  if((excess > tol) && ((1.0 - excess) > tol))
88  {
89  return 0;
90  }
91  // If we are at the upper end (i.e. the system has actually rounded up)
92  // we need to add one to the index
93  if((1.0 - excess) <= tol) {index[0] += 1;}
94  }
95  // If we've got here we have a node, so let's return a pointer to it
96  return node_pt(index[0]);
97 }
98 
99 
100 //=======================================================================
101 ///Shape function for specific QElement<1,..>
102 //=======================================================================
103 template <unsigned NNODE_1D>
105  const
106 {
107  //Local storage for the shape functions
108  double Psi[NNODE_1D];
109  //Call the OneDimensional Shape functions
110  OneDimLagrange::shape<NNODE_1D>(s[0],Psi);
111 
112  //Now let's loop over the nodal points in the element
113  //and copy the values back in
114  for(unsigned i=0;i<NNODE_1D;i++) {psi[i] = Psi[i];}
115 }
116 
117 //=======================================================================
118 ///Derivatives of shape functions for specific QElement<1,..>
119 //=======================================================================
120 template <unsigned NNODE_1D>
122  DShape &dpsids) const
123 {
124  //Local storage
125  double Psi[NNODE_1D];
126  double DPsi[NNODE_1D];
127  //Call the shape functions and derivatives
128  OneDimLagrange::shape<NNODE_1D>(s[0],Psi);
129  OneDimLagrange::dshape<NNODE_1D>(s[0],DPsi);
130 
131  //Loop over shape functions in element and assign to psi
132  for(unsigned l=0;l<NNODE_1D;l++)
133  {
134  psi[l] = Psi[l];
135  dpsids(l,0) = DPsi[l];
136  }
137 }
138 
139 //=======================================================================
140 /// Second derivatives of shape functions for specific QElement<1,..>:
141 /// d2psids(i,0) = \f$ d^2 \psi_j / d s^2 \f$
142 //=======================================================================
143 template <unsigned NNODE_1D>
145  DShape &dpsids, DShape &d2psids) const
146 {
147  //Local storage for the shape functions
148  double Psi[NNODE_1D];
149  double DPsi[NNODE_1D];
150  double D2Psi[NNODE_1D];
151  //Call the shape functions and derivatives
152  OneDimLagrange::shape<NNODE_1D>(s[0],Psi);
153  OneDimLagrange::dshape<NNODE_1D>(s[0],DPsi);
154  OneDimLagrange::d2shape<NNODE_1D>(s[0],D2Psi);
155 
156  //Loop over shape functions in element and assign to psi
157  for(unsigned l=0;l<NNODE_1D;l++)
158  {
159  psi[l] = Psi[l];
160  dpsids(l,0) = DPsi[l];
161  d2psids(l,0) = D2Psi[l];
162  }
163 }
164 
165 //=======================================================================
166 /// The output function for general 1D QElements
167 //=======================================================================
168 template <unsigned NNODE_1D>
169 void QElement<1,NNODE_1D>::output(std::ostream &outfile)
170 {
171  output(outfile, NNODE_1D);
172 }
173 
174 //=======================================================================
175 /// The output function for n_plot points in each coordinate direction
176 //=======================================================================
177 template <unsigned NNODE_1D>
178 void QElement<1,NNODE_1D>::output(std::ostream &outfile,
179  const unsigned &n_plot)
180 {
181  //Local variables
182  Vector<double> s(1);
183 
184  //Tecplot header info
185  outfile << "ZONE I=" << n_plot << std::endl;
186 
187  //Find the dimension of the nodes
188  unsigned n_dim = this->nodal_dimension();
189 
190  //Loop over plot points
191  for(unsigned l=0;l<n_plot;l++)
192  {
193  s[0] = -1.0 + l*2.0/(n_plot-1);
194  //Output the coordinates
195  for (unsigned i=0;i<n_dim;i++)
196  {
197  outfile << interpolated_x(s,i) << " " ;
198  }
199  outfile << std::endl;
200  }
201  outfile << std::endl;
202 }
203 
204 
205 
206 //=======================================================================
207 /// C style output function for general 1D QElements
208 //=======================================================================
209 template <unsigned NNODE_1D>
210 void QElement<1,NNODE_1D>::output(FILE* file_pt)
211 {
212  output(file_pt, NNODE_1D);
213 }
214 
215 //=======================================================================
216 /// C style output function for n_plot points in each coordinate direction
217 //=======================================================================
218 template <unsigned NNODE_1D>
219 void QElement<1,NNODE_1D>::output(FILE* file_pt, const unsigned &n_plot)
220 {
221  //Local variables
222  Vector<double> s(1);
223 
224  //Tecplot header info
225  //outfile << "ZONE I=" << n_plot << std::endl;
226  fprintf(file_pt,"ZONE I=%i\n",n_plot);
227 
228  //Find the dimension of the first node
229  unsigned n_dim = this->nodal_dimension();
230 
231  //Loop over plot points
232  for(unsigned l=0;l<n_plot;l++)
233  {
234  s[0] = -1.0 + l*2.0/(n_plot-1);
235 
236  //Output the coordinates
237  for (unsigned i=0;i<n_dim;i++)
238  {
239  //outfile << interpolated_x(s,i) << " " ;
240  fprintf(file_pt,"%g ",interpolated_x(s,i));
241  }
242  //outfile << std::endl;
243  fprintf(file_pt,"\n");
244  }
245  //outfile << std::endl;
246  fprintf(file_pt,"\n");
247 }
248 
249 
250 ////////////////////////////////////////////////////////////////
251 // 2D Qelements
252 ////////////////////////////////////////////////////////////////
253 
254 /// Assign the spatial integration scheme
255 template<unsigned NNODE_1D>
257 
258 
259 //==================================================================
260 /// Return the node at the specified local coordinate
261 //==================================================================
262 template<unsigned NNODE_1D>
265 {
266  //Load the tolerance into a local variable
268  //There are two possible indices.
269  Vector<int> index(2);
270  //Loop over the coordinates and determine the indices
271  for(unsigned i=0;i<2;i++)
272  {
273  //If we are at the lower limit, the index is zero
274  if(std::fabs(s[i] + 1.0) < tol)
275  {
276  index[i] = 0;
277  }
278  //If we are at the upper limit, the index is the number of nodes minus 1
279  else if(std::fabs(s[i] - 1.0) < tol)
280  {
281  index[i] = NNODE_1D-1;
282  }
283  //Otherwise, we have to calculate the index in general
284  else
285  {
286  //For uniformly spaced nodes the node number would be
287  double float_index = 0.5*(1.0 + s[i])*(NNODE_1D-1);
288  //Convert to an integer by taking the floor (rounding down)
289  index[i] = static_cast<int>(std::floor(float_index));
290  //What is the excess. This should be safe because the
291  //we have rounded down
292  double excess = float_index - index[i];
293  //If the excess is bigger than our tolerance there is no node,
294  //return null
295  //Note that we test at both lower and upper ends.
296  if((excess > tol) && ((1.0 - excess) > tol))
297  {
298  return 0;
299  }
300  //If we are at the upper end (i.e. the system has actually rounded up)
301  //we need to add one to the index
302  if((1.0 - excess) <= tol) {index[i] += 1;}
303  }
304  }
305  //If we've got here we have a node, so let's return a pointer to it
306  return node_pt(index[0] + NNODE_1D*index[1]);
307 }
308 
309 
310 
311 //=======================================================================
312 /// Shape function for specific QElement<2,..>
313 ///
314 //=======================================================================
315 template <unsigned NNODE_1D>
317  const
318 {
319  //Local storage
320  double Psi[2][NNODE_1D];
321  //Call the OneDimensional Shape functions
322  OneDimLagrange::shape<NNODE_1D>(s[0],Psi[0]);
323  OneDimLagrange::shape<NNODE_1D>(s[1],Psi[1]);
324  //Index for the shape functions
325  unsigned index=0;
326 
327  //Now let's loop over the nodal points in the element
328  //s1 is the "x" coordinate, s2 the "y"
329  for(unsigned i=0;i<NNODE_1D;i++)
330  {
331  for(unsigned j=0;j<NNODE_1D;j++)
332  {
333  //Multiply the two 1D functions together to get the 2D function
334  psi[index] = Psi[1][i]*Psi[0][j];
335  //Incremenet the index
336  ++index;
337  }
338  }
339 }
340 
341 //=======================================================================
342 ///Derivatives of shape functions for specific QElement<2,..>
343 //=======================================================================
344 template <unsigned NNODE_1D>
346  DShape &dpsids) const
347 {
348  //Local storage
349  double Psi[2][NNODE_1D];
350  double DPsi[2][NNODE_1D];
351  unsigned index=0;
352 
353  //Call the shape functions and derivatives
354  OneDimLagrange::shape<NNODE_1D>(s[0],Psi[0]);
355  OneDimLagrange::shape<NNODE_1D>(s[1],Psi[1]);
356  OneDimLagrange::dshape<NNODE_1D>(s[0],DPsi[0]);
357  OneDimLagrange::dshape<NNODE_1D>(s[1],DPsi[1]);
358 
359  //Loop over shape functions in element
360  for(unsigned i=0;i<NNODE_1D;i++)
361  {
362  for(unsigned j=0;j<NNODE_1D;j++)
363  {
364  //Assign the values
365  dpsids(index,0) = Psi[1][i]*DPsi[0][j];
366  dpsids(index,1) = DPsi[1][i]* Psi[0][j];
367  psi[index] = Psi[1][i]* Psi[0][j];
368  //Increment the index
369  ++index;
370  }
371  }
372 }
373 
374 
375 //=======================================================================
376 /// Second derivatives of shape functions for specific QElement<2,..>:
377 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
378 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
379 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
380 //=======================================================================
381 template <unsigned NNODE_1D>
383  DShape &dpsids, DShape &d2psids) const
384 {
385  //Local storage
386  double Psi[2][NNODE_1D];
387  double DPsi[2][NNODE_1D];
388  double D2Psi[2][NNODE_1D];
389  //Index for the assembly process
390  unsigned index=0;
391 
392  //Call the shape functions and derivatives
393  OneDimLagrange::shape<NNODE_1D>(s[0],Psi[0]);
394  OneDimLagrange::shape<NNODE_1D>(s[1],Psi[1]);
395  OneDimLagrange::dshape<NNODE_1D>(s[0],DPsi[0]);
396  OneDimLagrange::dshape<NNODE_1D>(s[1],DPsi[1]);
397  OneDimLagrange::d2shape<NNODE_1D>(s[0],D2Psi[0]);
398  OneDimLagrange::d2shape<NNODE_1D>(s[1],D2Psi[1]);
399 
400  //Loop over shape functions in element
401  for(unsigned i=0;i<NNODE_1D;i++)
402  {
403  for(unsigned j=0;j<NNODE_1D;j++)
404  {
405  //Assign the values
406  psi[index] = Psi[1][i]*Psi[0][j];
407  //First derivatives
408  dpsids(index,0) = Psi[1][i]*DPsi[0][j];
409  dpsids(index,1) = DPsi[1][i]* Psi[0][j];
410  //Second derivatives
411  //N.B. index 2 is the mixed derivative
412  d2psids(index,0) = Psi[1][i]*D2Psi[0][j];
413  d2psids(index,1) = D2Psi[1][i]* Psi[0][j];
414  d2psids(index,2) = DPsi[1][i]* DPsi[0][j];
415  //Increment the index
416  ++index;
417  }
418  }
419 }
420 
421 
422 
423 
424 //===========================================================
425 /// The output function for QElement<2,NNODE_1D>
426 //===========================================================
427 template <unsigned NNODE_1D>
428 void QElement<2,NNODE_1D>::output(std::ostream &outfile)
429 {
430  output(outfile, NNODE_1D);
431 }
432 
433 //=======================================================================
434 /// The output function for n_plot points in each coordinate direction
435 //=======================================================================
436 template <unsigned NNODE_1D>
437 void QElement<2,NNODE_1D>::output(std::ostream &outfile,
438  const unsigned &n_plot)
439 {
440  //Local variables
441  Vector<double> s(2);
442 
443  //Tecplot header info
444  outfile << "ZONE I=" << n_plot << ", J=" << n_plot << std::endl;
445 
446  //Find the dimension of the nodes
447  unsigned n_dim = this->nodal_dimension();
448 
449  //Loop over plot points
450  for(unsigned l2=0;l2<n_plot;l2++)
451  {
452  s[1] = -1.0 + l2*2.0/(n_plot-1);
453  for(unsigned l1=0;l1<n_plot;l1++)
454  {
455  s[0] = -1.0 + l1*2.0/(n_plot-1);
456 
457  //Output the coordinates
458  for (unsigned i=0;i<n_dim;i++)
459  {
460  outfile << interpolated_x(s,i) << " " ;
461  }
462  outfile << std::endl;
463  }
464  }
465  outfile << std::endl;
466 }
467 
468 
469 
470 
471 //===========================================================
472 /// C-style output function for QElement<2,NNODE_1D>
473 //===========================================================
474 template <unsigned NNODE_1D>
475 void QElement<2,NNODE_1D>::output(FILE* file_pt)
476 {
477  output(file_pt, NNODE_1D);
478 }
479 
480 //=======================================================================
481 /// C-style output function for n_plot points in each coordinate direction
482 //=======================================================================
483 template <unsigned NNODE_1D>
484 void QElement<2,NNODE_1D>::output(FILE* file_pt, const unsigned &n_plot)
485 {
486  //Local variables
487  Vector<double> s(2);
488 
489  //Find the dimension of the nodes
490  unsigned n_dim = this->nodal_dimension();
491 
492  //Tecplot header info
493  //outfile << "ZONE I=" << n_plot << ", J=" << n_plot << std::endl;
494  fprintf(file_pt,"ZONE I=%i, J=%i\n",n_plot,n_plot);
495 
496  //Loop over element nodes
497  for(unsigned l2=0;l2<n_plot;l2++)
498  {
499  s[1] = -1.0 + l2*2.0/(n_plot-1);
500  for(unsigned l1=0;l1<n_plot;l1++)
501  {
502  s[0] = -1.0 + l1*2.0/(n_plot-1);
503 
504  //Output the coordinates
505  for (unsigned i=0;i<n_dim;i++)
506  {
507  //outfile << interpolated_x(s,i) << " " ;
508  fprintf(file_pt,"%g ",interpolated_x(s,i));
509 
510  }
511  //outfile << std::endl;
512  fprintf(file_pt,"\n");
513  }
514  }
515  //outfile << std::endl;
516  fprintf(file_pt,"\n");
517 }
518 
519 
520 
521 ////////////////////////////////////////////////////////////////
522 // 3D Qelements
523 ////////////////////////////////////////////////////////////////
524 
525 /// Assign the spatial integration scheme
526 template<unsigned NNODE_1D>
528 
529 //==================================================================
530 /// Return the node at the specified local coordinate
531 //==================================================================
532 template<unsigned NNODE_1D>
535 {
536  //Load the tolerance into a local variable
538  //There are now three possible indices
539  Vector<int> index(3);
540  //Loop over the coordinates
541  for(unsigned i=0;i<3;i++)
542  {
543  //If we are at the lower limit, the index is zero
544  if(std::fabs(s[i] + 1.0) < tol)
545  {
546  index[i] = 0;
547  }
548  //If we are at the upper limit, the index is the number of nodes minus 1
549  else if(std::fabs(s[i] - 1.0) < tol)
550  {
551  index[i] = NNODE_1D-1;
552  }
553  //Otherwise, we have to calculate the index in general
554  else
555  {
556  //For uniformly spaced nodes the node number would be
557  double float_index = 0.5*(1.0 + s[i])*(NNODE_1D-1);
558  //Conver to an integer by taking the floor (rounding down)
559  index[i] = static_cast<int>(std::floor(float_index));
560  //What is the excess. This should be safe because
561  //we have rounded down
562  double excess = float_index - index[i];
563  //If the excess is bigger than our tolerance there is no node,
564  //return null. Note that we test at both ends
565  if((excess > tol) && ((1.0 - excess) > tol))
566  {
567  return 0;
568  }
569  //If we are at the upper end (i.e. the system has actually rounded up)
570  //we need to add one to the index
571  if((1.0 - excess) <= tol) {index[i] += 1;}
572  }
573  }
574  //If we've got here we have a node, so let's return a pointer to it
575  return node_pt(index[0] + NNODE_1D*index[1] + NNODE_1D*NNODE_1D*index[2]);
576 }
577 
578 
579 
580 //=======================================================================
581 /// Shape function for specific QElement<3,..>
582 //=======================================================================
583 template <unsigned NNODE_1D>
585  const
586 {
587  //Local storage
588  double Psi[3][NNODE_1D];
589 
590  //Call the OneDimensional Shape functions
591  OneDimLagrange::shape<NNODE_1D>(s[0],Psi[0]);
592  OneDimLagrange::shape<NNODE_1D>(s[1],Psi[1]);
593  OneDimLagrange::shape<NNODE_1D>(s[2],Psi[2]);
594 
595  //Index for the shape functions
596  unsigned index=0;
597 
598  //Now let's loop over the nodal points in the element
599  //s1 is the "x" coordinate, s2 the "y"
600  for(unsigned i=0;i<NNODE_1D;i++)
601  {
602  for(unsigned j=0;j<NNODE_1D;j++)
603  {
604  for(unsigned k=0;k<NNODE_1D;k++)
605  {
606  /*Multiply the three 1D functions together to get the 3D function*/
607  psi[index] = Psi[2][i]*Psi[1][j]*Psi[0][k];
608  //Increment the index
609  ++index;
610  }
611  }
612  }
613 }
614 
615 //=======================================================================
616 /// Derivatives of shape functions for specific QElement<3,..>
617 //=======================================================================
618 template <unsigned NNODE_1D>
620  DShape &dpsids) const
621 {
622  //Local storage
623  double Psi[3][NNODE_1D];
624  double DPsi[3][NNODE_1D];
625  //Index of the total shape function
626  unsigned index=0;
627 
628  //Call the OneDimensional Shape functions and derivatives
629  OneDimLagrange::shape<NNODE_1D>(s[0],Psi[0]);
630  OneDimLagrange::shape<NNODE_1D>(s[1],Psi[1]);
631  OneDimLagrange::shape<NNODE_1D>(s[2],Psi[2]);
632  OneDimLagrange::dshape<NNODE_1D>(s[0],DPsi[0]);
633  OneDimLagrange::dshape<NNODE_1D>(s[1],DPsi[1]);
634  OneDimLagrange::dshape<NNODE_1D>(s[2],DPsi[2]);
635 
636 
637  //Loop over shape functions in element
638  for(unsigned i=0;i<NNODE_1D;i++)
639  {
640  for(unsigned j=0;j<NNODE_1D;j++)
641  {
642  for(unsigned k=0;k<NNODE_1D;k++)
643  {
644  //Assign the values
645  dpsids(index,0) = Psi[2][i] * Psi[1][j] * DPsi[0][k];
646  dpsids(index,1) = Psi[2][i] * DPsi[1][j] * Psi[0][k];
647  dpsids(index,2) = DPsi[2][i] * Psi[1][j] * Psi[0][k];
648 
649  psi[index] = Psi[2][i]*Psi[1][j]*Psi[0][k];
650  //Increment the index
651  ++index;
652  }
653  }
654  }
655 }
656 
657 //=======================================================================
658 /// Second derivatives of shape functions for specific QElement<3,..>:
659 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
660 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
661 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_2^2 \f$
662 /// d2psids(i,3) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
663 /// d2psids(i,4) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_2 \f$
664 /// d2psids(i,5) = \f$ \partial^2 \psi_j / \partial s_1 \partial s_2 \f$
665 //=======================================================================
666 template <unsigned NNODE_1D>
668  DShape &dpsids, DShape &d2psids) const
669 {
670  //Local storage
671  double Psi[3][NNODE_1D];
672  double DPsi[3][NNODE_1D];
673  double D2Psi[3][NNODE_1D];
674  //Index of the shape function
675  unsigned index=0;
676 
677  //Call the OneDimensional Shape functions and derivatives
678  OneDimLagrange::shape<NNODE_1D>(s[0],Psi[0]);
679  OneDimLagrange::shape<NNODE_1D>(s[1],Psi[1]);
680  OneDimLagrange::shape<NNODE_1D>(s[2],Psi[2]);
681  OneDimLagrange::dshape<NNODE_1D>(s[0],DPsi[0]);
682  OneDimLagrange::dshape<NNODE_1D>(s[1],DPsi[1]);
683  OneDimLagrange::dshape<NNODE_1D>(s[2],DPsi[2]);
684  OneDimLagrange::d2shape<NNODE_1D>(s[0],D2Psi[0]);
685  OneDimLagrange::d2shape<NNODE_1D>(s[1],D2Psi[1]);
686  OneDimLagrange::d2shape<NNODE_1D>(s[2],D2Psi[2]);
687 
688  //Loop over shape functions in element
689  for(unsigned i=0;i<NNODE_1D;i++)
690  {
691  for(unsigned j=0;j<NNODE_1D;j++)
692  {
693  for(unsigned k=0;k<NNODE_1D;k++)
694  {
695  //Assign the values
696  psi[index] = Psi[2][i]*Psi[1][j]*Psi[0][k];
697 
698  dpsids(index,0) = Psi[2][i]*Psi[1][j]*DPsi[0][k];
699  dpsids(index,1) = Psi[2][i]*DPsi[1][j]*Psi[0][k];
700  dpsids(index,2) = DPsi[2][i]* Psi[1][j]*Psi[0][k];
701 
702  //Second derivative values
703  d2psids(index,0) = Psi[2][i]*Psi[1][j]*D2Psi[0][k];
704  d2psids(index,1) = Psi[2][i]*D2Psi[1][j]*Psi[0][k];
705  d2psids(index,2) = D2Psi[2][i]* Psi[1][j]*Psi[0][k];
706  //Convention for higher indices
707  //3: mixed 12, 4: mixed 13, 5: mixed 23
708  d2psids(index,3) = Psi[2][i]*DPsi[1][j]*DPsi[0][k];
709  d2psids(index,4) = DPsi[2][i]*Psi[1][j]*DPsi[0][k];
710  d2psids(index,5) = DPsi[2][i]*DPsi[1][j]*Psi[0][k];
711  //Increment the index
712  ++index;
713  }
714  }
715  }
716 }
717 
718 //===========================================================
719 /// The output function for QElement<3,NNODE_1D>
720 //===========================================================
721 template <unsigned NNODE_1D>
722 void QElement<3,NNODE_1D>::output(std::ostream &outfile)
723 {
724  output(outfile, NNODE_1D);
725 }
726 
727 //=======================================================================
728 /// The output function for n_plot points in each coordinate direction
729 //=======================================================================
730 template <unsigned NNODE_1D>
731 void QElement<3,NNODE_1D>::output(std::ostream &outfile,
732  const unsigned &n_plot)
733 {
734  //Local variables
735  Vector<double> s(3);
736 
737  //Tecplot header info
738  outfile << "ZONE I=" << n_plot << ", J=" << n_plot
739  << ", K=" << n_plot << std::endl;
740 
741  //Find the dimension of the nodes
742  unsigned n_dim = this->nodal_dimension();
743 
744  //Loop over element nodes
745  for(unsigned l3=0;l3<n_plot;l3++)
746  {
747  s[2] = -1.0 + l3*2.0/(n_plot-1);
748  for(unsigned l2=0;l2<n_plot;l2++)
749  {
750  s[1] = -1.0 + l2*2.0/(n_plot-1);
751  for(unsigned l1=0;l1<n_plot;l1++)
752  {
753  s[0] = -1.0 + l1*2.0/(n_plot-1);
754 
755  //Output the coordinates
756  for (unsigned i=0;i<n_dim;i++)
757  {
758  outfile << interpolated_x(s,i) << " " ;
759  }
760  outfile << std::endl;
761  }
762  }
763  }
764  outfile << std::endl;
765 }
766 
767 
768 
769 
770 //===========================================================
771 /// C-style output function for QElement<3,NNODE_1D>
772 //===========================================================
773 template <unsigned NNODE_1D>
774 void QElement<3,NNODE_1D>::output(FILE* file_pt)
775 {
776  output(file_pt, NNODE_1D);
777 }
778 
779 //=======================================================================
780 /// C-style output function for n_plot points in each coordinate direction
781 //=======================================================================
782 template <unsigned NNODE_1D>
783 void QElement<3,NNODE_1D>::output(FILE* file_pt, const unsigned &n_plot)
784 {
785  //Local variables
786  Vector<double> s(3);
787 
788  //Tecplot header info
789  fprintf(file_pt,"ZONE I=%i, J=%i, K=%i\n",n_plot,n_plot,n_plot);
790 
791  //Find the dimension of the nodes
792  unsigned n_dim = this->nodal_dimension();
793 
794  //Loop over element nodes
795  for(unsigned l3=0;l3<n_plot;l3++)
796  {
797  s[2] = -1.0 + l3*2.0/(n_plot-1);
798  for(unsigned l2=0;l2<n_plot;l2++)
799  {
800  s[1] = -1.0 + l2*2.0/(n_plot-1);
801  for(unsigned l1=0;l1<n_plot;l1++)
802  {
803  s[0] = -1.0 + l1*2.0/(n_plot-1);
804 
805  //Output the coordinates
806  for (unsigned i=0;i<n_dim;i++)
807  {
808  fprintf(file_pt,"%g ",interpolated_x(s,i));
809  }
810  fprintf(file_pt,"\n");
811  }
812  }
813  }
814  fprintf(file_pt,"\n");
815 }
816 
817 
818 
819 //===================================================================
820 // Build required templates
821 //===================================================================
822 template class QElement<1,2>;
823 template class QElement<1,3>;
824 template class QElement<1,4>;
825 
826 template class QElement<2,2>;
827 template class QElement<2,3>;
828 template class QElement<2,4>;
829 
830 template class QElement<3,2>;
831 template class QElement<3,3>;
832 template class QElement<3,4>;
833 
834 }
cstr elem_len * i
Definition: cfortran.h:607
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:852
static char t char * s
Definition: cfortran.h:572
static const double Node_location_tolerance
Default value for the tolerance to be used when locating nodes via local coordinates.
Definition: elements.h:1337
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 output(std::ostream &outfile)
Output with default number of plot points.
static Gauss< 1, NNODE_1D > Default_integration_scheme
Default integration rule: Gaussian integration of same &#39;order&#39; as the element.
Definition: Qelements.h:519
Node * get_node_at_local_coordinate(const Vector< double > &s) const
Get the node at the specified local coordinate.
Definition: Qelements.cc:54