41 std::complex<double>& detJ)
43 const unsigned DIM = 1;
46 if ( J.
nrow() != DIM && J.
ncol() != DIM )
48 throw OomphLibError(
"Input matrix must be 1x1", OOMPH_CURRENT_FUNCTION,
49 OOMPH_EXCEPTION_LOCATION);
55 laplace_matrix.
resize(DIM, DIM, 0.0);
57 laplace_matrix(0,0) = 1.0/J(0,0);
64 std::complex<double>& detJ)
66 const unsigned DIM = 1;
71 laplace_matrix.
resize(DIM, DIM, std::complex<double>(0.0,0.0));
73 laplace_matrix(0,0) = 1.0 / J(0,0);
80 std::complex<double>& detJ)
82 const unsigned DIM = 1;
87 laplace_matrix.
resize(DIM, DIM, std::complex<double>(0.0,0.0));
89 laplace_matrix(0,0) = 1.0 / J(0,0);
96 std::complex<double>& J_det)
98 const unsigned DIM = 1;
103 J_inv.
resize(DIM, DIM, std::complex<double>(0.0,0.0));
105 J_inv(0,0) = 1.0 / J(0,0);
112 std::complex<double>& detJ)
114 const unsigned DIM = 2;
117 if ( J.
nrow() != DIM && J.
ncol() != DIM )
119 throw OomphLibError(
"Input matrix must be 2x2", OOMPH_CURRENT_FUNCTION,
120 OOMPH_EXCEPTION_LOCATION);
124 detJ = J(0,0)*J(1,1) - J(1,0)*J(0,1);
127 laplace_matrix.
resize(DIM, DIM, 0.0);
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);
140 std::complex<double>& detJ)
142 const unsigned DIM = 2;
144 detJ = J(0,0) * J(1,0);
147 laplace_matrix.
resize(DIM, DIM, 0.0);
149 laplace_matrix(0,0) = J(1,1) / J(0,0);
150 laplace_matrix(1,1) = J(0,0) / J(1,1);
157 std::complex<double>& detJ)
159 const unsigned DIM = 2;
161 detJ = J(0,0) * J(1,0);
164 laplace_matrix.
resize(DIM, DIM, 0.0);
166 laplace_matrix(0,0) = J(1,1) / J(0,0);
167 laplace_matrix(1,1) = J(0,0) / J(1,1);
174 std::complex<double>& J_det)
176 const unsigned DIM = 2;
178 J_det = J(0,0) * J(1,0);
181 J_inv.
resize(DIM, DIM, 0.0);
183 J_inv(0,0) = 1.0 / J(0,0);
184 J_inv(1,1) = 1.0 / J(1,1);
192 std::complex<double>& detJ)
194 const unsigned DIM = 3;
196 detJ = J(0,0) * J(1,1) * J(2,2);
199 laplace_matrix.
resize(DIM, DIM, 0.0);
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);
210 std::complex<double>& detJ)
212 const unsigned DIM = 3;
214 detJ = J(0,0) * J(1,1) * J(2,2);
217 laplace_matrix.
resize(DIM, DIM, 0.0);
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);
228 std::complex<double>& detJ)
230 const unsigned DIM = 3;
232 detJ = J(0,0) * J(1,1) * J(2,2);
235 laplace_matrix.
resize(DIM, DIM, 0.0);
238 "Calculating Laplace matrix and det for 3x3 dense matrix not implemented",
239 OOMPH_CURRENT_FUNCTION,
240 OOMPH_EXCEPTION_LOCATION);
247 std::complex<double>& J_det)
249 const unsigned DIM = 3;
251 J_det = J(0,0) * J(1,1) * J(2,2);
254 J_inv.
resize(DIM, DIM, 0.0);
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);
265 void TangentiallyDiscontinuousConformal2DPMLElement::compute_transformed_normal_derivative(
268 Vector<std::complex<double> >& result)
271 const unsigned DIM = 2;
273 unsigned long N = J.
nrow();
274 unsigned long n_col = J.
ncol();
275 unsigned long n_vec = n.size();
277 if ( N != n_col || N != n_vec || N > 2 )
280 "Input vector must have size 2 and matrix must have size 2x2 ",
281 OOMPH_CURRENT_FUNCTION,
282 OOMPH_EXCEPTION_LOCATION);
287 result.resize(DIM, 0.0);
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;
295 template <
unsigned DIM>
303 if (this->Pml_is_enabled)
305 for (
unsigned i=0;
i<DIM;
i++)
307 if(this->Pml_direction_active[
i])
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,
317 pml_jacobian(i,i) = 1.0;
323 for (
unsigned i=0;
i<DIM;
i++)
325 pml_jacobian(
i,
i) = 1.0;
330 template <
unsigned DIM>
336 Vector<std::complex<double> >& transformed_x
339 if (this->Pml_is_enabled)
341 for (
unsigned i=0;
i<DIM;
i++)
343 if(this->Pml_direction_active[
i])
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,
350 transformed_x[
i] = Pml_inner_boundary[
i]
351 + Pml_mapping_pt->transformed_nu(nu_i, delta_i, k);
355 pml_jacobian(i,i) = 1.0;
356 transformed_x[
i] = x[
i];
362 for (
unsigned i=0;
i<DIM;
i++)
364 pml_jacobian(
i,
i) = 1.0;
365 transformed_x[
i] = x[
i];
370 void AnnularPMLElementBase::radial_to_cartesian_jacobian(
373 const std::complex<double>& rt,
374 const std::complex<double>& drt_dr,
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;
383 radial_to_cartesian_jacobian(r, theta, rt, radial_jacobian, cartesian_jacobian);
386 void AnnularPMLElementBase::radial_to_cartesian_jacobian(
389 const std::complex<double>& rt,
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);
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;
413 jacobian_xt_from_rt.
multiply(radial_jacobian, temp);
416 temp.
multiply(jacobian_r_from_x, cartesian_jacobian);
421 void AnnularPMLElementBase::pml_transformation_jacobian(
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();
434 std::complex<double> dtr_dr;
435 std::complex<double> tr;
436 radial_transformation_jacobian(nu, delta, tr, dtr_dr);
439 radial_to_cartesian_jacobian(r, theta, tr, dtr_dr, cartesian_jacobian);
444 void AnnularPMLElementBase::pml_transformation_jacobian(
449 Vector<std::complex<double> >& transformed_x)
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();
458 std::complex<double> dtr_dr;
459 std::complex<double> tr;
460 radial_transformation_jacobian(nu, delta, tr, dtr_dr);
463 radial_to_cartesian_jacobian(r, theta, tr, dtr_dr, cartesian_jacobian);
465 transformed_x[0] = tr * cos(theta);
466 transformed_x[1] = tr * sin(theta);
469 void Conformal2DPMLElement::
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;
489 const double nun_inner = Nu_at_s_min;
490 const double nun_outer = Nu_at_s_max;
493 const double nun_det = nun_outer*(1.0-nun_inner) - nun_inner*(1.0-nun_outer);
496 s_inner[ACROSS_S_INDEX] = s[ACROSS_S_INDEX];
497 s_inner[NU_S_INDEX] = this->s_min();
500 Shape inner_psi(N_NODE);
501 DShape inner_dpsi_ds(N_NODE, DIM);
502 dshape_local(s_inner, inner_psi, inner_dpsi_ds);
505 s_outer[ACROSS_S_INDEX] = s[ACROSS_S_INDEX];
506 s_outer[NU_S_INDEX] = this->s_max();
509 Shape outer_psi(N_NODE);
510 DShape outer_dpsi_ds(N_NODE, DIM);
511 dshape_local(s_outer, outer_psi, outer_dpsi_ds);
517 for(
unsigned i=0;
i<DIM;
i++)
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++)
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);
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;
538 p[
i] = x_outer[
i] - x_inner[
i];
540 dx_inner_dacross[
i] = ( nun_outer*dx_el_inner_dacross_i
541 - nun_inner*dx_el_outer_dacross_i)/nun_det;
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;
554 double ddelta_dacross = 0.0;
555 for(
unsigned i=0;
i<DIM;
i++)
560 ddelta_dacross += p[
i]*(dp_dacross[
i] - dx_inner_dacross[
i]);
564 for(
unsigned i=0;
i<DIM;
i++)
567 dp_dacross[
i] = (dp_dacross[
i]-dx_inner_dacross[
i]-ddelta_dacross*p[
i])
573 void Conformal2DPMLElement::pml_transformation_jacobian(
580 const unsigned DIM = 2;
588 get_pml_properties(s, x_inner, x_outer, p, dx_inner_dacross, dp_dacross,
591 const double NU = nu(s);
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,
598 assemble_conformal_jacobian(p, dx_inner_dacross, dp_dacross, NU, tnu,
602 void Conformal2DPMLElement::pml_transformation_jacobian(
607 Vector<std::complex<double> >& transformed_x
610 const unsigned DIM = 2;
618 get_pml_properties(s, x_inner, x_outer, p, dx_inner_dacross, dp_dacross,
621 const double NU = nu(s);
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,
628 assemble_conformal_jacobian(p, dx_inner_dacross, dp_dacross, NU, tnu,
631 transformed_x[0] = x_inner[0] + tnu*p[0];
632 transformed_x[1] = x_inner[1] + tnu*p[1];
636 void Conformal2DPMLElement::assemble_conformal_jacobian(
641 const std::complex<double>& tnu,
642 const std::complex<double>& dtnu_dnu,
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];
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;
659 dtx_ds.
multiply(ds_dx,mapping_jacobian);
662 void TangentiallyVaryingConformal2DPMLElement::assemble_conformal_jacobian(
667 const std::complex<double>& tnu,
668 const std::complex<double>& dtnu_dnu,
669 const std::complex<double>& dtnu_dacross,
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];
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;
686 dtx_ds.
multiply(ds_dx,mapping_jacobian);
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.
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)