MAST
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
frequency_domain_linearized_conservative_fluid_elem.cpp
Go to the documentation of this file.
1 /*
2  * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3  * Copyright (C) 2013-2020 Manav Bhatia and MAST authors
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 
21 // MAST includes
25 #include "fluid/flight_condition.h"
30 #include "base/nonlinear_system.h"
31 #include "mesh/fe_base.h"
32 #include "mesh/geom_elem.h"
33 #include "base/assembly_base.h"
34 
35 
36 
39  const MAST::GeomElem& elem,
40  const MAST::FlightCondition& f):
41 MAST::ConservativeFluidElementBase(sys, elem, f),
42 freq(nullptr) {
43 
44 
45 }
46 
47 
48 
49 
50 
53 
54 
55 }
56 
57 
58 
59 
60 bool
62 internal_residual (bool request_jacobian,
63  ComplexVectorX& f,
64  ComplexMatrixX& jac) {
65 
66  // first get the internal residual and Jacobian from the
67  // conservative elems, and then add to it an extra dissipation
68  // to control solution discontinuities emanating from the boundary.
69 
70  //const std::vector<Real>& JxW = _fe->get_JxW();
71  //const std::vector<std::vector<Real> >& phi = _fe->get_phi();
72  const unsigned int
73  n2 = f.size();
74  //nphi = _fe->n_shape_functions();
75 
77  f_jac_x = RealMatrixX::Zero( n2, n2),
78  fm_jac_xdot = RealMatrixX::Zero( n2, n2);
79  /*mat1_n1n1 = RealMatrixX::Zero( n1, n1),
80  mat2_n1n1 = RealMatrixX::Zero( n1, n1),
81  mat3_n1n2 = RealMatrixX::Zero( n1, n2),
82  mat4_n2n2 = RealMatrixX::Zero( n2, n2),
83  AiBi_adv = RealMatrixX::Zero( n1, n2),
84  A_sens = RealMatrixX::Zero( n1, n2),
85  LS = RealMatrixX::Zero( n1, n2),
86  LS_sens = RealMatrixX::Zero( n2, n2);*/
87 
88 
90  local_jac = ComplexMatrixX::Zero( n2, n2);
91 
92 
94  //vec1_n1 = RealVectorX::Zero(n1),
95  //vec2_n1 = RealVectorX::Zero(n1),
96  local_f = RealVectorX::Zero(n2);
97  //dc = RealVectorX::Zero(dim);
98 
99  const Complex
100  iota(0., 1.);
101 
102  Real
103  omega = 0.,
104  b_V = 0.;
105 
106  (*freq)(omega);
108 
109  // df/dx. We always need the Jacobian, since it is used to calculate
110  // the residual
112  local_f,
113  f_jac_x);
114 
115  // dfm/dxdot. We always need the Jacobian, since it is used to calculate
116  // the residual
118  local_f,
119  fm_jac_xdot,
120  f_jac_x);
121 
122  // now, combine the two to return the complex Jacobian
123 
124  local_jac = (f_jac_x.cast<Complex>() * b_V + // multiply stiffness with nondim factor
125  iota * omega * fm_jac_xdot.cast<Complex>());
126 
127  if (request_jacobian)
128  jac += local_jac;
129 
130  f += local_jac * _complex_sol;
131 
132  return request_jacobian;
133 }
134 
135 
136 
137 
138 
139 bool
142  bool request_jacobian,
143  ComplexVectorX& f,
144  ComplexMatrixX& jac) {
145 
146  // first get the internal residual and Jacobian from the
147  // conservative elems, and then add to it an extra dissipation
148  // to control solution discontinuities emanating from the boundary.
149 
150  //const std::vector<Real>& JxW = _fe->get_JxW();
151  //const std::vector<std::vector<Real> >& phi = _fe->get_phi();
152  const unsigned int
153  n2 = f.size();
154  //nphi = _fe->n_shape_functions();
155 
157  f_jac_x = RealMatrixX::Zero( n2, n2),
158  fm_jac_xdot = RealMatrixX::Zero( n2, n2);
159  /*mat1_n1n1 = RealMatrixX::Zero( n1, n1),
160  mat2_n1n1 = RealMatrixX::Zero( n1, n1),
161  mat3_n1n2 = RealMatrixX::Zero( n1, n2),
162  mat4_n2n2 = RealMatrixX::Zero( n2, n2),
163  AiBi_adv = RealMatrixX::Zero( n1, n2),
164  A_sens = RealMatrixX::Zero( n1, n2),
165  LS = RealMatrixX::Zero( n1, n2),
166  LS_sens = RealMatrixX::Zero( n2, n2);*/
167 
168 
170  local_jac = ComplexMatrixX::Zero( n2, n2),
171  local_jac_sens = ComplexMatrixX::Zero( n2, n2);
172 
173 
175  //vec1_n1 = RealVectorX::Zero(n1),
176  //vec2_n1 = RealVectorX::Zero(n1),
177  local_f = RealVectorX::Zero(n2);
178  //dc = RealVectorX::Zero(dim);
179 
180  const Complex
181  iota(0., 1.);
182 
183  Real
184  omega = 0.,
185  domega = 0.,
186  b_V = 0.;
187 
188  (*freq)(omega);
189  freq->derivative(p, domega);
191 
192 
193  // df/dx. We always need the Jacobian, since it is used to calculate
194  // the residual
196  local_f,
197  f_jac_x);
198 
199  // dfm/dxdot. We always need the Jacobian, since it is used to calculate
200  // the residual
202  local_f,
203  fm_jac_xdot,
204  f_jac_x);
205 
206  // now, combine the two to return the complex Jacobian
207 
208  local_jac = (f_jac_x.cast<Complex>() * b_V + // multiply stiffness with nondim factor
209  iota * omega * fm_jac_xdot.cast<Complex>());
210 
211  local_jac_sens = (iota * domega * fm_jac_xdot.cast<Complex>());
212 
213 
214  if (request_jacobian)
215  jac += local_jac_sens;
216 
217  f += local_jac_sens * _complex_sol + local_jac * _complex_sol_sens;
218 
219  return request_jacobian;
220 }
221 
222 
223 
224 
225 bool
227 side_external_residual (bool request_jacobian,
228  ComplexVectorX& f,
229  ComplexMatrixX& jac,
230  std::multimap<libMesh::boundary_id_type, MAST::BoundaryConditionBase*>& bc) {
231 
232  // the far-field and symmetry wall, which are assumed to be stationary will
233  // only contribute to the real part of the complex Jacobian. Hence,
234  // we will use the parent class's methods for these two. The
235  // slip wall, which may be oscillating, is implemented for this element.
236 
237  const unsigned int
238  dim = _elem.dim(),
239  n1 = dim+2,
240  n2 = f.size();
241 
243  f_jac_x = RealMatrixX::Zero(n2, n2);
244 
246  local_f = RealVectorX::Zero(n2);
247 
248  Real
249  b_V = 0.;
251 
252 
253  std::map<unsigned int, std::vector<MAST::BoundaryConditionBase*>> loads;
255 
256  std::map<unsigned int, std::vector<MAST::BoundaryConditionBase*>>::const_iterator
257  it = loads.begin(),
258  end = loads.end();
259 
260  for ( ; it != end; it++) {
261 
262  std::vector<MAST::BoundaryConditionBase*>::const_iterator
263  bc_it = it->second.begin(),
264  bc_end = it->second.end();
265 
266  for ( ; bc_it != bc_end; bc_it++) {
267 
268  // apply all the types of loading
269  switch ((*bc_it)->type()) {
270  case MAST::SYMMETRY_WALL: {
271 
272  f_jac_x.setZero();
273  local_f.setZero();
274 
275  // We always need the Jacobian, since it is used to
276  // calculate the residual
277 
280  local_f,
281  f_jac_x,
282  it->first,
283  **bc_it);
284 
285  // multiply jacobian with the nondimensionalizing
286  // factor (V/b for flutter analysis)
287  if (request_jacobian)
288  jac += f_jac_x.cast<Complex>() * b_V;
289  f += f_jac_x.cast<Complex>() * b_V * _complex_sol;
290  }
291  break;
292 
293  case MAST::SLIP_WALL: {
294 
295  // this calculates the Jacobian and residual contribution
296  // including the nondimensionalizing factor.
297  this->slip_wall_surface_residual(request_jacobian,
298  f,
299  jac,
300  it->first,
301  **bc_it);
302  }
303  break;
304 
305  case MAST::FAR_FIELD: {
306 
307  f_jac_x.setZero();
308  local_f.setZero();
309 
310  // We always need the Jacobian, since it is used to
311  // calculate the residual
312 
315  local_f,
316  f_jac_x,
317  it->first,
318  **bc_it);
319 
320  // multiply jacobian with the nondimensionalizing
321  // factor (V/b for flutter analysis)
322  if (request_jacobian)
323  jac += f_jac_x.cast<Complex>() * b_V;
324 
325  f += f_jac_x.cast<Complex>() * b_V * _complex_sol;
326  }
327  break;
328 
329  case MAST::DIRICHLET:
330  // nothing to be done here
331  break;
332 
333  default:
334  // not implemented yet
335  libmesh_error();
336  break;
337  }
338  }
339  }
340 
341 
342  return request_jacobian;
343 }
344 
345 
346 
347 
348 
349 
350 bool
353  bool request_jacobian,
354  ComplexVectorX& f,
355  ComplexMatrixX& jac,
356  std::multimap<libMesh::boundary_id_type, MAST::BoundaryConditionBase*>& bc) {
357 
358  // the far-field and symmetry wall, which are assumed to be stationary will
359  // only contribute to the real part of the complex Jacobian. Hence,
360  // we will use the parent class's methods for these two. The
361  // slip wall, which may be oscillating, is implemented for this element.
362 
363  const unsigned int
364  dim = _elem.dim(),
365  n1 = dim+2,
366  n2 = f.size();
367 
369  f_jac_x = RealMatrixX::Zero(n2, n2);
370 
372  local_f = RealVectorX::Zero(n2);
373 
374  Real
375  b_V = 0.;
377 
378  std::map<unsigned int, std::vector<MAST::BoundaryConditionBase*>> loads;
380 
381  std::map<unsigned int, std::vector<MAST::BoundaryConditionBase*>>::const_iterator
382  it = loads.begin(),
383  end = loads.end();
384 
385  for ( ; it != end; it++) {
386 
387  std::vector<MAST::BoundaryConditionBase*>::const_iterator
388  bc_it = it->second.begin(),
389  bc_end = it->second.end();
390 
391  for ( ; bc_it != bc_end; bc_it++) {
392 
393  // apply all the types of loading
394  switch ((*bc_it)->type()) {
395  case MAST::SYMMETRY_WALL: {
396 
397  f_jac_x.setZero();
398  local_f.setZero();
399 
400  // We always need the Jacobian, since it is used to
401  // calculate the residual
402 
405  local_f,
406  f_jac_x,
407  it->first,
408  **bc_it);
409 
410  // multiply jacobian with the nondimensionalizing
411  // factor (V/b for flutter analysis)
412  //if (request_jacobian)
413  // jac += f_jac_x.cast<Complex>() * b_V;
414  f += f_jac_x.cast<Complex>() * b_V * _complex_sol_sens;
415  }
416  break;
417 
418  case MAST::SLIP_WALL: {
419 
420  // this calculates the Jacobian and residual contribution
421  // including the nondimensionalizing factor.
422  this->slip_wall_surface_residual_sensitivity(p, request_jacobian,
423  f,
424  jac,
425  it->first,
426  **bc_it);
427  }
428  break;
429 
430  case MAST::FAR_FIELD: {
431 
432  f_jac_x.setZero();
433  local_f.setZero();
434 
435  // We always need the Jacobian, since it is used to
436  // calculate the residual
437 
440  local_f,
441  f_jac_x,
442  it->first,
443  **bc_it);
444 
445  // multiply jacobian with the nondimensionalizing
446  // factor (V/b for flutter analysis)
447  //if (request_jacobian)
448  // jac += f_jac_x.cast<Complex>() * b_V;
449 
450  f += f_jac_x.cast<Complex>() * b_V * _complex_sol_sens;
451  }
452  break;
453 
454  case MAST::DIRICHLET:
455  // nothing to be done here
456  break;
457 
458  default:
459  // not implemented yet
460  libmesh_error();
461  break;
462  }
463  }
464  }
465 
466  return request_jacobian;
467 }
468 
469 
470 
471 
472 
473 
474 bool
476 slip_wall_surface_residual(bool request_jacobian,
477  ComplexVectorX& f,
478  ComplexMatrixX& jac,
479  const unsigned int s,
481 
482  // inviscid boundary condition without any diffusive component
483  // conditions enforced are
484  // vi ni = wi_dot (ni + dni) - ui dni (moving slip wall with deformation)
485  // tau_ij nj = 0 (because velocity gradient at wall = 0)
486  // qi ni = 0 (since heat flux occurs only on no-slip wall and far-field bc)
487 
488  // prepare the side finite element
489  std::unique_ptr<MAST::FEBase> fe(_elem.init_side_fe(s, false, false));
490 
491  const std::vector<Real> &JxW = fe->get_JxW();
492  const std::vector<libMesh::Point>& normals = fe->get_normals_for_reference_coordinate();
493  const std::vector<libMesh::Point>& qpoint = fe->get_xyz();
494 
495  const unsigned int
496  dim = _elem.dim(),
497  n1 = dim+2,
498  n2 = fe->n_shape_functions()*n1;
499 
501  vec1_n1 = RealVectorX::Zero(n1),
502  uvec = RealVectorX::Zero(3),
503  dwdot_i = RealVectorX::Zero(3),
504  ni = RealVectorX::Zero(3),
505  dni = RealVectorX::Zero(3),
506  tmp = RealVectorX::Zero(6);
507 
509  Dw_i = ComplexVectorX::Zero(3),
510  Dni = ComplexVectorX::Zero(3),
511  Duvec = ComplexVectorX::Zero(3),
512  vec2_n1 = ComplexVectorX::Zero(n1),
513  vec2_n2 = ComplexVectorX::Zero(n2),
514  flux = ComplexVectorX::Zero(n1),
515  tmp_c = ComplexVectorX::Zero(6);
516 
518  mat1_n1n1 = RealMatrixX::Zero( n1, n1),
519  mat2_n1n2 = RealMatrixX::Zero( n1, n2),
520  mat3_n2n2 = RealMatrixX::Zero( n2, n2);
521 
522  libMesh::Point pt;
524 
525  // create objects to calculate the primitive solution, flux, and Jacobian
526  MAST::PrimitiveSolution primitive_sol;
528 
529  Complex
530  iota (0., 1.),
531  Dvi_ni_freq_indep = 0.,
532  Dvi_ni_freq_dep = 0.;
533 
534  Real
535  omega = 0.,
536  b_V = 0.,
537  ui_ni_steady = 0.;
538 
539 
540  // get the surface motion object from the boundary condition object
542  *vel = nullptr;
544  *n_rot = nullptr;
545 
547  *displ_perturb = nullptr;
549  *n_rot_perturb = nullptr;
550 
551  if (bc.contains("velocity"))
552  vel = &bc.get<MAST::FieldFunction<RealVectorX> >("velocity");
553 
554  if (bc.contains("normal_rotation")) {
555 
557  tmp = bc.get<MAST::FieldFunction<RealVectorX> >("normal_rotation");
558  n_rot = dynamic_cast<MAST::NormalRotationFunctionBase<RealVectorX>*>(&tmp);
559  }
560 
561  if (bc.contains("frequency_domain_displacement")) {
562 
563  displ_perturb = &bc.get<MAST::FieldFunction<ComplexVectorX> >("frequency_domain_displacement");
564  // if displ is provided then n_rot must also be provided
565  libmesh_assert(bc.contains("frequency_domain_normal_rotation"));
566 
568  tmp = bc.get<MAST::FieldFunction<ComplexVectorX> >("frequency_domain_normal_rotation");
569  n_rot_perturb = dynamic_cast<MAST::NormalRotationFunctionBase<ComplexVectorX>*>(&tmp);
570  }
571 
572 
573 
574 
575  (*freq)(omega);
577 
578 
579  for (unsigned int qp=0; qp<JxW.size(); qp++) {
580 
581  // initialize the Bmat operator for this term
582  _initialize_fem_interpolation_operator(qp, dim, *fe, Bmat);
583  Bmat.right_multiply(vec1_n1, _sol); // conservative sol
584  Bmat.right_multiply(vec2_n1, _complex_sol); // perturbation sol
585 
586  // initialize the primitive solution
587  primitive_sol.zero();
588  primitive_sol.init(dim,
589  vec1_n1,
592  if_viscous());
593 
594  // initialize the small-disturbance primitive sol
595  sd_primitive_sol.zero();
596  sd_primitive_sol.init(primitive_sol, vec2_n1, if_viscous());
597 
599  // Calculation of the surface velocity term. For a
600  // steady-state system,
601  // vi (ni + dni) = wdot_i (ni + dni)
602  // or vi ni = wdot_i (ni + dni) - vi dni
603  //
604  // The first order perturbation, D(.), of this is
605  // (vi + Dvi) (ni + dni + Dni) =
606  // (wdot_i + Dwdot_i) (ni + dni + Dni)
607  // or Dvi ni = Dwdot_i (ni + dni + Dni) +
608  // wdot_i (ni + dni + Dni) -
609  // vi (ni + dni + Dni) -
610  // Dvi (dni + Dni)
611  // Neglecting HOT, this becomes
612  // Dvi ni = Dwdot_i (ni + dni) +
613  // wdot_i (ni + dni + Dni) -
614  // vi (ni + dni + Dni) -
615  // Dvi dni
616  // = Dwdot_i (ni + dni) +
617  // wdot_i Dni - vi Dni - Dvi dni
618  //
620 
621  // copy the surface normal
622  for (unsigned int i_dim=0; i_dim<dim; i_dim++)
623  ni(i_dim) = normals[qp](i_dim);
624 
625  // now check if the surface deformation is defined and
626  // needs to be applied through transpiration boundary
627  // condition
628  primitive_sol.get_uvec(uvec);
629  sd_primitive_sol.get_duvec(Duvec);
630 
631  flux.setZero();
632 
634  // contribution from the base-flow boundary condition
636  if (vel) {
637 
638  (*vel)(qpoint[qp], _time, tmp);
639  dwdot_i = tmp.topRows(3);
640  }
641 
642  if (n_rot)
643  (*n_rot)(qpoint[qp], normals[qp], _time, dni);
644 
645  ui_ni_steady = dwdot_i.dot(ni+dni) - uvec.dot(dni);
646 
647  flux += ui_ni_steady * b_V * vec2_n1; // vi_ni dcons_flux
648  flux(n1-1) += ui_ni_steady * b_V * sd_primitive_sol.dp; // vi_ni {0,0,0,0,Dp}
649 
650  if (displ_perturb) {
651 
653  // contribution from the small-disturbance boundary condition
655  (*displ_perturb)(qpoint[qp], _time, tmp_c);
656  Dw_i = tmp_c.topRows(3);
657  (*n_rot_perturb)(qpoint[qp], normals[qp], _time, Dni);
658  }
659 
660  Dvi_ni_freq_dep = Dw_i.dot(ni+dni) * iota * omega;
661  Dvi_ni_freq_indep = (dwdot_i.cast<Complex>().dot(Dni) -
662  uvec.cast<Complex>().dot(Dni) -
663  Duvec.dot(dni));
664 
665 
666  flux += (Dvi_ni_freq_indep * b_V +
667  Dvi_ni_freq_dep) * vec1_n1; // Dvi_ni cons_flux
668  flux(n1-1) += (Dvi_ni_freq_indep * b_V +
669  Dvi_ni_freq_dep) * primitive_sol.p; // Dvi_ni {0,0,0,0,p}
670 
671  // ni Dp (only for the momentun eq)
672  flux.segment(1, dim) += ((sd_primitive_sol.dp * b_V) *
673  ni.segment(0,dim).cast<Complex>());
674 
675  Bmat.vector_mult_transpose(vec2_n2, flux);
676  f += JxW[qp] * vec2_n2;
677 
678  if ( request_jacobian ) {
679 
680  // the Jacobian contribution comes only from the dp term in the
681  // residual
683  (primitive_sol,
684  ui_ni_steady,
685  normals[qp],
686  dni,
687  mat1_n1n1);
688 
689  Bmat.left_multiply(mat2_n1n2, mat1_n1n1);
690  Bmat.right_multiply_transpose(mat3_n2n2, mat2_n1n2);
691  jac += (JxW[qp] * b_V) * mat3_n2n2.cast<Complex>() ;
692  }
693  }
694 
695  return request_jacobian;
696 }
697 
698 
699 
700 
701 
702 
703 bool
706  bool request_jacobian,
707  ComplexVectorX& f,
708  ComplexMatrixX& jac,
709  const unsigned int s,
711 
712  // inviscid boundary condition without any diffusive component
713  // conditions enforced are
714  // vi ni = wi_dot (ni + dni) - ui dni (moving slip wall with deformation)
715  // tau_ij nj = 0 (because velocity gradient at wall = 0)
716  // qi ni = 0 (since heat flux occurs only on no-slip wall and far-field bc)
717 
718  // prepare the side finite element
719  std::unique_ptr<MAST::FEBase> fe(_elem.init_side_fe(s, false, false));
720 
721  const std::vector<Real> &JxW = fe->get_JxW();
722  const std::vector<libMesh::Point>& normals = fe->get_normals_for_reference_coordinate();
723  const std::vector<libMesh::Point>& qpoint = fe->get_xyz();
724 
725  const unsigned int
726  dim = _elem.dim(),
727  n1 = dim+2,
728  n2 = fe->n_shape_functions()*n1;
729 
731  vec1_n1 = RealVectorX::Zero(n1),
732  uvec = RealVectorX::Zero(3),
733  ni = RealVectorX::Zero(3),
734  dni = RealVectorX::Zero(3),
735  dwdot_i = RealVectorX::Zero(3),
736  tmp = RealVectorX::Zero(6);
737 
739  vec2_n1 = ComplexVectorX::Zero(n1),
740  vec2_n2 = ComplexVectorX::Zero(n2),
741  flux = ComplexVectorX::Zero(n1),
742  tmp_c = ComplexVectorX::Zero(6),
743  Dw_i = ComplexVectorX::Zero(3),
744  Dni = ComplexVectorX::Zero(3);
745 
747  mat1_n1n1 = RealMatrixX::Zero( n1, n1),
748  mat2_n1n2 = RealMatrixX::Zero( n1, n2),
749  mat3_n2n2 = RealMatrixX::Zero( n2, n2);
750 
751  libMesh::Point pt;
753 
754  // create objects to calculate the primitive solution, flux, and Jacobian
755  MAST::PrimitiveSolution primitive_sol;
757 
758  Complex
759  iota (0., 1.),
760  Dvi_ni_freq_indep = 0.,
761  Dvi_ni_freq_dep = 0.;
762 
763  Real
764  omega = 0.,
765  domega = 0.,
766  b_V = 0.;
767 
768 
769  // get the surface motion object from the boundary condition object
771  *displ = nullptr;
773  *n_rot = nullptr;
774 
776  *displ_perturb = nullptr;
778  *n_rot_perturb = nullptr;
779 
780 
781  if (bc.contains("displacement")) {
782 
783  displ = &bc.get<MAST::FieldFunction<RealVectorX> >("displacement");
784 
785  libmesh_assert( bc.contains("normal_rotation"));
786 
788  tmp = bc.get<MAST::FieldFunction<RealVectorX> >("normal_rotation");
789  n_rot = dynamic_cast<MAST::NormalRotationFunctionBase<RealVectorX>*>(&tmp);
790  }
791 
792 
793  if (bc.contains("frequency_domain_displacement")) {
794 
795  displ_perturb = &bc.get<MAST::FieldFunction<ComplexVectorX> >("frequency_domain_displacement");
796 
797  libmesh_assert( bc.contains("frequency_domain_normal_rotation"));
798 
800  tmp = bc.get<MAST::FieldFunction<ComplexVectorX> >("frequency_domain_normal_rotation");
801  n_rot_perturb = dynamic_cast<MAST::NormalRotationFunctionBase<ComplexVectorX>*>(&tmp);
802  }
803 
804 
805  (*freq)(omega);
806  freq->derivative(p, domega);
808 
809 
810  for (unsigned int qp=0; qp<JxW.size(); qp++) {
811 
812  // initialize the Bmat operator for this term
813  _initialize_fem_interpolation_operator(qp, dim, *fe, Bmat);
814  Bmat.right_multiply(vec1_n1, _sol); // conservative sol
815  Bmat.right_multiply(vec2_n1, _complex_sol); // perturbation sol
816 
817  // initialize the primitive solution
818  primitive_sol.zero();
819  primitive_sol.init(dim,
820  vec1_n1,
823  if_viscous());
824 
825  // initialize the small-disturbance primitive sol
826  sd_primitive_sol.zero();
827  sd_primitive_sol.init(primitive_sol, vec2_n1, if_viscous());
828 
830  // Calculation of the surface velocity term. For a
831  // steady-state system,
832  // vi (ni + dni) = wdot_i (ni + dni)
833  // or vi ni = wdot_i (ni + dni) - vi dni
834  //
835  // The first order perturbation, D(.), of this is
836  // (vi + Dvi) (ni + dni + Dni) =
837  // (wdot_i + Dwdot_i) (ni + dni + Dni)
838  // or Dvi ni = Dwdot_i (ni + dni + Dni) +
839  // wdot_i (ni + dni + Dni) -
840  // vi (ni + dni + Dni) -
841  // Dvi (dni + Dni)
842  // Neglecting HOT, this becomes
843  // Dvi ni = Dwdot_i (ni + dni) +
844  // wdot_i (ni + dni + Dni) -
845  // vi (ni + dni + Dni) -
846  // Dvi dni
847  //
849 
850  // copy the surface normal
851  for (unsigned int i_dim=0; i_dim<dim; i_dim++)
852  ni(i_dim) = normals[qp](i_dim);
853 
854  // now check if the surface deformation is defined and
855  // needs to be applied through transpiration boundary
856  // condition
857  primitive_sol.get_uvec(uvec);
858 
859  if (displ) {
861  // contribution from the base-flow boundary condition
863  (*displ) (qpoint[qp], _time, tmp);
864  dwdot_i = tmp.topRows(3);
865  (*n_rot)(qpoint[qp], normals[qp], _time, dni);
866  }
867 
868  if (displ_perturb) {
869 
871  // contribution from the small-disturbance boundary condition
873  (*displ_perturb)(qpoint[qp], _time, tmp_c);
874  Dw_i = tmp_c.topRows(3);
875  (*n_rot_perturb)(qpoint[qp], normals[qp], _time, Dni);
876  }
877 
878 
879  Dvi_ni_freq_dep = Dw_i.dot(ni+dni) * iota * domega;
880 
881  flux.setZero();
882  flux += Dvi_ni_freq_dep * vec1_n1; // Dvi_ni cons_flux
883  flux(n1-1) += Dvi_ni_freq_dep * primitive_sol.p; // Dvi_ni {0,0,0,0,p}
884 
885 
886  Bmat.vector_mult_transpose(vec2_n2, flux);
887  f += JxW[qp] * vec2_n2;
888 
889  if ( request_jacobian ) {
890  libmesh_assert(false); // jac sens not implemented
891 
892  }
893  }
894 
895  return request_jacobian;
896 }
897 
898 
899 
900 
This class provides the necessary functionality for spatial discretization of the conservative fluid ...
Class defines basic operations and calculation of the small disturbance primitive variables...
virtual void external_side_loads_for_quadrature_elem(std::multimap< libMesh::boundary_id_type, MAST::BoundaryConditionBase *> &bc, std::map< unsigned int, std::vector< MAST::BoundaryConditionBase *>> &loads) const
From the given list of boundary loads, this identifies the sides of the quadrature element and the lo...
Definition: geom_elem.cpp:183
virtual bool internal_residual_sensitivity(const MAST::FunctionBase &p, bool request_jacobian, ComplexVectorX &f, ComplexMatrixX &jac)
sensitivity of internal force contribution to system residual.
const MAST::GeomElem & _elem
geometric element for which the computations are performed
Definition: elem_base.h:205
void calculate_advection_flux_jacobian_for_moving_solid_wall_boundary(const MAST::PrimitiveSolution &sol, const Real ui_ni, const libMesh::Point &nvec, const RealVectorX &dnvec, RealMatrixX &mat)
Class defines the conversion and some basic operations on primitive fluid variables used in calculati...
void init(const MAST::PrimitiveSolution &sol, const typename VectorType< ValType >::return_type &delta_sol, bool if_viscous)
virtual bool internal_residual(bool request_jacobian, ComplexVectorX &f, ComplexMatrixX &jac)
internal force contribution to system residual
ComplexVectorX _complex_sol
local solution used for frequency domain analysis
Definition: elem_base.h:237
Matrix< Complex, Dynamic, 1 > ComplexVectorX
void get_uvec(RealVectorX &u) const
virtual bool side_external_residual_sensitivity(const MAST::FunctionBase &p, bool request_jacobian, ComplexVectorX &f, ComplexMatrixX &jac, std::multimap< libMesh::boundary_id_type, MAST::BoundaryConditionBase *> &bc)
sensitivity of internal force contribution to system residual.
virtual bool velocity_residual(bool request_jacobian, RealVectorX &f, RealMatrixX &jac_xdot, RealMatrixX &jac)
inertial force contribution to system residual
libMesh::Real Real
MAST::FrequencyFunction * freq
frequency function that provides the frequency for computations.
libMesh::Complex Complex
FrequencyDomainLinearizedConservativeFluidElem(MAST::SystemInitialization &sys, const MAST::GeomElem &elem, const MAST::FlightCondition &f)
const MAST::FlightCondition * flight_condition
This defines the surface motion for use with the nonlinear fluid solver.
virtual bool symmetry_surface_residual(bool request_jacobian, RealVectorX &f, RealMatrixX &jac, const unsigned int s, MAST::BoundaryConditionBase &bc)
bool if_viscous() const
void nondimensionalizing_factor(Real &v)
bool contains(const std::string &nm) const
checks if the card contains the specified property value
Matrix< Real, Dynamic, Dynamic > RealMatrixX
Matrix< Complex, Dynamic, Dynamic > ComplexMatrixX
ComplexVectorX _complex_sol_sens
local solution used for frequency domain analysis
Definition: elem_base.h:243
void right_multiply(T &r, const T &m) const
[R] = [this] * [M]
void get_duvec(typename VectorType< ValType >::return_type &du) const
void vector_mult_transpose(T &res, const T &v) const
res = v^T * [this]
Matrix< Real, Dynamic, 1 > RealVectorX
void right_multiply_transpose(T &r, const T &m) const
[R] = [this]^T * [M]
RealVectorX _sol
local solution
Definition: elem_base.h:225
virtual bool internal_residual(bool request_jacobian, RealVectorX &f, RealMatrixX &jac)
internal force contribution to system residual
void init(const unsigned int dim, const RealVectorX &conservative_sol, const Real cp_val, const Real cv_val, bool if_viscous)
This class acts as a wrapper around libMesh::Elem for the purpose of providing a uniform interface fo...
Definition: geom_elem.h:59
bool side_external_residual(bool request_jacobian, ComplexVectorX &f, ComplexMatrixX &jac, std::multimap< libMesh::boundary_id_type, MAST::BoundaryConditionBase *> &bc)
side external force contribution to system residual
unsigned int dim() const
Definition: geom_elem.cpp:91
void _initialize_fem_interpolation_operator(const unsigned int qp, const unsigned int dim, const MAST::FEBase &fe, MAST::FEMOperatorMatrix &Bmat)
GasProperty gas_property
Ambient air properties.
const ValType & get(const std::string &nm) const
returns a constant reference to the specified function
virtual std::unique_ptr< MAST::FEBase > init_side_fe(unsigned int s, bool init_grads, bool init_second_order_derivative, int extra_quadrature_order=0) const
initializes the finite element shape function and quadrature object for the side with the order of qu...
Definition: geom_elem.cpp:165
virtual bool slip_wall_surface_residual_sensitivity(const MAST::FunctionBase &p, bool request_jacobian, ComplexVectorX &f, ComplexMatrixX &jac, const unsigned int s, MAST::BoundaryConditionBase &bc)
sensitivity of residual of the slip wall that may be oscillating.
virtual bool far_field_surface_residual(bool request_jacobian, RealVectorX &f, RealMatrixX &jac, const unsigned int s, MAST::BoundaryConditionBase &bc)
virtual void derivative(const MAST::FunctionBase &f, Real &v) const
calculates the value of the function derivative and returns it in v.
void left_multiply(T &r, const T &m) const
[R] = [M] * [this]
const Real & _time
time for which system is being assembled
Definition: elem_base.h:219
virtual bool slip_wall_surface_residual(bool request_jacobian, ComplexVectorX &f, ComplexMatrixX &jac, const unsigned int s, MAST::BoundaryConditionBase &bc)
residual of the slip wall that may be oscillating.