bem_panel_quadrature.f90 Source File


This file depends on

sourcefile~~bem_panel_quadrature.f90~~EfferentGraph sourcefile~bem_panel_quadrature.f90 bem_panel_quadrature.f90 sourcefile~bem_constants.f90 bem_constants.f90 sourcefile~bem_panel_quadrature.f90->sourcefile~bem_constants.f90 sourcefile~bem_kinds.f90 bem_kinds.f90 sourcefile~bem_panel_quadrature.f90->sourcefile~bem_kinds.f90 sourcefile~bem_panel_geometry.f90 bem_panel_geometry.f90 sourcefile~bem_panel_quadrature.f90->sourcefile~bem_panel_geometry.f90 sourcefile~bem_triangle_quadrature.f90 bem_triangle_quadrature.f90 sourcefile~bem_panel_quadrature.f90->sourcefile~bem_triangle_quadrature.f90 sourcefile~bem_constants.f90->sourcefile~bem_kinds.f90 sourcefile~bem_panel_geometry.f90->sourcefile~bem_kinds.f90 sourcefile~bem_triangle_quadrature.f90->sourcefile~bem_constants.f90 sourcefile~bem_triangle_quadrature.f90->sourcefile~bem_kinds.f90 sourcefile~bem_triangle_quadrature.f90->sourcefile~bem_panel_geometry.f90

Source Code

!> Independent Coulomb potential/field correctness oracles for triangle panels.
module bem_panel_quadrature
  use bem_kinds, only: dp, i32
  use bem_constants, only: k_coulomb
  use bem_panel_geometry, only: panel_geometry_type
  use bem_triangle_quadrature, only: panel_quadrature_plan_type, build_panel_quadrature, &
                                     fill_panel_quadrature, build_panel_duffy_quadrature, gauss_legendre_unit
  implicit none
  private

  public :: panel_quadrature_plan_type

  public :: build_panel_quadrature
  public :: fill_panel_quadrature
  public :: build_panel_duffy_quadrature
  public :: panel_oracle_potential_field
  public :: panel_singular_potential_oracle

contains

  subroutine panel_oracle_potential_field(geometry, charge, target, order, potential, field)
    type(panel_geometry_type), intent(in) :: geometry
    real(dp), intent(in) :: charge, target(3)
    integer(i32), intent(in) :: order
    real(dp), intent(out) :: potential, field(3)
    real(dp), allocatable :: node(:), weight(:)
    real(dp) :: source(3), displacement(3), radius2, jacobian, potential_integral, field_integral(3)
    real(dp) :: u, v, edge1(3), edge2(3), direction(3)
    integer :: iu, iv

    call gauss_legendre_unit(order, node, weight)
    edge1 = geometry%vertex(:, 2) - geometry%vertex(:, 1)
    edge2 = geometry%vertex(:, 3) - geometry%vertex(:, 1)
    potential_integral = 0.0_dp
    field_integral = 0.0_dp
    do iu = 1, order
      u = node(iu)
      do iv = 1, order
        v = node(iv)
        direction = (1.0_dp - v)*edge1 + v*edge2
        source = geometry%vertex(:, 1) + u*direction
        displacement = target - source
        radius2 = sum(displacement*displacement)
        jacobian = 2.0_dp*geometry%area*u*weight(iu)*weight(iv)
        potential_integral = potential_integral + jacobian/sqrt(radius2)
        field_integral = field_integral + jacobian*displacement/(radius2*sqrt(radius2))
      end do
    end do
    potential = k_coulomb*charge/geometry%area*potential_integral
    field = k_coulomb*charge/geometry%area*field_integral
  end subroutine panel_oracle_potential_field

  subroutine panel_singular_potential_oracle(geometry, charge, target, order, potential)
    type(panel_geometry_type), intent(in) :: geometry
    real(dp), intent(in) :: charge, target(3)
    integer(i32), intent(in) :: order
    real(dp), intent(out) :: potential
    real(dp), allocatable :: node(:), weight(:)
    real(dp) :: edge1(3), edge2(3), direction(3), source(3), radius, jacobian, integral
    real(dp) :: u, v, sub_area2
    integer :: edge, next_edge, iu, iv

    call gauss_legendre_unit(order, node, weight)
    integral = 0.0_dp
    do edge = 1, 3
      next_edge = merge(edge + 1, 1, edge < 3)
      edge1 = geometry%vertex(:, edge) - target
      edge2 = geometry%vertex(:, next_edge) - target
      sub_area2 = sqrt(sum(cross_product(edge1, edge2)**2))
      do iu = 1, order
        u = node(iu)
        do iv = 1, order
          v = node(iv)
          direction = (1.0_dp - v)*edge1 + v*edge2
          source = target + u*direction
          radius = sqrt(sum((target - source)**2))
          jacobian = sub_area2*u*weight(iu)*weight(iv)
          integral = integral + jacobian/radius
        end do
      end do
    end do
    potential = k_coulomb*charge/geometry%area*integral
  end subroutine panel_singular_potential_oracle

  pure function cross_product(a, b) result(c)
    real(dp), intent(in) :: a(3), b(3)
    real(dp) :: c(3)

    c = [a(2)*b(3) - a(3)*b(2), a(3)*b(1) - a(1)*b(3), a(1)*b(2) - a(2)*b(1)]
  end function cross_product

end module bem_panel_quadrature