Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
APE.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File APE.cpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: Acoustic perturbation equations in conservative variables
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
36 #include <iostream>
37 
40 
41 namespace Nektar
42 {
44  "APE", APE::create,
45  "Acoustic perturbation equations in conservative variables.");
46 
47 
50  : UnsteadySystem(pSession)
51 {
52 }
53 
54 
55 /**
56  * @brief Initialization object for the APE class.
57  */
59 {
61 
62  // TODO: We have a bug somewhere in the 1D boundary conditions. Therefore 1D
63  // problems are currently disabled. This should get fixed in the future.
64  ASSERTL0(m_spacedim > 1, "1D problems currently not supported by the APE class.");
65 
66  // Load constant incompressible density
67  m_session->LoadParameter("Rho0", m_Rho0, 1.204);
68 
69  // Load isentropic coefficient, Ratio of specific heats
70  m_session->LoadParameter("Gamma", m_gamma, 1.4);
71 
72  // Define Baseflow fields
73  m_basefield = Array<OneD, Array<OneD, NekDouble> >(m_spacedim + 1);
74  m_basefield_names.push_back("P0");
75  m_basefield_names.push_back("U0");
76  m_basefield_names.push_back("V0");
77  m_basefield_names.push_back("W0");
78 
79  // Resize the advection velocities vector to dimension of the problem
80  m_basefield_names.resize(m_spacedim + 1);
81 
82  // if discontinuous determine numerical flux to use
84  {
85  // Do not forwards transform initial condition
86  m_homoInitialFwd = false;
87 
88  // Define the normal velocity fields
89  if (m_fields[0]->GetTrace())
90  {
91  m_traceBasefield = Array<OneD, Array<OneD, NekDouble> > (m_spacedim+1);
92  for (int i = 0; i < m_spacedim + 1; i++)
93  {
94  m_traceBasefield[i] = Array<OneD, NekDouble>(GetTraceNpoints());
95  }
96  }
97 
98  // Set up locations of velocity and base velocity vectors.
99  m_vecLocs = Array<OneD, Array<OneD, NekDouble> >(1);
100  m_vecLocs[0] = Array<OneD, NekDouble>(m_spacedim);
101  for (int i = 0; i < m_spacedim; ++i)
102  {
103  // u', v', w'
104  m_vecLocs[0][i] = 1 + i;
105  }
106 
107  string riemName;
108  m_session->LoadSolverInfo("UpwindType", riemName, "APEUpwind");
109  riemName = "APEUpwind";
111  m_riemannSolver->SetVector("N", &APE::GetNormals, this);
112  m_riemannSolver->SetVector("basefield", &APE::GetBasefield, this);
113  m_riemannSolver->SetAuxVec("vecLocs", &APE::GetVecLocs, this);
114  m_riemannSolver->SetParam ("Gamma", &APE::GetGamma, this);
115  m_riemannSolver->SetParam ("Rho", &APE::GetRho, this);
116  }
117 
119  {
122  }
123  else
124  {
125  ASSERTL0(false, "Implicit APE not set up.");
126  }
127 }
128 
129 
130 /**
131  * @brief Destructor for APE class.
132  */
134 {
135 
136 }
137 
138 
139 /**
140  *
141  */
143 {
145 }
146 
147 
148 /**
149  * @brief Compute the numerical flux through the element boundaries.
150  *
151  */
153  Array<OneD, Array<OneD, NekDouble> > &physfield,
154  Array<OneD, Array<OneD, NekDouble> > &numflux)
155 {
156  //Number the points of the shared edges of the elements
157  int ntp = GetTraceTotPoints();
158  int nvar = physfield.num_elements();
159 
160  // temporary arrays
161  Array<OneD, Array<OneD, NekDouble> > Fwd(nvar);
162  Array<OneD, Array<OneD, NekDouble> > Bwd(nvar);
163 
164  for (int i = 0; i < nvar; ++i)
165  {
166  Fwd[i] = Array<OneD, NekDouble>(ntp);
167  Bwd[i] = Array<OneD, NekDouble>(ntp);
168  }
169 
170  // get the physical values at the trace
171  for (int i = 0; i < nvar; ++i)
172  {
173  m_fields[i]->GetFwdBwdTracePhys(physfield[i],Fwd[i],Bwd[i]);
174  }
175 
176  // Solve the Riemann problem
177  m_riemannSolver->Solve(m_spacedim, Fwd, Bwd, numflux);
178 
179 }
180 
181 
182 /**
183  *
184  */
186  Array<OneD, Array<OneD, NekDouble> > &physfield,
187  Array<OneD, Array<OneD, NekDouble> > &numfluxX,
188  Array<OneD, Array<OneD, NekDouble> > &numfluxY )
189 {
190  ASSERTL0(false, "This function is not implemented for this equation.");
191 }
192 
193 
194 /**
195  * @brief Compute the flux vectors.
196  */
197 void APE::v_GetFluxVector(const int i, const int j,
198  Array<OneD, Array<OneD, NekDouble> > &physfield,
199  Array<OneD, Array<OneD, NekDouble> > &flux)
200 {
201  v_GetFluxVector(i, physfield, flux);
202 }
203 
204 
205 /**
206  * @brief Compute the flux vectors.
207  */
208 void APE::v_GetFluxVector(const int i,
209  Array<OneD, Array<OneD, NekDouble> > &physfield,
210  Array<OneD, Array<OneD, NekDouble> > &flux)
211 {
213 
214  ASSERTL1(flux.num_elements() == m_basefield.num_elements() - 1,
215  "Dimension of flux array and velocity array do not match");
216 
217  int nq = physfield[0].num_elements();
218  NekDouble tmp0 = 0.0;
219  Array<OneD, NekDouble> tmp1(nq);
220  Array<OneD, NekDouble> tmp2(nq);
221 
222  if (i == 0)
223  {
224  // F_{adv,p',j} = \gamma p_0 u'_j + p' \bar{u}_j
225  for (int j = 0; j < flux.num_elements(); ++j)
226  {
227  Vmath::Zero(nq, flux[j], 1);
228 
229  // construct \gamma p_0 u'_j term
230  Vmath::Smul(nq, m_gamma, m_basefield[0], 1, tmp1, 1);
231  Vmath::Vmul(nq, tmp1, 1, physfield[j+1], 1, tmp1, 1);
232 
233  // construct p' \bar{u}_j term
234  Vmath::Vmul(nq, physfield[0], 1, m_basefield[j+1], 1, tmp2, 1);
235 
236  // add both terms
237  Vmath::Vadd(nq, tmp1, 1, tmp2, 1, flux[j], 1);
238  }
239  }
240  else
241  {
242  // F_{adv,u'_i,j} = (p'/ rho + \bar{u}_k u'_k) \delta_{ij}
243  for (int j = 0; j < flux.num_elements(); ++j)
244  {
245  Vmath::Zero(nq, flux[j], 1);
246 
247  if (i-1 == j)
248  {
249  // contruct p'/ rho term
250  tmp0 = 1 / m_Rho0;
251  Vmath::Smul(nq, tmp0, physfield[0], 1, flux[j], 1);
252 
253  // construct \bar{u}_k u'_k term
254  Vmath::Zero(nq, tmp1, 1);
255  for (int k = 0; k < flux.num_elements(); ++k)
256  {
257  Vmath::Vmul(nq, physfield[k+1], 1, m_basefield[k+1], 1, tmp2, 1);
258  Vmath::Vadd(nq, tmp1, 1, tmp2, 1, tmp1, 1);
259  }
260 
261  // add terms
262  Vmath::Vadd(nq, flux[j], 1, tmp1, 1, flux[j], 1);
263  }
264  }
265  }
266 
267 }
268 
269 
270 /**
271  * @brief Compute the right-hand side.
272  */
273 void APE::DoOdeRhs(const Array<OneD, const Array<OneD, NekDouble> >&inarray,
274  Array<OneD, Array<OneD, NekDouble> >&outarray,
275  const NekDouble time)
276 {
277  int i;
278  int ndim = m_spacedim;
279  int nvariables = inarray.num_elements();
280  int ncoeffs = GetNcoeffs();
281  int nq = GetTotPoints();
282 
283  switch(m_projectionType)
284  {
286  {
287  //-------------------------------------------------------
288  //inarray in physical space
289 
290  Array<OneD, Array<OneD, NekDouble> > modarray(nvariables);
291 
292  for (i = 0; i < nvariables; ++i)
293  {
294  modarray[i] = Array<OneD, NekDouble>(ncoeffs);
295  }
296 
297  // get the advection part
298  // input: physical space
299  // output: modal space
300 
301  // straighforward DG
302  WeakDGAdvection(inarray, modarray, true, true);
303 
304  // negate the outarray since moving terms to the rhs
305  for(i = 0; i < nvariables; ++i)
306  {
307  Vmath::Neg(ncoeffs,modarray[i],1);
308  }
309 
310  // Add "source term"
311  // input: physical space
312  // output: modal space (JOSEF)
313  AddSource(inarray, modarray);
314 
315  for(i = 0; i < nvariables; ++i)
316  {
317  m_fields[i]->MultiplyByElmtInvMass(modarray[i],modarray[i]);
318  m_fields[i]->BwdTrans(modarray[i],outarray[i]);
319  }
320  break;
321  }
322 
325  {
326  Array<OneD, Array<OneD, NekDouble> > physarray(nvariables);
327  Array<OneD, Array<OneD, NekDouble> > modarray(nvariables);
328 
329  for (i = 0; i < nvariables; ++i)
330  {
331  physarray[i] = Array<OneD, NekDouble>(nq);
332  modarray[i] = Array<OneD, NekDouble>(ncoeffs);
333  }
334 
335  // deep copy
336  for(i = 0; i < nvariables; ++i)
337  {
338  Vmath::Vcopy(nq,inarray[i],1,physarray[i],1);
339  }
340 
341  Array<OneD, Array<OneD, NekDouble> > fluxvector(ndim);
342  for(i = 0; i < ndim; ++i)
343  {
344  fluxvector[i] = Array<OneD, NekDouble>(nq);
345  }
346 
347  Array<OneD,NekDouble> tmp(nq);
348  Array<OneD, NekDouble>tmp1(nq);
349 
350  for(i = 0; i < nvariables; ++i)
351  {
352  // Get the ith component of the flux vector in (physical space)
353  APE::GetFluxVector(i, physarray, fluxvector);
354 
355  Vmath::Zero(nq, outarray[i], 1);
356  for (int j = 0; j < ndim; ++j)
357  {
358  // Get the ith component of the flux vector in (physical space)
359  m_fields[0]->PhysDeriv(j,fluxvector[j],tmp1);
360  Vmath::Vadd(nq, outarray[i], 1, tmp1, 1, outarray[i], 1);
361  }
362  Vmath::Neg(nq,outarray[i],1);
363  }
364 
365  // Add "source term"
366  // input: physical space
367  // output: modal space
368  AddSource(physarray,outarray);
369  break;
370  }
371 
372  default:
373  ASSERTL0(false,"Unknown projection scheme for the APE");
374  break;
375  }
376 }
377 
378 
379 /**
380  * @brief Compute the projection and call the method for imposing the
381  * boundary conditions in case of discontinuous projection.
382  */
383 void APE::DoOdeProjection(const Array<OneD, const Array<OneD, NekDouble> >&inarray,
384  Array<OneD, Array<OneD, NekDouble> >&outarray,
385  const NekDouble time)
386 {
387  int i;
388  int nvariables = inarray.num_elements();
389  int nq = m_fields[0]->GetNpoints();
390 
391  // deep copy
392  for(int i = 0; i < nvariables; ++i)
393  {
394  Vmath::Vcopy(nq,inarray[i],1,outarray[i],1);
395  }
396 
397  switch(m_projectionType)
398  {
400  {
401  SetBoundaryConditions(outarray,time);
402  break;
403  }
404 
407  {
409  Array<OneD, NekDouble> coeffs(m_fields[0]->GetNcoeffs());
410 
411  for(i = 0; i < nvariables; ++i)
412  {
413  m_fields[i]->FwdTrans(outarray[i],coeffs);
414  m_fields[i]->BwdTrans_IterPerExp(coeffs,outarray[i]);
415  }
416  break;
417  }
418 
419  default:
420  ASSERTL0(false,"Unknown projection scheme");
421  break;
422  }
423 }
424 
425 
426 /**
427  * @brief Apply the Boundary Conditions to the APE equations.
428  */
429 void APE::SetBoundaryConditions(Array<OneD, Array<OneD, NekDouble> > &inarray,
430  NekDouble time)
431 {
432  std::string varName;
433  int nvariables = m_fields.num_elements();
434  int cnt = 0;
435 
436  // loop over Boundary Regions
437  for(int n = 0; n < m_fields[0]->GetBndConditions().num_elements(); ++n)
438  {
439  // Wall Boundary Condition
440  if (m_fields[0]->GetBndConditions()[n]->GetUserDefined() == SpatialDomains::eWall)
441  {
442  WallBC(n, cnt, inarray);
443  }
444 
445  // Time Dependent Boundary Condition (specified in meshfile)
446  if (m_fields[0]->GetBndConditions()[n]->GetUserDefined() == SpatialDomains::eTimeDependent)
447  {
448  for (int i = 0; i < nvariables; ++i)
449  {
450  varName = m_session->GetVariable(i);
451  m_fields[i]->EvaluateBoundaryConditions(time, varName);
452  }
453  }
454  cnt +=m_fields[0]->GetBndCondExpansions()[n]->GetExpSize();
455  }
456 }
457 
458 
459 /**
460  * @brief Wall boundary conditions for the APE equations.
461  */
462 void APE::WallBC(int bcRegion, int cnt,
463  Array<OneD, Array<OneD, NekDouble> > &physarray)
464 {
465  int nTracePts = GetTraceTotPoints();
466  int nVariables = physarray.num_elements();
467 
468  const Array<OneD, const int> &traceBndMap = m_fields[0]->GetTraceBndMap();
469 
470  // Get physical values of the forward trace
471  Array<OneD, Array<OneD, NekDouble> > Fwd(nVariables);
472  for (int i = 0; i < nVariables; ++i)
473  {
474  Fwd[i] = Array<OneD, NekDouble>(nTracePts);
475  m_fields[i]->ExtractTracePhys(physarray[i], Fwd[i]);
476  }
477 
478  // Adjust the physical values of the trace to take
479  // user defined boundaries into account
480  int id1, id2, nBCEdgePts;
481  int eMax = m_fields[0]->GetBndCondExpansions()[bcRegion]->GetExpSize();
482 
483  for (int e = 0; e < eMax; ++e)
484  {
485  nBCEdgePts = m_fields[0]->GetBndCondExpansions()[bcRegion]->
486  GetExp(e)->GetTotPoints();
487  id1 = m_fields[0]->GetBndCondExpansions()[bcRegion]->GetPhys_Offset(e);
488  id2 = m_fields[0]->GetTrace()->GetPhys_Offset(traceBndMap[cnt+e]);
489 
490  // For 2D/3D, define: v* = v - 2(v.n)n
491  Array<OneD, NekDouble> tmp(nBCEdgePts, 0.0);
492 
493  // Calculate (v.n)
494  for (int i = 0; i < m_spacedim; ++i)
495  {
496  Vmath::Vvtvp(nBCEdgePts,
497  &Fwd[1+i][id2], 1,
498  &m_traceNormals[i][id2], 1,
499  &tmp[0], 1,
500  &tmp[0], 1);
501  }
502 
503  // Calculate 2.0(v.n)
504  Vmath::Smul(nBCEdgePts, -2.0, &tmp[0], 1, &tmp[0], 1);
505 
506  // Calculate v* = v - 2.0(v.n)n
507  for (int i = 0; i < m_spacedim; ++i)
508  {
509  Vmath::Vvtvp(nBCEdgePts,
510  &tmp[0], 1,
511  &m_traceNormals[i][id2], 1,
512  &Fwd[1+i][id2], 1,
513  &Fwd[1+i][id2], 1);
514  }
515 
516  // Copy boundary adjusted values into the boundary expansion
517  for (int i = 0; i < nVariables; ++i)
518  {
519  Vmath::Vcopy(nBCEdgePts,
520  &Fwd[i][id2], 1,
521  &(m_fields[i]->GetBndCondExpansions()[bcRegion]->UpdatePhys())[id1], 1);
522  }
523  }
524 }
525 
526 
527 /**
528  * @brief sourceterm for p' equation obtained from GetSource
529  */
530 void APE::AddSource(const Array< OneD, Array< OneD, NekDouble > > &inarray,
531  Array< OneD, Array< OneD, NekDouble > > &outarray)
532 {
533  int ncoeffs = outarray[0].num_elements();
534  int nq = inarray[0].num_elements();
535  Array<OneD, NekDouble> source(nq);
536 
537  EvaluateFunction("S", source, "Source", m_time);
539  {
540  m_fields[0]->IProductWRTBase(source,source);
541  }
542  Vmath::Vadd(ncoeffs,source,1,outarray[0],1,outarray[0],1);
543 
544 }
545 
546 
547 /**
548  * @brief Get the normal vectors.
549  */
550 const Array<OneD, const Array<OneD, NekDouble> > &APE::GetNormals()
551 {
552  return m_traceNormals;
553 }
554 
555 
556 /**
557  * @brief Get the locations of the components of the directed fields within the fields array.
558  */
559 const Array<OneD, const Array<OneD, NekDouble> > &APE::GetVecLocs()
560 {
561  return m_vecLocs;
562 }
563 
564 
565 /**
566  * @brief Get the baseflow field.
567  */
568 const Array<OneD, const Array<OneD, NekDouble> > &APE::GetBasefield()
569 {
570  for (int i = 0; i < m_spacedim +1; i++)
571  {
572  m_fields[0]->ExtractTracePhys(m_basefield[i], m_traceBasefield[i]);
573  }
574  return m_traceBasefield;
575 }
576 
577 
578 /**
579  * @brief Get the heat capacity ratio.
580  */
582 {
583  return m_gamma;
584 }
585 
586 
587 /**
588  * @brief Get the density.
589  */
591 {
592  return m_Rho0;
593 }
594 
595 } //end of namespace
596