pml_elements.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: 1282 $
7 //LIC//
8 //LIC// $LastChangedDate: 2017-01-16 08:27:53 +0000 (Mon, 16 Jan 2017) $
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 
31 #include "pml_elements.h"
32 #include "shape.h"
33 
34 namespace oomph
35 {
36 
37 template<>
40  DenseComplexMatrix& laplace_matrix,
41  std::complex<double>& detJ)
42 {
43  const unsigned DIM = 1;
44 #ifdef PARANOID
45  // check matrix dimensions are compatable and the DIM has been implemented
46  if ( J.nrow() != DIM && J.ncol() != DIM )
47  {
48  throw OomphLibError("Input matrix must be 1x1", OOMPH_CURRENT_FUNCTION,
49  OOMPH_EXCEPTION_LOCATION);
50  }
51 #endif
52  detJ = J(0,0);
53 
54  // resize and intialize result
55  laplace_matrix.resize(DIM, DIM, 0.0);
56 
57  laplace_matrix(0,0) = 1.0/J(0,0);
58 }
59 
60 template<>
63  DiagonalComplexMatrix& laplace_matrix,
64  std::complex<double>& detJ)
65 {
66  const unsigned DIM = 1;
67 
68  detJ = J(0,0);
69 
70  // resize and intialize result
71  laplace_matrix.resize(DIM, DIM, std::complex<double>(0.0,0.0));
72 
73  laplace_matrix(0,0) = 1.0 / J(0,0);
74 }
75 
76 template<>
79  DenseComplexMatrix& laplace_matrix,
80  std::complex<double>& detJ)
81 {
82  const unsigned DIM = 1;
83 
84  detJ = J(0,0);
85 
86  // resize and intialize result
87  laplace_matrix.resize(DIM, DIM, std::complex<double>(0.0,0.0));
88 
89  laplace_matrix(0,0) = 1.0 / J(0,0);
90 }
91 
92 template<>
95  DiagonalComplexMatrix& J_inv,
96  std::complex<double>& J_det)
97 {
98  const unsigned DIM = 1;
99 
100  J_det = J(0,0);
101 
102  // resize and intialize result
103  J_inv.resize(DIM, DIM, std::complex<double>(0.0,0.0));
104 
105  J_inv(0,0) = 1.0 / J(0,0);
106 }
107 
108 template<>
111  DenseComplexMatrix& laplace_matrix,
112  std::complex<double>& detJ)
113 {
114  const unsigned DIM = 2;
115 #ifdef PARANOID
116  // check matrix dimensions are compatable and the DIM has been implemented
117  if ( J.nrow() != DIM && J.ncol() != DIM )
118  {
119  throw OomphLibError("Input matrix must be 2x2", OOMPH_CURRENT_FUNCTION,
120  OOMPH_EXCEPTION_LOCATION);
121  }
122 #endif
123 
124  detJ = J(0,0)*J(1,1) - J(1,0)*J(0,1);
125 
126  // resize and intialize result
127  laplace_matrix.resize(DIM, DIM, 0.0);
128 
129  std::complex<double> invDetJ = 1.0/detJ;
130  laplace_matrix(0,0) = (std::pow(J(0,1),2) + std::pow(J(1,1),2))*invDetJ;
131  laplace_matrix(1,1) = (std::pow(J(1,0),2) + std::pow(J(0,0),2))*invDetJ;
132  laplace_matrix(0,1) = -(J(0,0)*J(0,1) + J(1,0)*J(1,1))*invDetJ;
133  laplace_matrix(1,0) = laplace_matrix(0,1);
134 }
135 
136 template<>
139  DiagonalComplexMatrix& laplace_matrix,
140  std::complex<double>& detJ)
141 {
142  const unsigned DIM = 2;
143 
144  detJ = J(0,0) * J(1,0);
145 
146  // resize and intialize result
147  laplace_matrix.resize(DIM, DIM, 0.0);
148 
149  laplace_matrix(0,0) = J(1,1) / J(0,0);
150  laplace_matrix(1,1) = J(0,0) / J(1,1);
151 }
152 
153 template<>
156  DenseComplexMatrix& laplace_matrix,
157  std::complex<double>& detJ)
158 {
159  const unsigned DIM = 2;
160 
161  detJ = J(0,0) * J(1,0);
162 
163  // resize and intialize result
164  laplace_matrix.resize(DIM, DIM, 0.0);
165 
166  laplace_matrix(0,0) = J(1,1) / J(0,0);
167  laplace_matrix(1,1) = J(0,0) / J(1,1);
168 }
169 
170 template<>
173  DiagonalComplexMatrix& J_inv,
174  std::complex<double>& J_det)
175 {
176  const unsigned DIM = 2;
177 
178  J_det = J(0,0) * J(1,0);
179 
180  // resize and intialize result
181  J_inv.resize(DIM, DIM, 0.0);
182 
183  J_inv(0,0) = 1.0 / J(0,0);
184  J_inv(1,1) = 1.0 / J(1,1);
185 }
186 
187 
188 template<>
191  DiagonalComplexMatrix& laplace_matrix,
192  std::complex<double>& detJ)
193 {
194  const unsigned DIM = 3;
195 
196  detJ = J(0,0) * J(1,1) * J(2,2);
197 
198  // resize and intialize result
199  laplace_matrix.resize(DIM, DIM, 0.0);
200 
201  laplace_matrix(0,0) = J(1,1) * J(2,2) / J(0,0);
202  laplace_matrix(1,1) = J(0,0) * J(2,2) / J(1,1);
203  laplace_matrix(2,2) = J(0,0) * J(1,1) / J(2,2);
204 }
205 
206 template<>
209  DenseComplexMatrix& laplace_matrix,
210  std::complex<double>& detJ)
211 {
212  const unsigned DIM = 3;
213 
214  detJ = J(0,0) * J(1,1) * J(2,2);
215 
216  // resize and intialize result
217  laplace_matrix.resize(DIM, DIM, 0.0);
218 
219  laplace_matrix(0,0) = J(1,1) * J(2,2) / J(0,0);
220  laplace_matrix(1,1) = J(0,0) * J(2,2) / J(1,1);
221  laplace_matrix(2,2) = J(0,0) * J(1,1) / J(2,2);
222 }
223 
224 template<>
227  DenseComplexMatrix& laplace_matrix,
228  std::complex<double>& detJ)
229 {
230  const unsigned DIM = 3;
231 
232  detJ = J(0,0) * J(1,1) * J(2,2);
233 
234  // resize and intialize result
235  laplace_matrix.resize(DIM, DIM, 0.0);
236 
237  throw OomphLibError(
238  "Calculating Laplace matrix and det for 3x3 dense matrix not implemented",
239  OOMPH_CURRENT_FUNCTION,
240  OOMPH_EXCEPTION_LOCATION);
241 }
242 
243 template<>
246  DiagonalComplexMatrix& J_inv,
247  std::complex<double>& J_det)
248 {
249  const unsigned DIM = 3;
250 
251  J_det = J(0,0) * J(1,1) * J(2,2);
252 
253  // resize and intialize result
254  J_inv.resize(DIM, DIM, 0.0);
255 
256  J_inv(0,0) = 1.0 / J(0,0);
257  J_inv(1,1) = 1.0 / J(1,1);
258  J_inv(2,2) = 1.0 / J(2,2);
259 }
260 
261 //=======================================================================
262 /// \short Compute n'J^{-1}, which when applied to the untransformed
263 /// grad operator gives us the transformed normal derivative
264 //=======================================================================
265 void TangentiallyDiscontinuousConformal2DPMLElement::compute_transformed_normal_derivative(
266  const DenseComplexMatrix& J,
267  const Vector<double>& n,
268  Vector<std::complex<double> >& result)
269 {
270 
271  const unsigned DIM = 2;
272 #ifdef PARANOID
273  unsigned long N = J.nrow();
274  unsigned long n_col = J.ncol();
275  unsigned long n_vec = n.size();
276  // check matrix dimensions are compatable and the DIM has been implemented
277  if ( N != n_col || N != n_vec || N > 2 )
278  {
279  throw OomphLibError(
280  "Input vector must have size 2 and matrix must have size 2x2 ",
281  OOMPH_CURRENT_FUNCTION,
282  OOMPH_EXCEPTION_LOCATION);
283  }
284 #endif
285 
286  // resize and intialize result
287  result.resize(DIM, 0.0);
288 
289  const std::complex<double> detJ = J(0,0)*J(1,1) - J(1,0)*J(0,1);
290  result[0] = (n[0]*J(1,1) - n[1]*J(0,1))/detJ;
291  result[1] = (-n[0]*J(1,0) + n[1]*J(0,0))/detJ;
292 
293 }
294 
295 template <unsigned DIM>
297  const unsigned& ipt,
298  const Vector<double>& s,
299  const Vector<double>& x,
300  DiagonalComplexMatrix& pml_jacobian
301 )
302 {
303  if (this->Pml_is_enabled)
304  {
305  for (unsigned i=0; i<DIM; i++)
306  {
307  if(this->Pml_direction_active[i])
308  {
309  const double k = this->wavenumber();
310  const double nu_i = nu(x,i);
311  const double delta_i = delta(i);
312  pml_jacobian(i,i) = Pml_mapping_pt->dtransformed_nu_dnu(nu_i, delta_i,
313  k);
314  }
315  else
316  {
317  pml_jacobian(i,i) = 1.0;
318  }
319  }
320  }
321  else
322  {
323  for (unsigned i=0; i<DIM; i++)
324  {
325  pml_jacobian(i,i) = 1.0;
326  }
327  }
328 }
329 
330 template <unsigned DIM>
332  const unsigned& ipt,
333  const Vector<double>& s,
334  const Vector<double>& x,
335  DiagonalComplexMatrix& pml_jacobian,
336  Vector<std::complex<double> >& transformed_x
337 )
338 {
339  if (this->Pml_is_enabled)
340  {
341  for (unsigned i=0; i<DIM; i++)
342  {
343  if(this->Pml_direction_active[i])
344  {
345  const double k = this->wavenumber();
346  const double nu_i = nu(x,i);
347  const double delta_i = delta(i);
348  pml_jacobian(i,i) = Pml_mapping_pt->dtransformed_nu_dnu(nu_i, delta_i,
349  k);
350  transformed_x[i] = Pml_inner_boundary[i]
351  + Pml_mapping_pt->transformed_nu(nu_i, delta_i, k);
352  }
353  else
354  {
355  pml_jacobian(i,i) = 1.0;
356  transformed_x[i] = x[i];
357  }
358  }
359  }
360  else
361  {
362  for (unsigned i=0; i<DIM; i++)
363  {
364  pml_jacobian(i,i) = 1.0;
365  transformed_x[i] = x[i];
366  }
367  }
368 }
369 
370 void AnnularPMLElementBase::radial_to_cartesian_jacobian(
371  const double& r,
372  const double& theta,
373  const std::complex<double>& rt,
374  const std::complex<double>& drt_dr,
375  DenseComplexMatrix& cartesian_jacobian) const
376 {
377  DenseComplexMatrix radial_jacobian(2,2);
378  radial_jacobian(0,0) = drt_dr;
379  radial_jacobian(0,1) = 0.0;
380  radial_jacobian(1,0) = 0.0;
381  radial_jacobian(1,1) = 1.0;
382 
383  radial_to_cartesian_jacobian(r, theta, rt, radial_jacobian, cartesian_jacobian);
384 }
385 
386 void AnnularPMLElementBase::radial_to_cartesian_jacobian(
387  const double& r,
388  const double& theta,
389  const std::complex<double>& rt,
390  const DenseComplexMatrix& radial_jacobian,
391  DenseComplexMatrix& cartesian_jacobian) const
392 {
393 
394  // construct jacobian to move to transformed cartesian from transformed radial
395  DenseComplexMatrix jacobian_xt_from_rt(2,2);
396  jacobian_xt_from_rt(0,0) = cos(theta);
397  jacobian_xt_from_rt(1,0) = sin(theta);
398  jacobian_xt_from_rt(0,1) = -rt*sin(theta);
399  jacobian_xt_from_rt(1,1) = rt*cos(theta);
400 
401  // construct jacobian to move to radial from cartesian
402  DenseComplexMatrix jacobian_r_from_x(2,2);
403  jacobian_r_from_x(0,0) = cos(theta);
404  jacobian_r_from_x(0,1) = sin(theta);
405  jacobian_r_from_x(1,0) = -sin(theta)/r;
406  jacobian_r_from_x(1,1) = cos(theta)/r;
407 
408  // Multiply them all together
409  // \f$(J_{\tilde x \tilde r}) (J_{\tilde r r}) (J_{\tilde r r})\f$
410 
411  // \f$(J_{\tilde x \tilde r}) (J_{\tilde r r})\f$
412  DenseComplexMatrix temp(2,2);
413  jacobian_xt_from_rt.multiply(radial_jacobian, temp);
414 
415  // Multiply previous by \f$(J_{\tilde r r})\f$, returning as mapping_jacobian
416  temp.multiply(jacobian_r_from_x, cartesian_jacobian);
417 }
418 
419 /// \short Implements an interface between the polar mapping and the Cartesian
420 /// output which the get residuals expects
421 void AnnularPMLElementBase::pml_transformation_jacobian(
422  const unsigned& ipt,
423  const Vector<double>& s,
424  const Vector<double>& x,
425  DenseComplexMatrix& cartesian_jacobian)
426 {
427  // Get position from
428  const double theta = this->theta(s, x);
429  const double r = this->radius(s, x);
430  const double nu = this->nu(s, x);
431  const double delta = this->delta();
432 
433  // Get the radial mapping jacobian and the transformed radial coordinate
434  std::complex<double> dtr_dr;
435  std::complex<double> tr;
436  radial_transformation_jacobian(nu, delta, tr, dtr_dr);
437 
438  // Convert the radial Jacobian to a cartesian Jacobian
439  radial_to_cartesian_jacobian(r, theta, tr, dtr_dr, cartesian_jacobian);
440 }
441 
442 /// \short Implements an interface between the polar mapping and the Cartesian
443 /// output which the get residuals expects
444 void AnnularPMLElementBase::pml_transformation_jacobian(
445  const unsigned& ipt,
446  const Vector<double>& s,
447  const Vector<double>& x,
448  DenseComplexMatrix& cartesian_jacobian,
449  Vector<std::complex<double> >& transformed_x)
450 {
451  // Get position from
452  const double theta = this->theta(s, x);
453  const double r = this->radius(s, x);
454  const double nu = this->nu(s, x);
455  const double delta = this->delta();
456 
457  // Get the radial mapping jacobian and the transformed radial coordinate
458  std::complex<double> dtr_dr;
459  std::complex<double> tr;
460  radial_transformation_jacobian(nu, delta, tr, dtr_dr);
461 
462  // Convert the radial Jacobian to a cartesian Jacobian
463  radial_to_cartesian_jacobian(r, theta, tr, dtr_dr, cartesian_jacobian);
464 
465  transformed_x[0] = tr * cos(theta);
466  transformed_x[1] = tr * sin(theta);
467 }
468 
469 void Conformal2DPMLElement::
470 get_pml_properties(const Vector<double>& s,
471  Vector<double>& x_inner,
472  Vector<double>& x_outer,
473  Vector<double>& p,
474  Vector<double>& dx_inner_dacross,
475  Vector<double>& dp_dacross,
476  double& delta)
477 {
478  const unsigned N_NODE = this->nnode();
479  const unsigned NU_S_INDEX = this->nu_s_index();
480  const unsigned ACROSS_S_INDEX = this->across_s_index();
481  const unsigned DIM = 2;
482 
483  // Vectors to hold local coordinates for the inner and outer parts of the PML
484  Vector<double> s_inner(DIM);
485  Vector<double> s_outer(DIM);
486 
487  // Get the values of nu normalised at the inner and outer boundaries of
488  // this element from the element data
489  const double nun_inner = Nu_at_s_min;
490  const double nun_outer = Nu_at_s_max;
491 
492  // We use this to find the inner and outer position of the PML
493  const double nun_det = nun_outer*(1.0-nun_inner) - nun_inner*(1.0-nun_outer);
494 
495  // Set LOCAL coordinate of point projected to the inner element boundary
496  s_inner[ACROSS_S_INDEX] = s[ACROSS_S_INDEX];
497  s_inner[NU_S_INDEX] = this->s_min();
498 
499  //Set up memory for the shape functions at the inside of the element
500  Shape inner_psi(N_NODE);
501  DShape inner_dpsi_ds(N_NODE, DIM);
502  dshape_local(s_inner, inner_psi, inner_dpsi_ds);
503 
504  // Set LOCAL coordinate of point projected to the outer element boundary
505  s_outer[ACROSS_S_INDEX] = s[ACROSS_S_INDEX];
506  s_outer[NU_S_INDEX] = this->s_max();
507 
508  //Set up memory for the shape functions at the inside of the element
509  Shape outer_psi(N_NODE);
510  DShape outer_dpsi_ds(N_NODE, DIM);
511  dshape_local(s_outer, outer_psi, outer_dpsi_ds);
512 
513  // Now project back and forward to the PML boundaries to get x_inner and
514  // x_outer (we solve a 2x2 linear system twice) and them dacross
515  // and delta which is thickness of PML at this point
516  delta = 0.0;
517  for(unsigned i=0; i<DIM; i++)
518  {
519  double x_el_inner_i = 0.0;
520  double x_el_outer_i = 0.0;
521  double dx_el_inner_dacross_i = 0.0;
522  double dx_el_outer_dacross_i = 0.0;
523  for(unsigned n=0; n<N_NODE; n++)
524  {
525  const double node_x = this->nodal_position(n,i);
526  x_el_inner_i += node_x*inner_psi(n);
527  x_el_outer_i += node_x*outer_psi(n);
528  dx_el_inner_dacross_i += node_x*inner_dpsi_ds(n, ACROSS_S_INDEX);
529  dx_el_outer_dacross_i += node_x*outer_dpsi_ds(n, ACROSS_S_INDEX);
530  }
531 
532  // Calculate the inner and outer coordinates of the PML
533  x_inner[i] = (nun_outer*x_el_inner_i - nun_inner*x_el_outer_i)/nun_det;
534  x_outer[i] = ( (1.0-nun_inner)*x_el_outer_i
535  -(1.0-nun_outer)*x_el_inner_i )/nun_det;
536 
537  // Calculate unnormalised through-the-PML vector (we will normalise later)
538  p[i] = x_outer[i] - x_inner[i];
539 
540  dx_inner_dacross[i] = ( nun_outer*dx_el_inner_dacross_i
541  - nun_inner*dx_el_outer_dacross_i)/nun_det;
542 
543  // Use dp_dacross to hold dx_outer_dacross, we will compute dp_dacross later
544  dp_dacross[i] = ( (1.0-nun_inner)*dx_el_outer_dacross_i
545  -(1.0-nun_outer)*dx_el_inner_dacross_i )/nun_det;
546 
547  delta += p[i]*p[i];
548 
549  // faire: should we calculate p and dp_dacross in here??
550  // Also, does delta change?
551  }
552  delta = sqrt(delta);
553 
554  double ddelta_dacross = 0.0;
555  for(unsigned i=0; i<DIM; i++)
556  {
557  // Normalise the through-the-PML vector
558  p[i] = p[i]/delta;
559  // Recall that dp_dacross is currently holding dx_outer_dacross
560  ddelta_dacross += p[i]*(dp_dacross[i] - dx_inner_dacross[i]);
561  }
562 
563  // Finally calculate dp_dacross
564  for(unsigned i=0; i<DIM; i++)
565  {
566  // Recall that dp_dacross is currently holding dx_outer_dacross
567  dp_dacross[i] = (dp_dacross[i]-dx_inner_dacross[i]-ddelta_dacross*p[i])
568  /delta;
569  }
570 }
571 
572 
573 void Conformal2DPMLElement::pml_transformation_jacobian(
574  const unsigned& ipt,
575  const Vector<double>& s,
576  const Vector<double>& x,
577  DenseComplexMatrix& jacobian
578 )
579 {
580  const unsigned DIM = 2;
581 
582  double delta;
583  Vector<double> x_inner(DIM);
584  Vector<double> x_outer(DIM);
585  Vector<double> p(DIM);
586  Vector<double> dx_inner_dacross(DIM);
587  Vector<double> dp_dacross(DIM);
588  get_pml_properties(s, x_inner, x_outer, p, dx_inner_dacross, dp_dacross,
589  delta);
590 
591  const double NU = nu(s);
592 
593  const double k = wavenumber();
594  std::complex<double> tnu = Pml_mapping_pt->transformed_nu(NU, delta, k);
595  std::complex<double> dtnu_dnu = Pml_mapping_pt->dtransformed_nu_dnu(NU, delta,
596  k);
597 
598  assemble_conformal_jacobian(p, dx_inner_dacross, dp_dacross, NU, tnu,
599  dtnu_dnu, jacobian);
600 }
601 
602 void Conformal2DPMLElement::pml_transformation_jacobian(
603  const unsigned& ipt,
604  const Vector<double>& s,
605  const Vector<double>& x,
606  DenseComplexMatrix& jacobian,
607  Vector<std::complex<double> >& transformed_x
608 )
609 {
610  const unsigned DIM = 2;
611 
612  double delta;
613  Vector<double> x_inner(DIM);
614  Vector<double> x_outer(DIM);
615  Vector<double> p(DIM);
616  Vector<double> dx_inner_dacross(DIM);
617  Vector<double> dp_dacross(DIM);
618  get_pml_properties(s, x_inner, x_outer, p, dx_inner_dacross, dp_dacross,
619  delta);
620 
621  const double NU = nu(s);
622 
623  const double k = wavenumber();
624  std::complex<double> tnu = Pml_mapping_pt->transformed_nu(NU, delta, k);
625  std::complex<double> dtnu_dnu = Pml_mapping_pt->dtransformed_nu_dnu(NU, delta,
626  k);
627 
628  assemble_conformal_jacobian(p, dx_inner_dacross, dp_dacross, NU, tnu,
629  dtnu_dnu, jacobian);
630 
631  transformed_x[0] = x_inner[0] + tnu*p[0];
632  transformed_x[1] = x_inner[1] + tnu*p[1];
633 }
634 
635 
636 void Conformal2DPMLElement::assemble_conformal_jacobian(
637  const Vector<double>& p,
638  const Vector<double>& dx_inner_dacross,
639  const Vector<double>& dp_dacross,
640  const double& nu,
641  const std::complex<double>& tnu,
642  const std::complex<double>& dtnu_dnu,
643  DenseComplexMatrix& mapping_jacobian)
644 {
645  DenseComplexMatrix dtx_ds(2,2);
646  dtx_ds(0,0) = dx_inner_dacross[0] + tnu*dp_dacross[0];
647  dtx_ds(0,1) = dtnu_dnu*p[0];
648  dtx_ds(1,0) = dx_inner_dacross[1] + tnu*dp_dacross[1];
649  dtx_ds(1,1) = dtnu_dnu*p[1];
650 
651  DenseComplexMatrix ds_dx(2,2);
652  double inv_det_dx_ds = 1.0/( (dx_inner_dacross[0] + dp_dacross[0]*nu)*p[1]
653  -(dx_inner_dacross[1] + dp_dacross[1]*nu)*p[0]);
654  ds_dx(0,0) = p[1]*inv_det_dx_ds;
655  ds_dx(0,1) = -p[0]*inv_det_dx_ds;
656  ds_dx(1,0) = -(dx_inner_dacross[1] + dp_dacross[1]*nu)*inv_det_dx_ds;
657  ds_dx(1,1) = (dx_inner_dacross[0] + dp_dacross[0]*nu)*inv_det_dx_ds;
658 
659  dtx_ds.multiply(ds_dx,mapping_jacobian);
660 }
661 
662 void TangentiallyVaryingConformal2DPMLElement::assemble_conformal_jacobian(
663  const Vector<double>& p,
664  const Vector<double>& dx_inner_dacross,
665  const Vector<double>& dp_dacross,
666  const double& nu,
667  const std::complex<double>& tnu,
668  const std::complex<double>& dtnu_dnu,
669  const std::complex<double>& dtnu_dacross,
670  DenseComplexMatrix& mapping_jacobian)
671 {
672  DenseComplexMatrix dtx_ds(2,2);
673  dtx_ds(0,0) = dx_inner_dacross[0] + tnu*dp_dacross[0] + p[0]*dtnu_dacross;
674  dtx_ds(0,1) = dtnu_dnu*p[0];
675  dtx_ds(1,0) = dx_inner_dacross[1] + tnu*dp_dacross[1] + p[1]*dtnu_dacross;
676  dtx_ds(1,1) = dtnu_dnu*p[1];
677 
678  DenseComplexMatrix ds_dx(2,2);
679  double inv_det_dx_ds = 1.0/( (dx_inner_dacross[0] + dp_dacross[0]*nu)*p[1]
680  -(dx_inner_dacross[1] + dp_dacross[1]*nu)*p[0]);
681  ds_dx(0,0) = p[1]*inv_det_dx_ds;
682  ds_dx(0,1) = -p[0]*inv_det_dx_ds;
683  ds_dx(1,0) = -(dx_inner_dacross[1] + dp_dacross[1]*nu)*inv_det_dx_ds;
684  ds_dx(1,1) = (dx_inner_dacross[0] + dp_dacross[0]*nu)*inv_det_dx_ds;
685 
686  dtx_ds.multiply(ds_dx,mapping_jacobian);
687 }
688 
689 template class AxisAlignedPMLElement<1>;
690 template class AxisAlignedPMLElement<2>;
691 template class AxisAlignedPMLElement<3>;
692 
693 }
cstr elem_len * i
Definition: cfortran.h:607
void resize(const unsigned &N, const unsigned &M)
unsigned long ncol() const
Return the number of columns of the matrix.
static void compute_jacobian_inverse_and_det(const DiagonalComplexMatrix &jacobian, DiagonalComplexMatrix &jacobian_inverse, std::complex< double > &jacobian_det)
Computes the inverse J^-1 and determinant |J| of a Jacobian J.
Base class for elements with pml capabilities.
Definition: pml_elements.h:65
static char t char * s
Definition: cfortran.h:572
unsigned long nrow() const
Return the number of rows of the matrix.
void multiply(const Vector< std::complex< double > > &x, Vector< std::complex< double > > &soln)
Multiply the matrix by the vector x: soln=Ax.
static void compute_laplace_matrix_and_det(const DenseComplexMatrix &jacobian, DenseComplexMatrix &laplace_matrix, std::complex< double > &jacobian_det)
Computes laplace matrix (JJ^T)^-1|J| and determinant |J| for jacobian J. Laplace matrix is so named b...
Class of matrices containing double complex, and stored as a DenseMatrix<complex<double> >...
void resize(const unsigned long &n)
Definition: matrices.h:511