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) 2014 Kilian Lackhove
10 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
11 // Department of Aeronautics, Imperial College London (UK), and Scientific
12 // Computing and Imaging Institute, University of Utah (USA).
13 //
14 // License for the specific language governing rights and limitations under
15 // Permission is hereby granted, free of charge, to any person obtaining a
16 // copy of this software and associated documentation files (the "Software"),
17 // to deal in the Software without restriction, including without limitation
18 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 // and/or sell copies of the Software, and to permit persons to whom the
20 // Software is furnished to do so, subject to the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be included
23 // in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 // DEALINGS IN THE SOFTWARE.
32 //
33 // Description: Acoustic perturbation equations in conservative variables
34 //
35 ///////////////////////////////////////////////////////////////////////////////
36 
37 #include <iostream>
38 
41 
42 namespace Nektar
43 {
45  "APE", APE::create,
46  "Acoustic perturbation equations in conservative variables.");
47 
48 
51  : UnsteadySystem(pSession)
52 {
53 }
54 
55 
56 /**
57  * @brief Initialization object for the APE class.
58  */
60 {
62 
63  // TODO: We have a bug somewhere in the 1D boundary conditions. Therefore 1D
64  // problems are currently disabled. This should get fixed in the future.
65  ASSERTL0(m_spacedim > 1, "1D problems currently not supported by the APE class.");
66 
68  "Only Projection=DisContinuous supported by the APE class.");
69 
70  // Load constant incompressible density
71  m_session->LoadParameter("Rho0", m_Rho0, 1.204);
72 
73  // Load isentropic coefficient, Ratio of specific heats
74  m_session->LoadParameter("Gamma", m_gamma, 1.4);
75 
76  // Define Baseflow fields
77  m_basefield = Array<OneD, Array<OneD, NekDouble> >(m_spacedim + 1);
78  m_basefield_names.push_back("P0");
79  m_basefield_names.push_back("U0");
80  m_basefield_names.push_back("V0");
81  m_basefield_names.push_back("W0");
82 
83  // Resize the advection velocities vector to dimension of the problem
84  m_basefield_names.resize(m_spacedim + 1);
85 
86 
87  // Do not forwards transform initial condition
88  m_homoInitialFwd = false;
89 
90  // Define the normal velocity fields
91  if (m_fields[0]->GetTrace())
92  {
93  m_traceBasefield = Array<OneD, Array<OneD, NekDouble> > (m_spacedim + 1);
94  for (int i = 0; i < m_spacedim + 1; i++)
95  {
96  m_traceBasefield[i] = Array<OneD, NekDouble>(GetTraceNpoints());
97  }
98  }
99 
100  // Set up locations of velocity and base velocity vectors.
101  m_vecLocs = Array<OneD, Array<OneD, NekDouble> >(1);
102  m_vecLocs[0] = Array<OneD, NekDouble>(m_spacedim);
103  for (int i = 0; i < m_spacedim; ++i)
104  {
105  // u', v', w'
106  m_vecLocs[0][i] = 1 + i;
107  }
108 
109  string riemName;
110  m_session->LoadSolverInfo("UpwindType", riemName, "APEUpwind");
112  riemName);
113  m_riemannSolver->SetVector("N", &APE::GetNormals, this);
114  m_riemannSolver->SetVector("basefield", &APE::GetBasefield, this);
115  m_riemannSolver->SetAuxVec("vecLocs", &APE::GetVecLocs, this);
116  m_riemannSolver->SetParam("Gamma", &APE::GetGamma, this);
117  m_riemannSolver->SetParam("Rho", &APE::GetRho, this);
118 
119  // Set up advection operator
120  string advName;
121  m_session->LoadSolverInfo("AdvectionType", advName, "WeakDG");
123  .CreateInstance(advName, advName);
124  m_advection->SetFluxVector(&APE::GetFluxVector, this);
125  m_advection->SetRiemannSolver(m_riemannSolver);
126  m_advection->InitObject(m_session, m_fields);
127 
129  {
132  }
133  else
134  {
135  ASSERTL0(false, "Implicit APE not set up.");
136  }
137 }
138 
139 
140 /**
141  * @brief Destructor for APE class.
142  */
144 {
145 
146 }
147 
148 
149 /**
150  *
151  */
153 {
155 }
156 
157 
158 /**
159  * @brief Return the flux vector for the APE equations.
160  *
161  * @param physfield Fields.
162  * @param flux Resulting flux. flux[eq][dir][pt]
163  */
165  const Array<OneD, Array<OneD, NekDouble> > &physfield,
166  Array<OneD, Array<OneD, Array<OneD, NekDouble> > > &flux)
167 {
168  UpdateBasefield();
169 
170  for (int i = 0; i < flux.num_elements(); ++i)
171  {
172  ASSERTL1(flux[i].num_elements() == m_spacedim,
173  "Dimension of flux array and velocity array do not match");
174 
175  int nq = physfield[0].num_elements();
176  NekDouble tmp0 = 0.0;
177  Array<OneD, NekDouble> tmp1(nq);
178  Array<OneD, NekDouble> tmp2(nq);
179 
180  if (i == 0)
181  {
182  // F_{adv,p',j} = \gamma p_0 u'_j + p' \bar{u}_j
183  for (int j = 0; j < m_spacedim; ++j)
184  {
185  Vmath::Zero(nq, flux[i][j], 1);
186 
187  // construct \gamma p_0 u'_j term
188  Vmath::Smul(nq, m_gamma, m_basefield[0], 1, tmp1, 1);
189  Vmath::Vmul(nq, tmp1, 1, physfield[j+1], 1, tmp1, 1);
190 
191  // construct p' \bar{u}_j term
192  Vmath::Vmul(nq, physfield[0], 1, m_basefield[j+1], 1, tmp2, 1);
193 
194  // add both terms
195  Vmath::Vadd(nq, tmp1, 1, tmp2, 1, flux[i][j], 1);
196  }
197  }
198  else
199  {
200  // F_{adv,u'_i,j} = (p'/ rho + \bar{u}_k u'_k) \delta_{ij}
201  for (int j = 0; j < m_spacedim; ++j)
202  {
203  Vmath::Zero(nq, flux[i][j], 1);
204 
205  if (i-1 == j)
206  {
207  // contruct p'/ rho term
208  tmp0 = 1 / m_Rho0;
209  Vmath::Smul(nq, tmp0, physfield[0], 1, flux[i][j], 1);
210 
211  // construct \bar{u}_k u'_k term
212  Vmath::Zero(nq, tmp1, 1);
213  for (int k = 0; k < m_spacedim; ++k)
214  {
215  Vmath::Vmul(nq, physfield[k+1], 1, m_basefield[k+1], 1, tmp2, 1);
216  Vmath::Vadd(nq, tmp1, 1, tmp2, 1, tmp1, 1);
217  }
218 
219  // add terms
220  Vmath::Vadd(nq, flux[i][j], 1, tmp1, 1, flux[i][j], 1);
221  }
222  }
223  }
224  }
225 }
226 
227 
228 /**
229  * @brief Compute the right-hand side.
230  */
231 void APE::DoOdeRhs(const Array<OneD, const Array<OneD, NekDouble> >&inarray,
232  Array<OneD, Array<OneD, NekDouble> >&outarray,
233  const NekDouble time)
234 {
235  int nVariables = inarray.num_elements();
236  int nq = GetTotPoints();
237 
238  // WeakDG does not use advVel, so we only provide a dummy array
239  Array<OneD, Array<OneD, NekDouble> > advVel(m_spacedim);
240  m_advection->Advect(nVariables, m_fields, advVel, inarray, outarray, time);
241 
242  for (int i = 0; i < nVariables; ++i)
243  {
244  Vmath::Neg(nq, outarray[i], 1);
245  }
246 
247  AddSource(outarray);
248 }
249 
250 
251 /**
252  * @brief Compute the projection and call the method for imposing the
253  * boundary conditions in case of discontinuous projection.
254  */
255 void APE::DoOdeProjection(const Array<OneD, const Array<OneD, NekDouble> >&inarray,
256  Array<OneD, Array<OneD, NekDouble> >&outarray,
257  const NekDouble time)
258 {
259  int nvariables = inarray.num_elements();
260  int nq = m_fields[0]->GetNpoints();
261 
262  // deep copy
263  for (int i = 0; i < nvariables; ++i)
264  {
265  Vmath::Vcopy(nq, inarray[i], 1, outarray[i], 1);
266  }
267 
268  SetBoundaryConditions(outarray, time);
269 }
270 
271 
272 /**
273  * @brief Apply the Boundary Conditions to the APE equations.
274  */
275 void APE::SetBoundaryConditions(Array<OneD, Array<OneD, NekDouble> > &inarray,
276  NekDouble time)
277 {
278  std::string varName;
279  int nvariables = m_fields.num_elements();
280  int cnt = 0;
281 
282  // loop over Boundary Regions
283  for(int n = 0; n < m_fields[0]->GetBndConditions().num_elements(); ++n)
284  {
285  // Wall Boundary Condition
286  if (m_fields[0]->GetBndConditions()[n]->GetUserDefined() == SpatialDomains::eWall)
287  {
288  WallBC(n, cnt, inarray);
289  }
290 
291  // Time Dependent Boundary Condition (specified in meshfile)
292  if (m_fields[0]->GetBndConditions()[n]->GetUserDefined() == SpatialDomains::eTimeDependent)
293  {
294  for (int i = 0; i < nvariables; ++i)
295  {
296  varName = m_session->GetVariable(i);
297  m_fields[i]->EvaluateBoundaryConditions(time, varName);
298  }
299  }
300  cnt +=m_fields[0]->GetBndCondExpansions()[n]->GetExpSize();
301  }
302 }
303 
304 
305 /**
306  * @brief Wall boundary conditions for the APE equations.
307  */
308 void APE::WallBC(int bcRegion, int cnt,
309  Array<OneD, Array<OneD, NekDouble> > &physarray)
310 {
311  int nTracePts = GetTraceTotPoints();
312  int nVariables = physarray.num_elements();
313 
314  const Array<OneD, const int> &traceBndMap = m_fields[0]->GetTraceBndMap();
315 
316  // Get physical values of the forward trace
317  Array<OneD, Array<OneD, NekDouble> > Fwd(nVariables);
318  for (int i = 0; i < nVariables; ++i)
319  {
320  Fwd[i] = Array<OneD, NekDouble>(nTracePts);
321  m_fields[i]->ExtractTracePhys(physarray[i], Fwd[i]);
322  }
323 
324  // Adjust the physical values of the trace to take
325  // user defined boundaries into account
326  int id1, id2, nBCEdgePts;
327  int eMax = m_fields[0]->GetBndCondExpansions()[bcRegion]->GetExpSize();
328 
329  for (int e = 0; e < eMax; ++e)
330  {
331  nBCEdgePts = m_fields[0]->GetBndCondExpansions()[bcRegion]->
332  GetExp(e)->GetTotPoints();
333  id1 = m_fields[0]->GetBndCondExpansions()[bcRegion]->GetPhys_Offset(e);
334  id2 = m_fields[0]->GetTrace()->GetPhys_Offset(traceBndMap[cnt+e]);
335 
336  // For 2D/3D, define: v* = v - 2(v.n)n
337  Array<OneD, NekDouble> tmp(nBCEdgePts, 0.0);
338 
339  // Calculate (v.n)
340  for (int i = 0; i < m_spacedim; ++i)
341  {
342  Vmath::Vvtvp(nBCEdgePts,
343  &Fwd[1+i][id2], 1,
344  &m_traceNormals[i][id2], 1,
345  &tmp[0], 1,
346  &tmp[0], 1);
347  }
348 
349  // Calculate 2.0(v.n)
350  Vmath::Smul(nBCEdgePts, -2.0, &tmp[0], 1, &tmp[0], 1);
351 
352  // Calculate v* = v - 2.0(v.n)n
353  for (int i = 0; i < m_spacedim; ++i)
354  {
355  Vmath::Vvtvp(nBCEdgePts,
356  &tmp[0], 1,
357  &m_traceNormals[i][id2], 1,
358  &Fwd[1+i][id2], 1,
359  &Fwd[1+i][id2], 1);
360  }
361 
362  // Copy boundary adjusted values into the boundary expansion
363  for (int i = 0; i < nVariables; ++i)
364  {
365  Vmath::Vcopy(nBCEdgePts,
366  &Fwd[i][id2], 1,
367  &(m_fields[i]->GetBndCondExpansions()[bcRegion]->UpdatePhys())[id1], 1);
368  }
369  }
370 }
371 
372 
373 /**
374  * @brief sourceterm for p' equation obtained from GetSource
375  */
376 void APE::AddSource(Array< OneD, Array< OneD, NekDouble > > &outarray)
377 {
378  int nCoeffs = m_fields[0]->GetNcoeffs();
379  int nTotPoints = GetTotPoints();
380 
381  Array<OneD, NekDouble> sourceP(nTotPoints);
382  Array<OneD, NekDouble> sourceC(nCoeffs);
383 
384  EvaluateFunction("S", sourceP, "Source", m_time);
385 
386  m_fields[0]->IProductWRTBase(sourceP, sourceC);
387  m_fields[0]->MultiplyByElmtInvMass(sourceC, sourceC);
388  m_fields[0]->BwdTrans(sourceC, sourceP);
389 
390  Vmath::Vadd(nTotPoints, sourceP, 1, outarray[0], 1, outarray[0], 1);
391 }
392 
393 
395  std::vector<Array<OneD, NekDouble> > &fieldcoeffs,
396  std::vector<std::string> &variables)
397 {
398  UpdateBasefield();
399 
400  const int nCoeffs = m_fields[0]->GetNcoeffs();
401 
402  for (int i = 0; i < m_spacedim + 1; i++)
403  {
404  variables.push_back(m_basefield_names[i]);
405 
406  Array<OneD, NekDouble> tmpFwd(nCoeffs);
407  m_fields[0]->FwdTrans(m_basefield[i], tmpFwd);
408  fieldcoeffs.push_back(tmpFwd);
409  }
410 }
411 
412 
413 /**
414  * @brief Get the normal vectors.
415  */
416 const Array<OneD, const Array<OneD, NekDouble> > &APE::GetNormals()
417 {
418  return m_traceNormals;
419 }
420 
421 
422 /**
423  * @brief Get the locations of the components of the directed fields within the fields array.
424  */
425 const Array<OneD, const Array<OneD, NekDouble> > &APE::GetVecLocs()
426 {
427  return m_vecLocs;
428 }
429 
430 
431 /**
432  * @brief Get the baseflow field.
433  */
434 const Array<OneD, const Array<OneD, NekDouble> > &APE::GetBasefield()
435 {
436  for (int i = 0; i < m_spacedim +1; i++)
437  {
438  m_fields[0]->ExtractTracePhys(m_basefield[i], m_traceBasefield[i]);
439  }
440  return m_traceBasefield;
441 }
442 
443 
444 /**
445  * @brief Get the heat capacity ratio.
446  */
448 {
449  return m_gamma;
450 }
451 
452 
453 /**
454  * @brief Get the density.
455  */
457 {
458  return m_Rho0;
459 }
460 
462 {
463  static NekDouble last_update = -1.0;
464 
465  if (m_time > last_update)
466  {
468 
469  // some sanity chacks for the basefield
470  ASSERTL0(Vmath::Vmin(m_basefield[0].num_elements(), m_basefield[0], 1) >= 0.0, "Basefield contains negative pressures");
471 
472  last_update = m_time;
473  }
474 }
475 
476 
477 } //end of namespace
478